From d1c37afbb84f19586792ac86c0664895d8368d7f Mon Sep 17 00:00:00 2001 From: Spiros Tsalikis Date: Fri, 27 Sep 2024 16:07:57 -0400 Subject: [PATCH 1/3] lixml2: update to 2.13.4 --- ThirdParty/libxml2/CMakeLists.txt | 4 ++-- ThirdParty/libxml2/update.sh | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ThirdParty/libxml2/CMakeLists.txt b/ThirdParty/libxml2/CMakeLists.txt index 31262002410..2f7be18b9fb 100644 --- a/ThirdParty/libxml2/CMakeLists.txt +++ b/ThirdParty/libxml2/CMakeLists.txt @@ -7,9 +7,9 @@ vtk_module_third_party( SPDX_COPYRIGHT_TEXT "Copyright (C) 1998-2012 Daniel Veillard" SPDX_DOWNLOAD_LOCATION - "git+https://gitlab.kitware.com/third-party/libxml2.git@for/vtk-20220827-2.10.1" + "git+https://gitlab.kitware.com/third-party/libxml2.git@for/vtk-20241002-2.13.4" VERSION - "2.9.12" + "2.13.4" STANDARD_INCLUDE_DIRS EXTERNAL PACKAGE LibXml2 diff --git a/ThirdParty/libxml2/update.sh b/ThirdParty/libxml2/update.sh index 00fcf9e51c8..a8a1f2f4ef2 100755 --- a/ThirdParty/libxml2/update.sh +++ b/ThirdParty/libxml2/update.sh @@ -8,22 +8,17 @@ readonly name="libxml2" readonly ownership="libxml2 Upstream " readonly subtree="ThirdParty/$name/vtk$name" readonly repo="https://gitlab.kitware.com/third-party/libxml2.git" -readonly tag="for/vtk-20231030-2.10.1" +readonly tag="for/vtk-20241002-2.13.4" readonly paths=" -include/libxml/*.h -include/libxml/xmlversion.h.in -include/win32config.h configure.ac buf.c -buf.h c14n.c catalog.c chvalid.c config.h.cmake.in debugXML.c dict.c -enc.h encoding.c entities.c error.c @@ -31,6 +26,11 @@ globals.c hash.c HTMLparser.c HTMLtree.c +include/libxml/*.h +include/libxml/xmlversion.h.in +include/private/*.h +include/win32config.h +include/wsockcompat.h legacy.c libxml.h list.c @@ -40,21 +40,23 @@ parser.c parserInternals.c pattern.c relaxng.c -SAX.c +rngparser.c +runsuite.c +runtest.c +runxmlconf.c SAX2.c -save.h +SAX.c schematron.c threads.c timsort.h tree.c -triodef.h -trionan.c -trionan.h uri.c valid.c xinclude.c xlink.c +xmlcatalog.c xmlIO.c +xmllint.c xmlmemory.c xmlmodule.c xmlreader.c -- GitLab From 80f3de794d69217aab6211bad04cda9bfee7b907 Mon Sep 17 00:00:00 2001 From: libxml2 Upstream Date: Tue, 1 Oct 2024 12:21:34 -0400 Subject: [PATCH 2/3] libxml2 2024-10-01 (f7b26bc7) Code extracted from: https://gitlab.kitware.com/third-party/libxml2.git at commit f7b26bc7d8ceb7ff3db1fa5fa1454c9eb4f5511e (for/vtk-20241002-2.13.4). --- CMakeLists.txt | 895 +- Copyright | 6 +- HTMLparser.c | 2226 ++--- HTMLtree.c | 269 +- README.md | 112 +- SAX.c | 1 - SAX2.c | 1290 ++- buf.c | 331 +- buf.h | 67 - c14n.c | 335 +- catalog.c | 213 +- chvalid.c | 2 + config.h.cmake.in | 91 +- configure.ac | 1851 ++-- debugXML.c | 228 +- dict.c | 1587 ++-- enc.h | 32 - encoding.c | 2051 ++--- entities.c | 578 +- error.c | 1236 ++- globals.c | 1257 +-- hash.c | 1904 ++-- include/libxml/HTMLparser.h | 106 +- include/libxml/HTMLtree.h | 36 +- include/libxml/SAX.h | 74 +- include/libxml/SAX2.h | 75 +- include/libxml/c14n.h | 23 +- include/libxml/catalog.h | 72 +- include/libxml/chvalid.h | 18 +- include/libxml/debugXML.h | 58 +- include/libxml/dict.h | 27 +- include/libxml/encoding.h | 78 +- include/libxml/entities.h | 57 +- include/libxml/globals.h | 488 +- include/libxml/hash.h | 185 +- include/libxml/list.h | 56 +- include/libxml/nanoftp.h | 48 +- include/libxml/nanohttp.h | 51 +- include/libxml/parser.h | 417 +- include/libxml/parserInternals.h | 303 +- include/libxml/pattern.h | 36 +- include/libxml/relaxng.h | 55 +- include/libxml/schemasInternals.h | 5 +- include/libxml/schematron.h | 37 +- include/libxml/threads.h | 52 +- include/libxml/tree.h | 449 +- include/libxml/uri.h | 44 +- include/libxml/valid.h | 192 +- include/libxml/vtk_libxml2_mangle.h | 189 +- include/libxml/xinclude.h | 27 +- include/libxml/xlink.h | 10 +- include/libxml/xmlIO.h | 223 +- include/libxml/xmlautomata.h | 42 +- include/libxml/xmlerror.h | 123 +- include/libxml/xmlexports.h | 153 +- include/libxml/xmlmemory.h | 189 +- include/libxml/xmlmodule.h | 8 +- include/libxml/xmlreader.h | 182 +- include/libxml/xmlregexp.h | 71 +- include/libxml/xmlsave.h | 34 +- include/libxml/xmlschemas.h | 63 +- include/libxml/xmlschemastypes.h | 68 +- include/libxml/xmlstring.h | 60 +- include/libxml/xmlunicode.h | 498 +- include/libxml/xmlversion.h.in | 158 +- include/libxml/xmlwriter.h | 161 +- include/libxml/xpath.h | 86 +- include/libxml/xpathInternals.h | 237 +- include/libxml/xpointer.h | 51 +- include/private/buf.h | 61 + include/private/dict.h | 74 + include/private/enc.h | 18 + include/private/entities.h | 27 + include/private/error.h | 34 + include/private/globals.h | 14 + include/private/html.h | 14 + include/private/io.h | 35 + include/private/memory.h | 9 + include/private/parser.h | 121 + include/private/regexp.h | 23 + include/private/save.h | 24 + include/private/string.h | 13 + include/private/threads.h | 35 + include/private/tree.h | 27 + include/private/xinclude.h | 9 + include/private/xpath.h | 16 + include/private/xzlib.h | 32 + include/win32config.h | 15 +- include/wsockcompat.h | 53 + legacy.c | 464 +- libxml.h | 110 +- list.c | 33 +- nanoftp.c | 154 +- nanohttp.c | 306 +- parser.c | 12472 ++++++++++++-------------- parserInternals.c | 2807 ++++-- pattern.c | 218 +- relaxng.c | 597 +- rngparser.c | 1588 ++++ runsuite.c | 1166 +++ runtest.c | 5129 +++++++++++ runxmlconf.c | 609 ++ save.h | 36 - schematron.c | 232 +- threads.c | 1028 +-- tree.c | 6059 ++++++------- triodef.h | 228 - trionan.c | 914 -- trionan.h | 84 - uri.c | 1365 +-- valid.c | 2383 +++-- xinclude.c | 2204 +++-- xlink.c | 2 - xmlIO.c | 3432 +++---- xmlcatalog.c | 614 ++ xmllint.c | 3787 ++++++++ xmlmemory.c | 899 +- xmlmodule.c | 177 +- xmlreader.c | 1466 ++- xmlregexp.c | 1144 +-- xmlsave.c | 1004 ++- xmlschemas.c | 1111 +-- xmlschemastypes.c | 1254 ++- xmlstring.c | 272 +- xmlwriter.c | 130 +- xpath.c | 3829 +++----- xpointer.c | 210 +- xzlib.c | 50 +- 128 files changed, 44268 insertions(+), 38190 deletions(-) delete mode 100644 buf.h delete mode 100644 enc.h create mode 100644 include/private/buf.h create mode 100644 include/private/dict.h create mode 100644 include/private/enc.h create mode 100644 include/private/entities.h create mode 100644 include/private/error.h create mode 100644 include/private/globals.h create mode 100644 include/private/html.h create mode 100644 include/private/io.h create mode 100644 include/private/memory.h create mode 100644 include/private/parser.h create mode 100644 include/private/regexp.h create mode 100644 include/private/save.h create mode 100644 include/private/string.h create mode 100644 include/private/threads.h create mode 100644 include/private/tree.h create mode 100644 include/private/xinclude.h create mode 100644 include/private/xpath.h create mode 100644 include/private/xzlib.h create mode 100644 include/wsockcompat.h create mode 100644 rngparser.c create mode 100644 runsuite.c create mode 100644 runtest.c create mode 100644 runxmlconf.c delete mode 100644 save.h delete mode 100644 triodef.h delete mode 100644 trionan.c delete mode 100644 trionan.h create mode 100644 xmlcatalog.c create mode 100644 xmllint.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 724f8474579..cb4e830c7a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,14 @@ if (FALSE) # XXX(kitware): use VTK's module system -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.18) endif () file(STRINGS "configure.ac" CONFIGURE_AC_LINES) foreach(line ${CONFIGURE_AC_LINES}) - if(line MATCHES [[^m4_define\(\[(MAJOR_VERSION|MINOR_VERSION|MICRO_VERSION)\],[ \t]*([0-9]+)\)$]]) - set(LIBXML_${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) - elseif(line MATCHES "^(LIBXML_MAJOR_VERSION|LIBXML_MINOR_VERSION|LIBXML_MICRO_VERSION)=([0-9]+)$") - set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) - endif() + if(line MATCHES [[^m4_define\(\[(MAJOR_VERSION|MINOR_VERSION|MICRO_VERSION)\],[ \t]*([0-9]+)\)$]]) + set(LIBXML_${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) + elseif(line MATCHES "^(LIBXML_MAJOR_VERSION|LIBXML_MINOR_VERSION|LIBXML_MICRO_VERSION)=([0-9]+)$") + set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) + endif() endforeach() set(VERSION "${LIBXML_MAJOR_VERSION}.${LIBXML_MINOR_VERSION}.${LIBXML_MICRO_VERSION}") @@ -18,9 +18,13 @@ include(CheckCSourceCompiles) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) +if (FALSE) # XXX(kitware): Requires bumping minimum CMake version to 3.18 +include(CheckLinkerFlag) +endif() include(CheckStructHasMember) include(CheckSymbolExists) include(CMakePackageConfigHelpers) +include(FindPkgConfig) include(GNUInstallDirs) if (FALSE) # XXX(kitware): Hardcode settings. @@ -32,13 +36,12 @@ option(LIBXML2_WITH_DEBUG "Add the debugging module" ON) set(LIBXML2_WITH_EXPR ON) option(LIBXML2_WITH_FTP "Add the FTP support" OFF) option(LIBXML2_WITH_HTML "Add the HTML support" ON) -option(LIBXML2_WITH_HTTP "Add the HTTP support" ON) +option(LIBXML2_WITH_HTTP "Add the HTTP support" OFF) option(LIBXML2_WITH_ICONV "Add ICONV support" ON) option(LIBXML2_WITH_ICU "Add ICU support" OFF) option(LIBXML2_WITH_ISO8859X "Add ISO8859X support if no iconv" ON) option(LIBXML2_WITH_LEGACY "Add deprecated APIs for compatibility" OFF) -option(LIBXML2_WITH_LZMA "Use liblzma" ON) -option(LIBXML2_WITH_MEM_DEBUG "Add the memory debugging module" OFF) +option(LIBXML2_WITH_LZMA "Use liblzma" OFF) option(LIBXML2_WITH_MODULES "Add the dynamic modules support" ON) option(LIBXML2_WITH_OUTPUT "Add the serialization support" ON) option(LIBXML2_WITH_PATTERN "Add the xmlPattern selection interface" ON) @@ -47,15 +50,14 @@ option(LIBXML2_WITH_PUSH "Add the PUSH parser interfaces" ON) option(LIBXML2_WITH_PYTHON "Build Python bindings" ON) option(LIBXML2_WITH_READER "Add the xmlReader parsing interface" ON) option(LIBXML2_WITH_REGEXPS "Add Regular Expressions support" ON) -option(LIBXML2_WITH_RUN_DEBUG "Add the runtime debugging module" OFF) option(LIBXML2_WITH_SAX1 "Add the older SAX1 interface" ON) option(LIBXML2_WITH_SCHEMAS "Add Relax-NG and Schemas support" ON) option(LIBXML2_WITH_SCHEMATRON "Add Schematron support" ON) option(LIBXML2_WITH_TESTS "Build tests" ON) option(LIBXML2_WITH_THREADS "Add multithread support" ON) option(LIBXML2_WITH_THREAD_ALLOC "Add per-thread memory" OFF) +option(LIBXML2_WITH_TLS "Enable thread-local storage" OFF) option(LIBXML2_WITH_TREE "Add the DOM like tree manipulation APIs" ON) -set(LIBXML2_WITH_TRIO OFF) set(LIBXML2_WITH_UNICODE ON) option(LIBXML2_WITH_VALID "Add the DTD validation support" ON) option(LIBXML2_WITH_WRITER "Add the xmlWriter saving interface" ON) @@ -63,7 +65,7 @@ option(LIBXML2_WITH_XINCLUDE "Add the XInclude support" ON) option(LIBXML2_WITH_XPATH "Add the XPATH support" ON) option(LIBXML2_WITH_XPTR "Add the XPointer support" ON) option(LIBXML2_WITH_XPTR_LOCS "Add support for XPointer locations" OFF) -option(LIBXML2_WITH_ZLIB "Use libz" ON) +option(LIBXML2_WITH_ZLIB "Use libz" OFF) set(LIBXML2_XMLCONF_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Working directory for XML Conformance Test Suite") else () set(LIBXML2_WITH_AUTOMATA ON) @@ -108,46 +110,21 @@ set(LIBXML2_WITH_ZLIB ON) set(LIBXML2_XMLCONF_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}) endif () -if(LIBXML2_WITH_ICONV) - find_package(Iconv REQUIRED) -endif() - -if(LIBXML2_WITH_ICU) - find_package(ICU REQUIRED COMPONENTS data i18n uc) -endif() - -if(LIBXML2_WITH_LZMA) - find_package(LibLZMA REQUIRED) -endif() - if(LIBXML2_WITH_PYTHON) - check_include_files(unistd.h HAVE_UNISTD_H) - check_symbol_exists(F_GETFL fcntl.h HAVE_F_GETFL) - if(HAVE_UNISTD_H AND HAVE_F_GETFL) - find_package(Python COMPONENTS Interpreter Development REQUIRED) - else() - find_package(Python2 COMPONENTS Interpreter Development REQUIRED) - add_library(Python::Python ALIAS Python2::Python) - set(Python_EXECUTABLE ${Python2_EXECUTABLE}) - set(Python_SITEARCH ${Python2_SITEARCH}) - endif() - set(LIBXML2_PYTHON_INSTALL_DIR ${Python_SITEARCH} CACHE PATH "Python bindings install directory") -endif() - -if(LIBXML2_WITH_THREADS) - find_package(Threads REQUIRED) -endif() - -if(LIBXML2_WITH_ZLIB) - #find_package(ZLIB REQUIRED) -endif() - -foreach(VARIABLE IN ITEMS WITH_AUTOMATA WITH_C14N WITH_CATALOG WITH_DEBUG WITH_EXPR WITH_FTP WITH_HTML WITH_HTTP WITH_ICONV WITH_ICU WITH_ISO8859X WITH_LEGACY WITH_LZMA WITH_MEM_DEBUG WITH_MODULES WITH_OUTPUT WITH_PATTERN WITH_PUSH WITH_READER WITH_REGEXPS WITH_RUN_DEBUG WITH_SAX1 WITH_SCHEMAS WITH_SCHEMATRON WITH_THREADS WITH_THREAD_ALLOC WITH_TREE WITH_TRIO WITH_UNICODE WITH_VALID WITH_WRITER WITH_XINCLUDE WITH_XPATH WITH_XPTR WITH_XPTR_LOCS WITH_ZLIB) - if(LIBXML2_${VARIABLE}) - set(${VARIABLE} 1) - else() - set(${VARIABLE} 0) - endif() + check_include_files(unistd.h HAVE_UNISTD_H) + check_symbol_exists(F_GETFL fcntl.h HAVE_F_GETFL) + find_package(Python COMPONENTS Interpreter Development REQUIRED) + #set(LIBXML2_PYTHON_INSTALL_DIR ${Python_SITEARCH} CACHE PATH "Python bindings install directory") + set(LIBXML2_PYTHON_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/python" + CACHE PATH "Python bindings install directory") +endif() + +foreach(VARIABLE IN ITEMS WITH_AUTOMATA WITH_C14N WITH_CATALOG WITH_DEBUG WITH_EXPR WITH_FTP WITH_HTML WITH_HTTP WITH_ICONV WITH_ICU WITH_ISO8859X WITH_LEGACY WITH_LZMA WITH_MODULES WITH_OUTPUT WITH_PATTERN WITH_PUSH WITH_READER WITH_REGEXPS WITH_SAX1 WITH_SCHEMAS WITH_SCHEMATRON WITH_THREADS WITH_THREAD_ALLOC WITH_TREE WITH_UNICODE WITH_VALID WITH_WRITER WITH_XINCLUDE WITH_XPATH WITH_XPTR WITH_XPTR_LOCS WITH_ZLIB) + if(LIBXML2_${VARIABLE}) + set(${VARIABLE} 1) + else() + set(${VARIABLE} 0) + endif() endforeach() set(LIBXML_VERSION ${VERSION}) @@ -161,132 +138,121 @@ math(EXPR LIBXML_VERSION_NUMBER " set(MODULE_EXTENSION "${CMAKE_SHARED_LIBRARY_SUFFIX}") set(PACKAGE "libxml2") -set(PACKAGE_BUGREPORT "xml@gnome.org") set(PACKAGE_NAME "libxml2") set(PACKAGE_STRING "libxml2 ${VERSION}") set(PACKAGE_TARNAME "libxml2") set(PACKAGE_URL "https://gitlab.gnome.org/GNOME/libxml2") set(PACKAGE_VERSION ${VERSION}) -if(LIBLZMA_FOUND) - list(APPEND CMAKE_REQUIRED_LIBRARIES LibLZMA::LibLZMA) +if(LIBXML2_WITH_ICONV) + find_package(Iconv REQUIRED) endif() -if(Threads_FOUND) - list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads) +if(LIBXML2_WITH_ICU) + find_package(ICU REQUIRED COMPONENTS data i18n uc) endif() -if(FALSE AND ZLIB_FOUND) # XXX(kitware): not needed for any try_compiles - list(APPEND CMAKE_REQUIRED_LIBRARIES ZLIB::ZLIB) +if(LIBXML2_WITH_LZMA) + find_package(LibLZMA REQUIRED) +endif() + +if(LIBXML2_WITH_THREADS) + find_package(Threads REQUIRED) + set(THREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads) +endif() + +if(LIBXML2_WITH_ZLIB) + # find_package(ZLIB REQUIRED) endif() if (NOT MSVC) - check_c_source_compiles(" - void __attribute__((destructor)) - f(void) {} - int main(void) { return 0; } - " HAVE_ATTRIBUTE_DESTRUCTOR) - if(HAVE_ATTRIBUTE_DESTRUCTOR) - set(ATTRIBUTE_DESTRUCTOR "__attribute__((destructor))") - endif() - check_c_source_compiles(" - #include - int main() { (void) gethostbyname((const char*) \"\"); return 0; } - " GETHOSTBYNAME_ARG_CAST_CONST) - if(NOT GETHOSTBYNAME_ARG_CAST_CONST) - set(GETHOSTBYNAME_ARG_CAST "(char *)") - else() - set(GETHOSTBYNAME_ARG_CAST "/**/") - endif() - check_include_files(arpa/inet.h HAVE_ARPA_INET_H) - check_include_files(arpa/nameser.h HAVE_ARPA_NAMESER_H) - check_struct_has_member("struct sockaddr_storage" ss_family "sys/socket.h;sys/types.h" HAVE_SS_FAMILY) - check_struct_has_member("struct sockaddr_storage" __ss_family "sys/socket.h;sys/types.h" HAVE_BROKEN_SS_FAMILY) - if(HAVE_BROKEN_SS_FAMILY) - set(ss_family __ss_family) - endif() - check_function_exists(class HAVE_CLASS) - check_include_files(dlfcn.h HAVE_DLFCN_H) - check_library_exists(dl dlopen "" HAVE_DLOPEN) - check_include_files(dl.h HAVE_DL_H) - check_include_files(fcntl.h HAVE_FCNTL_H) - check_function_exists(fpclass HAVE_FPCLASS) - check_function_exists(ftime HAVE_FTIME) - check_function_exists(getaddrinfo HAVE_GETADDRINFO) - check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) - check_include_files(inttypes.h HAVE_INTTYPES_H) - check_function_exists(isascii HAVE_ISASCII) - check_library_exists(history append_history "" HAVE_LIBHISTORY) - check_library_exists(readline readline "" HAVE_LIBREADLINE) - check_function_exists(mmap HAVE_MMAP) - check_function_exists(munmap HAVE_MUNMAP) - check_include_files(netdb.h HAVE_NETDB_H) - check_include_files(netinet/in.h HAVE_NETINET_IN_H) - check_include_files(poll.h HAVE_POLL_H) - check_function_exists(putenv HAVE_PUTENV) - check_function_exists(rand_r HAVE_RAND_R) - check_include_files(resolv.h HAVE_RESOLV_H) - check_library_exists(dld shl_load "" HAVE_SHLLOAD) - check_function_exists(stat HAVE_STAT) - check_include_files(stdint.h HAVE_STDINT_H) - check_include_files(sys/mman.h HAVE_SYS_MMAN_H) - check_include_files(sys/select.h HAVE_SYS_SELECT_H) - check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) - check_include_files(sys/stat.h HAVE_SYS_STAT_H) - check_include_files(sys/timeb.h HAVE_SYS_TIMEB_H) - check_include_files(sys/time.h HAVE_SYS_TIME_H) - check_include_files(sys/types.h HAVE_SYS_TYPES_H) - check_include_files(unistd.h HAVE_UNISTD_H) - check_function_exists(va_copy HAVE_VA_COPY) - check_function_exists(__va_copy HAVE___VA_COPY) - set(LT_OBJDIR ".libs/") - check_c_source_compiles(" - #include - #include - int main() { (void) send(1, (const char*) \"\", 1, 1); return 0; } - " SEND_ARG2_CAST_CONST) - if(NOT SEND_ARG2_CAST_CONST) - set(SEND_ARG2_CAST "(char *)") - else() - set(SEND_ARG2_CAST "/**/") - endif() - check_c_source_compiles(" - #include - void a(va_list* ap) {}; - int main() { va_list ap1, ap2; a(&ap1); ap2 = (va_list) ap1; return 0; } - " VA_LIST_IS_ARRAY_TEST) - if(VA_LIST_IS_ARRAY_TEST) - set(VA_LIST_IS_ARRAY FALSE) - else() - set(VA_LIST_IS_ARRAY TRUE) - endif() - check_c_source_compiles(" - #include - #include - #include - int main() { (void) getsockopt(1, 1, 1, NULL, (socklen_t*) NULL); return 0; } - " XML_SOCKLEN_T_SOCKLEN_T) - if(XML_SOCKLEN_T_SOCKLEN_T) - set(XML_SOCKLEN_T socklen_t) - else() - check_c_source_compiles(" - #include - #include - #include - int main() { (void) getsockopt(1, 1, 1, NULL, (size_t*) NULL); return 0; } - " XML_SOCKLEN_T_SIZE_T) - if(XML_SOCKLEN_T_SIZE_T) - set(XML_SOCKLEN_T size_t) - else() - check_c_source_compiles(" - #include - #include - #include - int main() { (void) getsockopt (1, 1, 1, NULL, (int*) NULL); return 0; } - " XML_SOCKLEN_T_INT) - set(XML_SOCKLEN_T int) - endif() - endif() + check_c_source_compiles(" + void __attribute__((destructor)) + f(void) {} + int main(void) { return 0; } + " HAVE_ATTRIBUTE_DESTRUCTOR) + if(HAVE_ATTRIBUTE_DESTRUCTOR) + set(ATTRIBUTE_DESTRUCTOR "__attribute__((destructor))") + endif() + check_include_files(arpa/inet.h HAVE_ARPA_INET_H) + check_function_exists(class HAVE_CLASS) + check_include_files(dlfcn.h HAVE_DLFCN_H) + check_library_exists(dl dlopen "" HAVE_DLOPEN) + check_include_files(dl.h HAVE_DL_H) + check_include_files(fcntl.h HAVE_FCNTL_H) + check_function_exists(fpclass HAVE_FPCLASS) + check_function_exists(ftime HAVE_FTIME) + check_function_exists(getentropy HAVE_GETENTROPY) + check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) + check_library_exists(history append_history "" HAVE_LIBHISTORY) + check_library_exists(readline readline "" HAVE_LIBREADLINE) + check_function_exists(mmap HAVE_MMAP) + check_function_exists(munmap HAVE_MUNMAP) + check_include_files(netdb.h HAVE_NETDB_H) + check_include_files(netinet/in.h HAVE_NETINET_IN_H) + check_include_files(poll.h HAVE_POLL_H) + check_library_exists(dld shl_load "" HAVE_SHLLOAD) + check_function_exists(stat HAVE_STAT) + check_include_files(stdint.h HAVE_STDINT_H) + check_include_files(sys/mman.h HAVE_SYS_MMAN_H) + check_include_files(sys/random.h HAVE_SYS_RANDOM_H) + check_include_files(sys/select.h HAVE_SYS_SELECT_H) + check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) + check_include_files(sys/stat.h HAVE_SYS_STAT_H) + check_include_files(sys/timeb.h HAVE_SYS_TIMEB_H) + check_include_files(sys/time.h HAVE_SYS_TIME_H) + check_include_files(unistd.h HAVE_UNISTD_H) + check_c_source_compiles(" + #include + #include + int main() { (void) getsockopt(1, 1, 1, NULL, (socklen_t*) NULL); return 0; } + " XML_SOCKLEN_T_SOCKLEN_T) + if(XML_SOCKLEN_T_SOCKLEN_T) + set(XML_SOCKLEN_T socklen_t) + else() + check_c_source_compiles(" + #include + #include + int main() { (void) getsockopt(1, 1, 1, NULL, (size_t*) NULL); return 0; } + " XML_SOCKLEN_T_SIZE_T) + if(XML_SOCKLEN_T_SIZE_T) + set(XML_SOCKLEN_T size_t) + else() + check_c_source_compiles(" + #include + #include + int main() { (void) getsockopt (1, 1, 1, NULL, (int*) NULL); return 0; } + " XML_SOCKLEN_T_INT) + set(XML_SOCKLEN_T int) + endif() + endif() +endif() + +if(LIBXML2_WITH_TLS) + check_c_source_compiles( + "_Thread_local int v; int main(){return 0;}" + XML_THREAD_LOCAL_C11 + ) + if (XML_THREAD_LOCAL_C11) + set(XML_THREAD_LOCAL "_Thread_local") + else() + check_c_source_compiles( + "__thread int v; int main(){return 0;}" + XML_THREAD_LOCAL_THREAD + ) + if (XML_THREAD_LOCAL_THREAD) + set(XML_THREAD_LOCAL "__thread") + else() + check_c_source_compiles( + "__declspec(thread) int v; int main(){return 0;}" + XML_THREAD_LOCAL_DECLSPEC + ) + if (XML_THREAD_LOCAL_DECLSPEC) + set(XML_THREAD_LOCAL "__declspec(thread)") + endif() + endif() + endif() endif() set( @@ -341,67 +307,63 @@ set( ) set( - LIBXML2_SRCS - buf.c - c14n.c - catalog.c - chvalid.c - debugXML.c - dict.c - encoding.c - entities.c - error.c - globals.c - hash.c - HTMLparser.c - HTMLtree.c - legacy.c - list.c - nanoftp.c - nanohttp.c - parser.c - parserInternals.c - pattern.c - relaxng.c - SAX.c - SAX2.c - schematron.c - threads.c - tree.c - uri.c - valid.c - xinclude.c - xlink.c - xmlIO.c - xmlmemory.c - xmlmodule.c - xmlreader.c - xmlregexp.c - xmlsave.c - xmlschemas.c - xmlschemastypes.c - xmlstring.c - xmlunicode.c - xmlwriter.c - xpath.c - xpointer.c - xzlib.c + LIBXML2_SRCS + buf.c + c14n.c + catalog.c + chvalid.c + debugXML.c + dict.c + encoding.c + entities.c + error.c + globals.c + hash.c + HTMLparser.c + HTMLtree.c + legacy.c + list.c + nanoftp.c + nanohttp.c + parser.c + parserInternals.c + pattern.c + relaxng.c + SAX.c + SAX2.c + schematron.c + threads.c + tree.c + uri.c + valid.c + xinclude.c + xlink.c + xmlIO.c + xmlmemory.c + xmlmodule.c + xmlreader.c + xmlregexp.c + xmlsave.c + xmlschemas.c + xmlschemastypes.c + xmlstring.c + xmlunicode.c + xmlwriter.c + xpath.c + xpointer.c + xzlib.c ) if(WIN32) - list(APPEND LIBXML2_SRCS win32/libxml2.rc) - file( - WRITE - ${CMAKE_CURRENT_BINARY_DIR}/rcVersion.h - "#define LIBXML_MAJOR_VERSION ${LIBXML_MAJOR_VERSION}\n" - "#define LIBXML_MINOR_VERSION ${LIBXML_MINOR_VERSION}\n" - "#define LIBXML_MICRO_VERSION ${LIBXML_MICRO_VERSION}\n" - "#define LIBXML_DOTTED_VERSION \"${VERSION}\"\n" - ) -endif() - -if(LIBXML2_WITH_TRIO) - list(APPEND LIBXML2_SRCS trio.c triostr.c) + list(APPEND LIBXML2_SRCS win32/libxml2.rc) + file( + WRITE + ${CMAKE_CURRENT_BINARY_DIR}/rcVersion.h + "#define LIBXML_MAJOR_VERSION ${LIBXML_MAJOR_VERSION}\n" + "#define LIBXML_MINOR_VERSION ${LIBXML_MINOR_VERSION}\n" + "#define LIBXML_MICRO_VERSION ${LIBXML_MICRO_VERSION}\n" + "#define LIBXML_DOTTED_VERSION \"${VERSION}\"\n" + ) endif() if (FALSE) # XXX(kitware): use VTK's module system @@ -410,32 +372,18 @@ add_library(LibXml2::LibXml2 ALIAS LibXml2) target_compile_definitions(LibXml2 PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") -if(NOT BUILD_SHARED_LIBS) - target_compile_definitions(LibXml2 INTERFACE LIBXML_STATIC) - set(XML_CFLAGS "-DLIBXML_STATIC") -endif() - -if(BUILD_SHARED_LIBS AND UNIX AND NOT APPLE) - if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_options(LibXml2 PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libxml2.syms") - endif() -endif() - if(LIBXML2_WITH_THREADS) - target_compile_definitions(LibXml2 PRIVATE _REENTRANT) - if(WIN32) - target_compile_definitions(LibXml2 PRIVATE HAVE_WIN32_THREADS) - else() - check_include_files(pthread.h HAVE_PTHREAD_H) - endif() + if(NOT WIN32) + check_include_files(pthread.h HAVE_PTHREAD_H) + endif() endif() target_include_directories( - LibXml2 - PUBLIC - $ - $ - $/${CMAKE_INSTALL_INCLUDEDIR}/libxml2> + LibXml2 + PUBLIC + $ + $ + $/${CMAKE_INSTALL_INCLUDEDIR}/libxml2> ) else () vtk_module_add_module(VTK::libxml2 @@ -464,219 +412,264 @@ target_include_directories(libxml2 "$") endif () -if(HAVE_DLOPEN) - #target_link_libraries(LibXml2 PRIVATE dl) - #set(MODULE_PLATFORM_LIBS "-ldl") - vtk_module_link(VTK::libxml2 PRIVATE dl) -endif() +if(LIBXML2_WITH_MODULES) + if(HAVE_DLOPEN) + # target_link_libraries(LibXml2 PRIVATE dl) + # set(MODULE_PLATFORM_LIBS "-ldl") + vtk_module_link(VTK::libxml2 PRIVATE dl) + endif() -if(HAVE_SHLLOAD) - #target_link_libraries(LibXml2 PRIVATE dld) - #set(MODULE_PLATFORM_LIBS "-ldld") - vtk_module_link(VTK::libxml2 PRIVATE dld) + if(HAVE_SHLLOAD) + # target_link_libraries(LibXml2 PRIVATE dld) + # set(MODULE_PLATFORM_LIBS "-ldld") + vtk_module_link(VTK::libxml2 PRIVATE dld) + endif() endif() if(UNIX) - #target_link_libraries(LibXml2 PRIVATE m) - #set(LIBM "-lm") - vtk_module_link(VTK::libxml2 PRIVATE m) + # target_link_libraries(LibXml2 PRIVATE m) + # set(LIBM "-lm") + vtk_module_link(VTK::libxml2 PRIVATE m) endif() if(WIN32) - #target_link_libraries(LibXml2 PRIVATE ws2_32) - #set(WIN32_EXTRA_LIBADD "-lws2_32") - vtk_module_link(VTK::libxml2 PRIVATE ws2_32) + # target_link_libraries(LibXml2 PRIVATE ws2_32) + # set(WINSOCK_LIBS "-lws2_32") + vtk_module_link(VTK::libxml2 PRIVATE ws2_32) + # target_link_libraries(LibXml2 PRIVATE bcrypt) + # set(CRYPTO_LIBS "-lbcrypt") + vtk_module_link(VTK::libxml2 PRIVATE bcrypt) endif() if(LIBXML2_WITH_ICONV) - target_link_libraries(LibXml2 PUBLIC Iconv::Iconv) - if(NOT Iconv_IS_BUILT_IN) - set(ICONV_LIBS "-liconv") - endif() + target_link_libraries(LibXml2 PUBLIC Iconv::Iconv) + if(NOT Iconv_IS_BUILT_IN) + set(ICONV_LIBS "-liconv") + endif() endif() if(LIBXML2_WITH_ICU) - target_link_libraries(LibXml2 PRIVATE ICU::data ICU::i18n ICU::uc) - if(WIN32) - set(ICU_LIBS "-licudt -licuin -licuuc") - else() - set(ICU_LIBS "-licudata -licui18n -licuuc") - endif() + target_link_libraries(LibXml2 PRIVATE ICU::data ICU::i18n ICU::uc) + if(WIN32) + set(ICU_LDFLAGS "-licudt -licuin -licuuc") + else() + set(ICU_LDFLAGS "-licudata -licui18n -licuuc") + endif() + list(APPEND XML_PRIVATE_LIBS "${ICU_LDFLAGS}") + pkg_check_modules(ICU_PC IMPORTED_TARGET icu-i18n) + if(ICU_PC_FOUND) + list(APPEND XML_PC_REQUIRES icu-i18n) + else() + list(APPEND XML_PC_LIBS "${ICU_LDFLAGS}") + endif() endif() if(LIBXML2_WITH_LZMA) - target_link_libraries(LibXml2 PRIVATE LibLZMA::LibLZMA) - set(LZMA_LIBS "-llzma") + target_link_libraries(LibXml2 PRIVATE LibLZMA::LibLZMA) + set(LibLZMA_LDFLAGS "-llzma") + list(APPEND XML_PRIVATE_LIBS "${LibLZMA_LDFLAGS}") + pkg_check_modules(LibLZMA_PC IMPORTED_TARGET liblzma) + if(LibLZMA_PC_FOUND) + list(APPEND XML_PC_REQUIRES liblzma) + else() + list(APPEND XML_PC_LIBS "${LibLZMA_LDFLAGS}") + endif() endif() if(LIBXML2_WITH_THREADS) - #target_link_libraries(LibXml2 PRIVATE Threads::Threads) - #set(THREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) + # target_link_libraries(LibXml2 PRIVATE Threads::Threads) + # set(THREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) vtk_module_link(VTK::libxml2 PRIVATE Threads::Threads) endif() if(LIBXML2_WITH_ZLIB) - #target_link_libraries(LibXml2 PRIVATE ZLIB::ZLIB) - #set(Z_LIBS "-lz") + # target_link_libraries(LibXml2 PRIVATE ZLIB::ZLIB) + # set(Z_LIBS "-lz") vtk_module_link(VTK::libxml2 PRIVATE VTK::zlib) + list(APPEND XML_PRIVATE_LIBS "${ZLIB_LDFLAGS}") + pkg_check_modules(ZLIB_PC IMPORTED_TARGET zlib) + if(ZLIB_PC_FOUND) + list(APPEND XML_PC_REQUIRES zlib) + else() + list(APPEND XML_PC_LIBS "${ZLIB_LDFLAGS}") + endif() +endif() + +if (FALSE) # XXX(kitware): handled by VTK's module system. +if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "GNU") + # These compiler flags can break the checks above so keep them here. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Wextra -Wshadow \ +-Wpointer-arith -Wcast-align -Wwrite-strings \ +-Wstrict-prototypes -Wmissing-prototypes \ +-Wno-long-long -Wno-format-extra-args") + + if(BUILD_SHARED_LIBS AND UNIX AND NOT APPLE) + check_linker_flag(C "LINKER:--undefined-version" FLAG_UNDEFINED_VERSION) + if (FLAG_UNDEFINED_VERSION) + target_link_options(LibXml2 PRIVATE "LINKER:--undefined-version") + endif() + target_link_options(LibXml2 PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libxml2.syms") + endif() endif() -if (FALSE) # XXX(kitware): handled by VTK's moduel system. set_target_properties( - LibXml2 - PROPERTIES - IMPORT_PREFIX lib - OUTPUT_NAME xml2 - POSITION_INDEPENDENT_CODE ON - PREFIX lib - VERSION ${PROJECT_VERSION} + LibXml2 + PROPERTIES + IMPORT_PREFIX lib + OUTPUT_NAME xml2 + POSITION_INDEPENDENT_CODE ON + PREFIX lib + VERSION ${PROJECT_VERSION} + SOVERSION ${LIBXML_MAJOR_VERSION} ) if(MSVC) - if(BUILD_SHARED_LIBS) - set_target_properties( - LibXml2 - PROPERTIES - DEBUG_POSTFIX d - ) - else() - set_target_properties( - LibXml2 - PROPERTIES - DEBUG_POSTFIX sd - MINSIZEREL_POSTFIX s - RELEASE_POSTFIX s - RELWITHDEBINFO_POSTFIX s - ) - endif() + if(BUILD_SHARED_LIBS) + set_target_properties( + LibXml2 + PROPERTIES + DEBUG_POSTFIX d + ) + else() + set_target_properties( + LibXml2 + PROPERTIES + DEBUG_POSTFIX sd + MINSIZEREL_POSTFIX s + RELEASE_POSTFIX s + RELWITHDEBINFO_POSTFIX s + ) + endif() endif() install(FILES ${LIBXML2_HDRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libxml2/libxml COMPONENT development) install( - TARGETS LibXml2 - EXPORT LibXml2 - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT development - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime + TARGETS LibXml2 + EXPORT LibXml2 + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT development + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime ) if(MSVC AND BUILD_SHARED_LIBS) - install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug) +endif() endif() -endif () if(LIBXML2_WITH_PROGRAMS) - set( - PROGRAMS - xmlcatalog - xmllint - ) - foreach(PROGRAM ${PROGRAMS}) - add_executable(${PROGRAM} ${PROGRAM}.c) - add_executable(LibXml2::${PROGRAM} ALIAS ${PROGRAM}) - target_compile_definitions(${PROGRAM} PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") - target_link_libraries(${PROGRAM} LibXml2) - if(HAVE_LIBHISTORY) - target_link_libraries(${PROGRAM} history) - endif() - if(HAVE_LIBREADLINE) - target_link_libraries(${PROGRAM} readline) - endif() - install(TARGETS ${PROGRAM} EXPORT LibXml2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs) - endforeach() + set( + PROGRAMS + xmlcatalog + xmllint + ) + foreach(PROGRAM ${PROGRAMS}) + add_executable(${PROGRAM} ${PROGRAM}.c) + add_executable(LibXml2::${PROGRAM} ALIAS ${PROGRAM}) + target_compile_definitions(${PROGRAM} PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") + target_link_libraries(${PROGRAM} LibXml2) + if(HAVE_LIBHISTORY) + target_link_libraries(${PROGRAM} history) + endif() + if(HAVE_LIBREADLINE) + target_link_libraries(${PROGRAM} readline) + endif() + install(TARGETS ${PROGRAM} EXPORT LibXml2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs) + endforeach() endif() if(LIBXML2_WITH_TESTS) - enable_testing() - set( - TESTS - runtest - runxmlconf - runsuite - testapi - testAutomata - testchar - testdict - testModule - testlimits - testrecurse - testThreads - ) - foreach(TEST ${TESTS}) - add_executable(${TEST} ${TEST}.c) - target_compile_definitions(${TEST} PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") - target_link_libraries(${TEST} LibXml2) - endforeach() - if(Threads_FOUND) - foreach(TEST runtest testThreads) - if(WIN32) - target_compile_definitions(${TEST} PRIVATE HAVE_WIN32_THREADS) - endif() - target_link_libraries(${TEST} Threads::Threads) - endforeach() - endif() - add_test(NAME runtest COMMAND runtest --out ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - if(EXISTS ${LIBXML2_XMLCONF_WORKING_DIR}/xmlconf/xmlconf.xml) - add_test(NAME runxmlconf COMMAND runxmlconf WORKING_DIRECTORY ${LIBXML2_XMLCONF_WORKING_DIR}) - endif() - if(NOT WIN32) - add_test(NAME testapi COMMAND testapi) - endif() - add_test(NAME testchar COMMAND testchar) - add_test(NAME testdict COMMAND testdict) - add_test(NAME testrecurse COMMAND testrecurse WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - add_test(NAME testThreads COMMAND testThreads WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + enable_testing() + set( + TESTS + runtest + runxmlconf + runsuite + testapi + testchar + testdict + testModule + testlimits + testparser + testrecurse + testThreads + ) + foreach(TEST ${TESTS}) + add_executable(${TEST} ${TEST}.c) + target_compile_definitions(${TEST} PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") + target_link_libraries(${TEST} LibXml2) + endforeach() + if(Threads_FOUND) + foreach(TEST runtest testThreads) + target_link_libraries(${TEST} Threads::Threads) + endforeach() + endif() + add_test(NAME runtest COMMAND runtest --out ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME runsuite COMMAND runsuite WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + if(EXISTS ${LIBXML2_XMLCONF_WORKING_DIR}/xmlconf/xmlconf.xml) + add_test(NAME runxmlconf COMMAND runxmlconf WORKING_DIRECTORY ${LIBXML2_XMLCONF_WORKING_DIR}) + endif() + if(NOT WIN32) + add_test(NAME testapi COMMAND testapi) + endif() + add_test(NAME testchar COMMAND testchar) + add_test(NAME testdict COMMAND testdict) + add_test(NAME testparser COMMAND testparser WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME testrecurse COMMAND testrecurse WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME testThreads COMMAND testThreads WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() if(LIBXML2_WITH_PYTHON) - execute_process( - COMMAND - ${Python_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/python/generator.py - ${CMAKE_CURRENT_SOURCE_DIR}/doc/libxml2-api.xml - ${CMAKE_CURRENT_SOURCE_DIR}/python/libxml2-python-api.xml - WORKING_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR} - ) - file(READ python/libxml.py LIBXML_PY) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in "${LIBXML_PY}") - file(READ ${CMAKE_CURRENT_BINARY_DIR}/libxml2class.py LIBXML2CLASS_PY) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in "${LIBXML2CLASS_PY}") - configure_file(${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in libxml2.py COPYONLY) - add_library( - LibXml2Mod - libxml2-py.c - libxml2-py.h - python/libxml.c - python/libxml_wrap.h - python/types.c - ) - target_include_directories( - LibXml2Mod - PUBLIC - $ - ) - target_link_libraries(LibXml2Mod LibXml2 Python::Python) - set_target_properties( - LibXml2Mod - PROPERTIES - IMPORT_PREFIX lib - OUTPUT_NAME xml2mod - PREFIX lib - VERSION ${PROJECT_VERSION} - ) - install( - TARGETS LibXml2Mod - ARCHIVE DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT development - LIBRARY DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime NAMELINK_COMPONENT development - RUNTIME DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime - ) - if(MSVC AND BUILD_SHARED_LIBS) - install(FILES $ DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug) - endif() - install(FILES python/drv_libxml2.py DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime) + execute_process( + COMMAND + ${Python_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/python/generator.py + ${CMAKE_CURRENT_SOURCE_DIR}/doc/libxml2-api.xml + ${CMAKE_CURRENT_SOURCE_DIR}/python/libxml2-python-api.xml + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} + ) + file(READ python/libxml.py LIBXML_PY) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in "${LIBXML_PY}") + file(READ ${CMAKE_CURRENT_BINARY_DIR}/libxml2class.py LIBXML2CLASS_PY) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in "${LIBXML2CLASS_PY}") + configure_file(${CMAKE_CURRENT_BINARY_DIR}/libxml2.py.in libxml2.py COPYONLY) + add_library( + LibXml2Mod + libxml2-py.c + libxml2-py.h + python/libxml.c + python/libxml_wrap.h + python/types.c + ) + target_include_directories( + LibXml2Mod + PUBLIC + $ + ) + target_link_libraries(LibXml2Mod LibXml2 Python::Python) + set_target_properties( + LibXml2Mod + PROPERTIES + IMPORT_PREFIX lib + OUTPUT_NAME xml2mod + PREFIX lib + VERSION ${PROJECT_VERSION} + ) + if (WIN32) + set_target_properties(LibXml2Mod PROPERTIES SUFFIX ".pyd") + endif() + install( + TARGETS LibXml2Mod + ARCHIVE DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT development + LIBRARY DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime NAMELINK_COMPONENT development + RUNTIME DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime + ) + if(MSVC AND BUILD_SHARED_LIBS) + install(FILES $ DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug) + endif() + install(FILES python/drv_libxml2.py DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2.py DESTINATION ${LIBXML2_PYTHON_INSTALL_DIR} COMPONENT runtime) endif() if (FALSE) # XXX(kitware): mask installation rules @@ -684,49 +677,49 @@ install(FILES doc/xml2-config.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONE install(FILES doc/xmlcatalog.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT documentation) install(FILES doc/xmllint.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT documentation) install(DIRECTORY doc/ DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT documentation - PATTERN "Makefile.*" EXCLUDE - PATTERN "*.1" EXCLUDE - PATTERN "*.py" EXCLUDE - PATTERN "*.res" EXCLUDE - PATTERN "*.xml" EXCLUDE - PATTERN "*.xsl" EXCLUDE) + PATTERN "Makefile.*" EXCLUDE + PATTERN "*.1" EXCLUDE + PATTERN "*.py" EXCLUDE + PATTERN "*.res" EXCLUDE + PATTERN "*.xml" EXCLUDE + PATTERN "*.xsl" EXCLUDE) configure_package_config_file( - libxml2-config.cmake.cmake.in libxml2-config.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} + libxml2-config.cmake.cmake.in libxml2-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} ) install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} - COMPONENT development + FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} + COMPONENT development ) write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config-version.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY ExactVersion + ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config-version.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY ExactVersion ) install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config-version.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} - COMPONENT development + FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} + COMPONENT development ) install( - EXPORT LibXml2 - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} - NAMESPACE LibXml2:: - FILE libxml2-export.cmake - COMPONENT development + EXPORT LibXml2 + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libxml2-${PROJECT_VERSION} + NAMESPACE LibXml2:: + FILE libxml2-export.cmake + COMPONENT development ) endif () if(MSVC) - configure_file(include/win32config.h include/config.h COPYONLY) + configure_file(include/win32config.h include/config.h COPYONLY) else() - configure_file(config.h.cmake.in include/config.h) + configure_file(config.h.cmake.in include/config.h) endif() configure_file(include/libxml/xmlversion.h.in include/libxml/xmlversion.h) if (FALSE) # XXX(kitware): mask installation rules @@ -734,23 +727,42 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml/xmlversion.h DESTINATION ${CMAK endif () if(LIBXML2_WITH_PYTHON) - set(prefix "${CMAKE_INSTALL_PREFIX}") - configure_file(python/setup.py.in setup.py @ONLY) + set(prefix "${CMAKE_INSTALL_PREFIX}") + configure_file(python/setup.py.in setup.py @ONLY) endif() +set(NON_PC_LIBS "${THREAD_LIBS} ${ICONV_LIBS} ${LIBM} ${WINSOCK_LIBS} ${CRYPTO_LIBS}") +list(APPEND XML_PC_LIBS "${NON_PC_LIBS}") +list(APPEND XML_PRIVATE_LIBS "${NON_PC_LIBS}") +list(REMOVE_DUPLICATES XML_PC_LIBS) +list(REMOVE_DUPLICATES XML_PRIVATE_LIBS) + +list(JOIN XML_PC_REQUIRES " " XML_PC_REQUIRES) +list(JOIN XML_PC_LIBS " " XML_PC_LIBS) +list(JOIN XML_PRIVATE_LIBS " " XML_PRIVATE_LIBS) + if (FALSE) # XXX(kitware): mask installation rules set(XML_INCLUDEDIR "-I\${includedir}/libxml2") set(XML_LIBDIR "-L\${libdir}") set(XML_LIBS "-lxml2") -set(XML_PRIVATE_LIBS "${Z_LIBS} ${LZMA_LIBS} ${THREAD_LIBS} ${ICONV_LIBS} ${ICU_LIBS} ${LIBM} ${WIN32_EXTRA_LIBADD}") + +if(BUILD_SHARED_LIBS) + set(XML_PC_PRIVATE ".private") + set(XML_PC_LIBS_PRIVATE " +Libs.private:") +else() + target_compile_definitions(LibXml2 PUBLIC LIBXML_STATIC) + set(XML_CFLAGS "-DLIBXML_STATIC") + set(XML_PRIVATE_LIBS_NO_SHARED "${XML_PRIVATE_LIBS}") +endif() file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig" "${CMAKE_INSTALL_PREFIX}") string(REGEX REPLACE "/$" "" PACKAGE_RELATIVE_PATH "${PACKAGE_RELATIVE_PATH}") if(WIN32) - set(prefix "\${pcfiledir}/${PACKAGE_RELATIVE_PATH}") + set(prefix "\${pcfiledir}/${PACKAGE_RELATIVE_PATH}") else() - set(prefix "${CMAKE_INSTALL_PREFIX}") + set(prefix "${CMAKE_INSTALL_PREFIX}") endif() set(exec_prefix "\${prefix}") set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}") @@ -759,13 +771,13 @@ configure_file(libxml-2.0.pc.in libxml-2.0.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml-2.0.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT development) if(WIN32) - set(prefix "\$(cd \"\$(dirname \"\$0\")\"; pwd -P)/..") + set(prefix "\$(cd \"\$(dirname \"\$0\")\"; pwd -P)/..") endif() configure_file(xml2-config.in xml2-config @ONLY) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/xml2-config DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT development) if(UNIX) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libxml.m4 DESTINATION ${CMAKE_INSTALL_DATADIR}/aclocal) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libxml.m4 DESTINATION ${CMAKE_INSTALL_DATADIR}/aclocal) endif() set(XML_INCLUDEDIR "-I${CMAKE_INSTALL_FULL_INCLUDEDIR}/libxml2") @@ -788,7 +800,6 @@ set(CPACK_DEBIAN_RUNTIME_PACKAGE_RECOMMENDS "${PACKAGE_TARNAME}-utils") set(CPACK_DEBIAN_RUNTIME_PACKAGE_SECTION "libs") set(CPACK_NSIS_PACKAGE_NAME ${PACKAGE_STRING}) set(CPACK_NSIS_URL_INFO_ABOUT ${PACKAGE_URL}) -set(CPACK_PACKAGE_CONTACT ${PACKAGE_BUGREPORT}) set(CPACK_PACKAGE_DISPLAY_NAME ${PACKAGE_STRING}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PACKAGE_TARNAME}-${PACKAGE_VERSION}") set(CPACK_PACKAGE_NAME ${PACKAGE_TARNAME}) diff --git a/Copyright b/Copyright index d61318502ca..f76a86df63f 100644 --- a/Copyright +++ b/Copyright @@ -1,6 +1,6 @@ -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: +Except where otherwise noted in the source code (e.g. the files dict.c and +list.c, which are covered by a similar licence but with different Copyright +notices) all the files are: Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. diff --git a/HTMLparser.c b/HTMLparser.c index ba886908e44..22135929565 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -14,30 +14,30 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include -#include #include -#include #include -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" +#include "private/html.h" +#include "private/io.h" +#include "private/parser.h" +#include "private/tree.h" #define HTML_MAX_NAMELEN 1000 #define HTML_PARSER_BIG_BUFFER_SIZE 1000 #define HTML_PARSER_BUFFER_SIZE 100 -/* #define DEBUG */ -/* #define DEBUG_PUSH */ - static int htmlOmittedDefaultValue = 1; xmlChar * htmlDecodeEntities(htmlParserCtxtPtr ctxt, int len, @@ -58,25 +58,9 @@ static void htmlParseComment(htmlParserCtxtPtr ctxt); * Handle a redefinition of attribute error */ static void -htmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra) +htmlErrMemory(xmlParserCtxtPtr ctxt) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } - if (extra) - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + xmlCtxtErrMemory(ctxt); } /** @@ -93,18 +77,8 @@ static void LIBXML_ATTR_FORMAT(3,0) htmlParseErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, - msg, str1, str2); - if (ctxt != NULL) - ctxt->wellFormed = 0; + xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -120,16 +94,8 @@ static void LIBXML_ATTR_FORMAT(3,0) htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, int val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error, - XML_ERR_ERROR, NULL, 0, NULL, NULL, - NULL, val, 0, msg, val); - if (ctxt != NULL) - ctxt->wellFormed = 0; + xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR, + NULL, NULL, NULL, val, msg, val); } /************************************************************************ @@ -145,7 +111,7 @@ htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, * * Pushes a new element name on top of the name stack * - * Returns 0 in case of error, the index in the stack otherwise + * Returns -1 in case of error, the index in the stack otherwise */ static int htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value) @@ -155,15 +121,17 @@ htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value) if ((ctxt->html < 10) && (xmlStrEqual(value, BAD_CAST "body"))) ctxt->html = 10; if (ctxt->nameNr >= ctxt->nameMax) { - ctxt->nameMax *= 2; - ctxt->nameTab = (const xmlChar * *) - xmlRealloc((xmlChar * *)ctxt->nameTab, - ctxt->nameMax * - sizeof(ctxt->nameTab[0])); - if (ctxt->nameTab == NULL) { - htmlErrMemory(ctxt, NULL); - return (0); + size_t newSize = ctxt->nameMax * 2; + const xmlChar **tmp; + + tmp = xmlRealloc((xmlChar **) ctxt->nameTab, + newSize * sizeof(ctxt->nameTab[0])); + if (tmp == NULL) { + htmlErrMemory(ctxt); + return (-1); } + ctxt->nameTab = tmp; + ctxt->nameMax = newSize; } ctxt->nameTab[ctxt->nameNr] = value; ctxt->name = value; @@ -217,7 +185,7 @@ htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value) ctxt->nodeInfoMax * sizeof(ctxt->nodeInfoTab[0])); if (ctxt->nodeInfoTab == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); return (0); } } @@ -270,8 +238,6 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) * * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding * - * 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. * NEXTL(l) Skip the current unicode character of l xmlChars long. @@ -289,32 +255,32 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) #define CUR_PTR ctxt->input->cur #define BASE_PTR ctxt->input->base -#define SHRINK if ((ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ - (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ - xmlParserInputShrink(ctxt->input) - -#define GROW if ((ctxt->progressive == 0) && \ - (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ - xmlParserInputGrow(ctxt->input, INPUT_CHUNK) +#define SHRINK \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ + xmlParserShrink(ctxt); -#define CURRENT ((int) (*ctxt->input->cur)) +#define GROW \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + xmlParserGrow(ctxt); #define SKIP_BLANKS htmlSkipBlankChars(ctxt) /* Imported from XML */ -/* #define CUR (ctxt->token ? ctxt->token : (int) (*ctxt->input->cur)) */ -#define CUR ((int) (*ctxt->input->cur)) +#define CUR (*ctxt->input->cur) #define NEXT xmlNextChar(ctxt) -#define RAW (ctxt->token ? -1 : (*ctxt->input->cur)) +#define RAW (*ctxt->input->cur) #define NEXTL(l) do { \ if (*(ctxt->input->cur) == '\n') { \ ctxt->input->line++; ctxt->input->col = 1; \ } else ctxt->input->col++; \ - ctxt->token = 0; ctxt->input->cur += l; \ + ctxt->input->cur += l; \ } while (0) /************ @@ -324,10 +290,9 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) ************/ #define CUR_CHAR(l) htmlCurrentChar(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; \ + if (l == 1) b[i++] = v; \ else i += xmlCopyChar(l,&b[i],v) /** @@ -347,10 +312,10 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) static xmlChar * htmlFindEncoding(xmlParserCtxtPtr ctxt) { const xmlChar *start, *cur, *end; + xmlChar *ret; if ((ctxt == NULL) || (ctxt->input == NULL) || - (ctxt->input->encoding != NULL) || (ctxt->input->buf == NULL) || - (ctxt->input->buf->encoder != NULL)) + (ctxt->input->flags & XML_INPUT_HAS_ENCODING)) return(NULL); if ((ctxt->input->cur == NULL) || (ctxt->input->end == NULL)) return(NULL); @@ -379,7 +344,10 @@ htmlFindEncoding(xmlParserCtxtPtr ctxt) { cur++; if (cur == start) return(NULL); - return(xmlStrndup(start, cur - start)); + ret = xmlStrndup(start, cur - start); + if (ret == NULL) + htmlErrMemory(ctxt); + return(ret); } /** @@ -402,31 +370,31 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { unsigned char c; unsigned int val; - if (ctxt->instate == XML_PARSER_EOF) - return(0); + if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) + xmlParserGrow(ctxt); - if (ctxt->token != 0) { - *len = 0; - return(ctxt->token); - } - if (ctxt->charset != XML_CHAR_ENCODING_UTF8) { + if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) { xmlChar * guess; - xmlCharEncodingHandlerPtr handler; /* * Assume it's a fixed length encoding (1) with * a compatible encoding for the ASCII set, since * HTML constructs only use < 128 chars */ - if ((int) *ctxt->input->cur < 0x80) { - *len = 1; - if ((*ctxt->input->cur == 0) && - (ctxt->input->cur < ctxt->input->end)) { - htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", 0); - return(' '); + if (*ctxt->input->cur < 0x80) { + if (*ctxt->input->cur == 0) { + if (ctxt->input->cur < ctxt->input->end) { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x%X out of allowed range\n", 0); + *len = 1; + return(' '); + } else { + *len = 0; + return(0); + } } - return((int) *ctxt->input->cur); + *len = 1; + return(*ctxt->input->cur); } /* @@ -436,23 +404,10 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { if (guess == NULL) { xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1); } else { - if (ctxt->input->encoding != NULL) - xmlFree((xmlChar *) ctxt->input->encoding); - ctxt->input->encoding = guess; - handler = xmlFindCharEncodingHandler((const char *) guess); - if (handler != NULL) { - /* - * Don't use UTF-8 encoder which isn't required and - * can produce invalid UTF-8. - */ - if (!xmlStrEqual(BAD_CAST handler->name, BAD_CAST "UTF-8")) - xmlSwitchToEncoding(ctxt, handler); - } else { - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "Unsupported encoding %s", guess, NULL); - } + xmlSwitchEncodingName(ctxt, (const char *) guess); + xmlFree(guess); } - ctxt->charset = XML_CHAR_ENCODING_UTF8; + ctxt->input->flags |= XML_INPUT_HAS_ENCODING; } /* @@ -469,29 +424,21 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { cur = ctxt->input->cur; c = *cur; if (c & 0x80) { + size_t avail; + if ((c & 0x40) == 0) goto encoding_error; - if (cur[1] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if ((cur[1] & 0xc0) != 0x80) + + avail = ctxt->input->end - ctxt->input->cur; + + if ((avail < 2) || ((cur[1] & 0xc0) != 0x80)) goto encoding_error; if ((c & 0xe0) == 0xe0) { - - if (cur[2] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if ((cur[2] & 0xc0) != 0x80) + if ((avail < 3) || ((cur[2] & 0xc0) != 0x80)) goto encoding_error; if ((c & 0xf0) == 0xf0) { - if (cur[3] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } if (((c & 0xf8) != 0xf0) || - ((cur[3] & 0xc0) != 0x80)) + (avail < 4) || ((cur[3] & 0xc0) != 0x80)) goto encoding_error; /* 4-byte code */ *len = 4; @@ -524,53 +471,29 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { } return(val); } else { - if ((*ctxt->input->cur == 0) && - (ctxt->input->cur < ctxt->input->end)) { - htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", 0); - *len = 1; - return(' '); + if (*ctxt->input->cur == 0) { + if (ctxt->input->cur < ctxt->input->end) { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x%X out of allowed range\n", 0); + *len = 1; + return(' '); + } else { + *len = 0; + return(0); + } } /* 1-byte code */ *len = 1; - return((int) *ctxt->input->cur); + return(*ctxt->input->cur); } encoding_error: - /* - * If we detect an UTF8 error that probably mean 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 !) - */ - { - char buffer[150]; - - if (ctxt->input->end - ctxt->input->cur >= 4) { - snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - ctxt->input->cur[0], ctxt->input->cur[1], - ctxt->input->cur[2], ctxt->input->cur[3]); - } else { - snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]); - } - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "Input is not proper UTF-8, indicate encoding !\n", - BAD_CAST buffer, NULL); - } + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); - /* - * Don't switch encodings twice. Note that if there's an encoder, we - * shouldn't receive invalid UTF-8 anyway. - * - * Note that if ctxt->input->buf == NULL, switching encodings is - * impossible, see Gitlab issue #34. - */ - if ((ctxt->input->buf != NULL) && - (ctxt->input->buf->encoder == NULL)) + if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1); *len = 1; - return((int) *ctxt->input->cur); + return(*ctxt->input->cur); } /** @@ -587,17 +510,12 @@ htmlSkipBlankChars(xmlParserCtxtPtr ctxt) { int res = 0; while (IS_BLANK_CH(*(ctxt->input->cur))) { - if ((*ctxt->input->cur == 0) && - (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) { - xmlPopInput(ctxt); - } else { - if (*(ctxt->input->cur) == '\n') { - ctxt->input->line++; ctxt->input->col = 1; - } else ctxt->input->col++; - ctxt->input->cur++; - if (*ctxt->input->cur == 0) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - } + if (*(ctxt->input->cur) == '\n') { + ctxt->input->line++; ctxt->input->col = 1; + } else ctxt->input->col++; + ctxt->input->cur++; + if (*ctxt->input->cur == 0) + xmlParserGrow(ctxt); if (res < INT_MAX) res++; } @@ -1223,7 +1141,6 @@ static const htmlStartCloseEntry htmlStartClose[] = { { "menu", "form" }, { "menu", "ul" }, { "ol", "form" }, - { "ol", "ul" }, { "option", "optgroup" }, { "option", "option" }, { "p", "address" }, @@ -1307,7 +1224,6 @@ static const htmlStartCloseEntry htmlStartClose[] = { { "ul", "address" }, { "ul", "form" }, { "ul", "menu" }, - { "ul", "ol" }, { "ul", "pre" }, { "xmp", "dd" }, { "xmp", "dl" }, @@ -1395,10 +1311,7 @@ static const elementPriority htmlEndPriority[] = { /** * htmlInitAutoClose: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * This is a no-op now. + * DEPRECATED: This is a no-op. */ void htmlInitAutoClose(void) { @@ -1565,20 +1478,11 @@ htmlAutoCloseOnEnd(htmlParserCtxtPtr ctxt) static void htmlAutoClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag) { - while ((newtag != NULL) && (ctxt->name != NULL) && - (htmlCheckAutoClose(newtag, ctxt->name))) { - if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL)) - ctxt->sax->endElement(ctxt->userData, ctxt->name); - htmlnamePop(ctxt); - } - if (newtag == NULL) { - htmlAutoCloseOnEnd(ctxt); + if (newtag == NULL) return; - } - while ((newtag == NULL) && (ctxt->name != NULL) && - ((xmlStrEqual(ctxt->name, BAD_CAST "head")) || - (xmlStrEqual(ctxt->name, BAD_CAST "body")) || - (xmlStrEqual(ctxt->name, BAD_CAST "html")))) { + + while ((ctxt->name != NULL) && + (htmlCheckAutoClose(newtag, ctxt->name))) { if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL)) ctxt->sax->endElement(ctxt->userData, ctxt->name); htmlnamePop(ctxt); @@ -2075,9 +1979,9 @@ static const htmlEntityDesc html40EntitiesTable[] = { #define growBuffer(buffer) { \ xmlChar *tmp; \ buffer##_size *= 2; \ - tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \ - if (tmp == NULL) { \ - htmlErrMemory(ctxt, "growing buffer\n"); \ + tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size); \ + if (tmp == NULL) { \ + htmlErrMemory(ctxt); \ xmlFree(buffer); \ return(NULL); \ } \ @@ -2107,6 +2011,14 @@ htmlEntityLookup(const xmlChar *name) { return(NULL); } +static int +htmlCompareEntityDesc(const void *vkey, const void *vdesc) { + const unsigned *key = vkey; + const htmlEntityDesc *desc = vdesc; + + return((int) *key - (int) desc->value); +} + /** * htmlEntityValueLookup: * @value: the entity's unicode value @@ -2119,17 +2031,14 @@ htmlEntityLookup(const xmlChar *name) { */ const htmlEntityDesc * htmlEntityValueLookup(unsigned int value) { - unsigned int i; + const htmlEntityDesc *desc; + size_t nmemb; - for (i = 0;i < (sizeof(html40EntitiesTable)/ - sizeof(html40EntitiesTable[0]));i++) { - if (html40EntitiesTable[i].value >= value) { - if (html40EntitiesTable[i].value > value) - break; - return((htmlEntityDescPtr) &html40EntitiesTable[i]); - } - } - return(NULL); + nmemb = sizeof(html40EntitiesTable) / sizeof(html40EntitiesTable[0]); + desc = bsearch(&value, html40EntitiesTable, nmemb, sizeof(htmlEntityDesc), + htmlCompareEntityDesc); + + return(desc); } /** @@ -2320,7 +2229,7 @@ htmlEncodeEntities(unsigned char* out, int *outlen, else cp = ent->name; len = strlen(cp); - if (out + 2 + len > outend) + if (outend - out < len + 2) break; *out++ = '&'; memcpy(out, cp, len); @@ -2334,47 +2243,6 @@ htmlEncodeEntities(unsigned char* out, int *outlen, return(0); } -/************************************************************************ - * * - * Commodity functions to handle streams * - * * - ************************************************************************/ - -#ifdef LIBXML_PUSH_ENABLED -/** - * htmlNewInputStream: - * @ctxt: an HTML parser context - * - * Create a new input stream structure - * Returns the new input stream or NULL - */ -static htmlParserInputPtr -htmlNewInputStream(htmlParserCtxtPtr ctxt) { - htmlParserInputPtr input; - - input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput)); - if (input == NULL) { - htmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); - return(NULL); - } - memset(input, 0, sizeof(htmlParserInput)); - input->filename = NULL; - input->directory = NULL; - input->base = NULL; - input->cur = NULL; - input->buf = NULL; - input->line = 1; - input->col = 1; - input->buf = NULL; - input->free = NULL; - input->version = NULL; - input->consumed = 0; - input->length = 0; - return(input); -} -#endif - - /************************************************************************ * * * Commodity functions, cleanup needed ? * @@ -2480,10 +2348,8 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) { * Allocate a new document and fill the fields. */ cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); - if (cur == NULL) { - htmlErrMemory(NULL, "HTML document creation failed\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDoc)); cur->type = XML_HTML_DOCUMENT_NODE; @@ -2503,8 +2369,15 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) { cur->charset = XML_CHAR_ENCODING_UTF8; cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT; if ((ExternalID != NULL) || - (URI != NULL)) - xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI); + (URI != NULL)) { + xmlDtdPtr intSubset; + + intSubset = xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI); + if (intSubset == NULL) { + xmlFree(cur); + return(NULL); + } + } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); @@ -2552,12 +2425,14 @@ htmlSkipBogusComment(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_HTML_INCORRECTLY_OPENED_COMMENT, "Incorrectly opened comment\n", NULL, NULL); - do { + while (PARSER_STOPPED(ctxt) == 0) { c = CUR; if (c == 0) break; NEXT; - } while (c != '>'); + if (c == '>') + break; + } } /** @@ -2572,6 +2447,7 @@ htmlSkipBogusComment(htmlParserCtxtPtr ctxt) { static const xmlChar * htmlParseHTMLName(htmlParserCtxtPtr ctxt) { + const xmlChar *ret; int i = 0; xmlChar loc[HTML_PARSER_BUFFER_SIZE]; @@ -2589,7 +2465,11 @@ htmlParseHTMLName(htmlParserCtxtPtr ctxt) { NEXT; } - return(xmlDictLookup(ctxt->dict, loc, i)); + ret = xmlDictLookup(ctxt->dict, loc, i); + if (ret == NULL) + htmlErrMemory(ctxt); + + return(ret); } @@ -2608,6 +2488,7 @@ static const xmlChar * htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) { int i = 0; xmlChar loc[HTML_PARSER_BUFFER_SIZE]; + const xmlChar *ret; if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') && (NXT(1) != ':')) return(NULL); @@ -2620,7 +2501,11 @@ htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) { i++; } - return(xmlDictLookup(ctxt->dict, loc, i)); + ret = xmlDictLookup(ctxt->dict, loc, i); + if (ret == NULL) + htmlErrMemory(ctxt); + + return(ret); } @@ -2662,6 +2547,8 @@ htmlParseName(htmlParserCtxtPtr ctxt) { if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + if (ret == NULL) + htmlErrMemory(ctxt); ctxt->input->cur = in; ctxt->input->col += count; return(ret); @@ -2674,13 +2561,15 @@ static const xmlChar * htmlParseNameComplex(xmlParserCtxtPtr ctxt) { int len = 0, l; int c; - int count = 0; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; const xmlChar *base = ctxt->input->base; + const xmlChar *ret; /* * Handler for more complex cases */ - GROW; c = CUR_CHAR(l); if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ (!IS_LETTER(c) && (c != '_') && @@ -2694,11 +2583,11 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) { (c == '_') || (c == ':') || (IS_COMBINING(c)) || (IS_EXTENDER(c)))) { - if (count++ > 100) { - count = 0; - GROW; - } len += l; + if (len > maxLength) { + htmlParseErr(ctxt, XML_ERR_NAME_TOO_LONG, "name too long", NULL, NULL); + return(NULL); + } NEXTL(l); c = CUR_CHAR(l); if (ctxt->input->base != base) { @@ -2717,7 +2606,11 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) { return (NULL); } - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len); + if (ret == NULL) + htmlErrMemory(ctxt); + + return(ret); } @@ -2736,6 +2629,9 @@ static xmlChar * htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { xmlChar *buffer = NULL; int buffer_size = 0; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; xmlChar *out = NULL; const xmlChar *name = NULL; const xmlChar *cur = NULL; @@ -2745,9 +2641,9 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { * allocate a translation buffer. */ buffer_size = HTML_PARSER_BUFFER_SIZE; - buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(buffer_size); if (buffer == NULL) { - htmlErrMemory(ctxt, "buffer allocation failed\n"); + htmlErrMemory(ctxt); return(NULL); } out = buffer; @@ -2755,7 +2651,8 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { /* * Ok loop until we reach one of the ending chars */ - while ((CUR != 0) && (CUR != stop)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != stop)) { if ((stop == 0) && (CUR == '>')) break; if ((stop == 0) && (IS_BLANK_CH(CUR))) break; if (CUR == '&') { @@ -2853,8 +2750,14 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { for ( ; bits >= 0; bits-= 6) { *out++ = ((c >> bits) & 0x3F) | 0x80; } - NEXT; + NEXTL(l); } + if (out - buffer > maxLength) { + htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, + "attribute value too long\n", NULL, NULL); + xmlFree(buffer); + return(NULL); + } } *out = 0; return(buffer); @@ -2865,6 +2768,8 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { * @ctxt: an HTML parser context * @str: location to store the entity name * + * DEPRECATED: Internal function, don't use. + * * parse an HTML ENTITY references * * [68] EntityRef ::= '&' Name ';' @@ -2985,7 +2890,8 @@ htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) { return(ret); startPosition = CUR_PTR - BASE_PTR; - while ((CUR != 0) && (CUR != quote)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != quote)) { /* TODO: Handle UTF-8 */ if (!IS_CHAR_CH(CUR)) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, @@ -2999,9 +2905,14 @@ htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, "Unfinished SystemLiteral\n", NULL, NULL); } else { - NEXT; - if (err == 0) + if (err == 0) { ret = xmlStrndup((BASE_PTR+startPosition), len); + if (ret == NULL) { + htmlErrMemory(ctxt); + return(NULL); + } + } + NEXT; } return(ret); @@ -3040,7 +2951,8 @@ htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) { return(ret); startPosition = CUR_PTR - BASE_PTR; - while ((CUR != 0) && (CUR != quote)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != quote)) { if (!IS_PUBIDCHAR_CH(CUR)) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in PubidLiteral 0x%X\n", CUR); @@ -3054,9 +2966,14 @@ htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, "Unfinished PubidLiteral\n", NULL, NULL); } else { - NEXT; - if (err == 0) + if (err == 0) { ret = xmlStrndup((BASE_PTR + startPosition), len); + if (ret == NULL) { + htmlErrMemory(ctxt); + return(NULL); + } + } + NEXT; } return(ret); @@ -3089,7 +3006,6 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { int nbchar = 0; int cur,l; - SHRINK; cur = CUR_CHAR(l); while (cur != 0) { if ((cur == '<') && (NXT(1) == '/')) { @@ -3128,6 +3044,7 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in CDATA 0x%X\n", cur); } + NEXTL(l); if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) { buf[nbchar] = 0; if (ctxt->sax->cdataBlock!= NULL) { @@ -3139,9 +3056,8 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { ctxt->sax->characters(ctxt->userData, buf, nbchar); } nbchar = 0; + SHRINK; } - GROW; - NEXTL(l); cur = CUR_CHAR(l); } @@ -3175,22 +3091,22 @@ htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) { xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 6]; int nbchar = 0; int cur, l; - int chunk = 0; if (readahead) buf[nbchar++] = readahead; - SHRINK; cur = CUR_CHAR(l); - while (((cur != '<') || (ctxt->token == '<')) && - ((cur != '&') || (ctxt->token == '&')) && - (cur != 0)) { + while ((cur != '<') && + (cur != '&') && + (cur != 0) && + (!PARSER_STOPPED(ctxt))) { if (!(IS_CHAR(cur))) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in CDATA 0x%X\n", cur); } else { COPY_BUF(l,buf,nbchar,cur); } + NEXTL(l); if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) { buf[nbchar] = 0; @@ -3214,20 +3130,9 @@ htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) { } } nbchar = 0; - } - NEXTL(l); - chunk++; - if (chunk > HTML_PARSER_BUFFER_SIZE) { - chunk = 0; SHRINK; - GROW; - } - cur = CUR_CHAR(l); - if (cur == 0) { - SHRINK; - GROW; - cur = CUR_CHAR(l); } + cur = CUR_CHAR(l); } if (nbchar != 0) { buf[nbchar] = 0; @@ -3251,12 +3156,6 @@ htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) { ctxt->sax->characters(ctxt->userData, buf, nbchar); } } - } else { - /* - * Loop detection - */ - if (cur == 0) - ctxt->instate = XML_PARSER_EOF; } } @@ -3334,12 +3233,11 @@ htmlParseExternalID(htmlParserCtxtPtr ctxt, xmlChar **publicID) { } /** - * xmlParsePI: - * @ctxt: an XML parser context - * - * parse an XML Processing Instruction. + * htmlParsePI: + * @ctxt: an HTML parser context * - * [16] PI ::= '' Char*)))? '?>' + * Parse an XML Processing Instruction. HTML5 doesn't allow processing + * instructions, so this will be removed at some point. */ static void htmlParsePI(htmlParserCtxtPtr ctxt) { @@ -3347,9 +3245,11 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { int len = 0; int size = HTML_PARSER_BUFFER_SIZE; int cur, l; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; const xmlChar *target; xmlParserInputState state; - int count = 0; if ((RAW == '<') && (NXT(1) == '?')) { state = ctxt->instate; @@ -3358,7 +3258,6 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { * this is a Processing Instruction. */ SKIP(2); - SHRINK; /* * Parse the target name and check for special support like @@ -3376,13 +3275,11 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, NULL); - ctxt->instate = state; - return; + goto done; } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - htmlErrMemory(ctxt, NULL); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } cur = CUR; @@ -3397,20 +3294,14 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { xmlChar *tmp; size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); xmlFree(buf); - ctxt->instate = state; return; } buf = tmp; } - count++; - if (count > 50) { - GROW; - count = 0; - } if (IS_CHAR(cur)) { COPY_BUF(l,buf,len,cur); } else { @@ -3418,13 +3309,14 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { "Invalid char in processing instruction " "0x%X\n", cur); } + if (len > maxLength) { + htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED, + "PI %s too long", target, NULL); + xmlFree(buf); + goto done; + } NEXTL(l); cur = CUR_CHAR(l); - if (cur == 0) { - SHRINK; - GROW; - cur = CUR_CHAR(l); - } } buf[len] = 0; if (cur != '>') { @@ -3446,6 +3338,8 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED, "PI is not started correctly", NULL, NULL); } + +done: ctxt->instate = state; } } @@ -3454,9 +3348,7 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { * htmlParseComment: * @ctxt: an HTML parser context * - * Parse an XML (SGML) comment - * - * [15] Comment ::= '' + * Parse an HTML comment */ static void htmlParseComment(htmlParserCtxtPtr ctxt) { @@ -3467,6 +3359,9 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { int r, rl; int cur, l; int next, nl; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; xmlParserInputState state; /* @@ -3477,12 +3372,10 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { state = ctxt->instate; ctxt->instate = XML_PARSER_COMMENT; - SHRINK; SKIP(4); - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - htmlErrMemory(ctxt, "buffer allocation failed\n"); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } len = 0; @@ -3511,11 +3404,6 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { (r != '-') || (q != '-'))) { NEXTL(l); next = CUR_CHAR(nl); - if (next == 0) { - SHRINK; - GROW; - next = CUR_CHAR(nl); - } if ((q == '-') && (r == '-') && (cur == '!') && (next == '>')) { htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, @@ -3528,11 +3416,10 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { xmlChar *tmp; size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - htmlErrMemory(ctxt, "growing buffer failed\n"); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } buf = tmp; @@ -3543,6 +3430,13 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in comment 0x%X\n", q); } + if (len > maxLength) { + htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, + "comment too long", NULL, NULL); + xmlFree(buf); + ctxt->instate = state; + return; + } q = r; ql = rl; @@ -3573,6 +3467,8 @@ unfinished: * htmlParseCharRef: * @ctxt: an HTML parser context * + * DEPRECATED: Internal function, don't use. + * * parse Reference declarations * * [66] CharRef ::= '&#' [0-9]+ ';' | @@ -3584,12 +3480,8 @@ int htmlParseCharRef(htmlParserCtxtPtr ctxt) { int val = 0; - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseCharRef: context error\n", - NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return(0); - } if ((CUR == '&') && (NXT(1) == '#') && ((NXT(2) == 'x') || NXT(2) == 'X')) { SKIP(3); @@ -3701,7 +3593,8 @@ htmlParseDocTypeDecl(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, "DOCTYPE improperly terminated\n", NULL, NULL); /* Ignore bogus content */ - while ((CUR != 0) && (CUR != '>')) + while ((CUR != 0) && (CUR != '>') && + (PARSER_STOPPED(ctxt) == 0)) NEXT; } if (CUR == '>') @@ -3769,93 +3662,6 @@ htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) { return(name); } -/** - * htmlCheckEncodingDirect: - * @ctxt: an HTML parser context - * @attvalue: the attribute value - * - * Checks an attribute value to detect - * the encoding - * If a new encoding is detected the parser is switched to decode - * it and pass UTF8 - */ -static void -htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) { - - if ((ctxt == NULL) || (encoding == NULL) || - (ctxt->options & HTML_PARSE_IGNORE_ENC)) - return; - - /* do not change encoding */ - if (ctxt->input->encoding != NULL) - return; - - if (encoding != NULL) { - xmlCharEncoding enc; - xmlCharEncodingHandlerPtr handler; - - while ((*encoding == ' ') || (*encoding == '\t')) encoding++; - - if (ctxt->input->encoding != NULL) - xmlFree((xmlChar *) ctxt->input->encoding); - ctxt->input->encoding = xmlStrdup(encoding); - - enc = xmlParseCharEncoding((const char *) encoding); - /* - * registered set of known encodings - */ - if (enc != XML_CHAR_ENCODING_ERROR) { - if (((enc == XML_CHAR_ENCODING_UTF16LE) || - (enc == XML_CHAR_ENCODING_UTF16BE) || - (enc == XML_CHAR_ENCODING_UCS4LE) || - (enc == XML_CHAR_ENCODING_UCS4BE)) && - (ctxt->input->buf != NULL) && - (ctxt->input->buf->encoder == NULL)) { - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "htmlCheckEncoding: wrong encoding meta\n", - NULL, NULL); - } else { - xmlSwitchEncoding(ctxt, enc); - } - ctxt->charset = XML_CHAR_ENCODING_UTF8; - } else { - /* - * fallback for unknown encodings - */ - handler = xmlFindCharEncodingHandler((const char *) encoding); - if (handler != NULL) { - xmlSwitchToEncoding(ctxt, handler); - ctxt->charset = XML_CHAR_ENCODING_UTF8; - } else { - htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "htmlCheckEncoding: unknown encoding %s\n", - encoding, NULL); - } - } - - if ((ctxt->input->buf != NULL) && - (ctxt->input->buf->encoder != NULL) && - (ctxt->input->buf->raw != NULL) && - (ctxt->input->buf->buffer != NULL)) { - int nbchars; - int processed; - - /* - * convert as much as possible to the parser reading buffer. - */ - processed = ctxt->input->cur - ctxt->input->base; - xmlBufShrink(ctxt->input->buf->buffer, processed); - nbchars = xmlCharEncInput(ctxt->input->buf, 1); - xmlBufResetInput(ctxt->input->buf->buffer, ctxt->input); - if (nbchars < 0) { - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "htmlCheckEncoding: encoder error\n", - NULL, NULL); - } - } - } -} - /** * htmlCheckEncoding: * @ctxt: an HTML parser context @@ -3869,6 +3675,7 @@ htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) { static void htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) { const xmlChar *encoding; + xmlChar *copy; if (!attvalue) return; @@ -3884,7 +3691,10 @@ htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) { encoding = xmlStrcasestr(attvalue, BAD_CAST"="); if (encoding && *encoding == '=') { encoding ++; - htmlCheckEncodingDirect(ctxt, encoding); + copy = xmlStrdup(encoding); + if (copy == NULL) + htmlErrMemory(ctxt); + xmlSetDeclaredEncoding(ctxt, copy); } } @@ -3909,13 +3719,21 @@ htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) { att = atts[i++]; while (att != NULL) { value = atts[i++]; - if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv")) - && (!xmlStrcasecmp(value, BAD_CAST"Content-Type"))) - http = 1; - else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset"))) - htmlCheckEncodingDirect(ctxt, value); - else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content"))) - content = value; + if (value != NULL) { + if ((!xmlStrcasecmp(att, BAD_CAST "http-equiv")) && + (!xmlStrcasecmp(value, BAD_CAST "Content-Type"))) { + http = 1; + } else if (!xmlStrcasecmp(att, BAD_CAST "charset")) { + xmlChar *copy; + + copy = xmlStrdup(value); + if (copy == NULL) + htmlErrMemory(ctxt); + xmlSetDeclaredEncoding(ctxt, copy); + } else if (!xmlStrcasecmp(att, BAD_CAST "content")) { + content = value; + } + } att = atts[i++]; } if ((http) && (content != NULL)) @@ -3955,13 +3773,8 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { int i; int discardtag = 0; - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseStartTag: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return -1; - } - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if (CUR != '<') return -1; NEXT; @@ -3976,7 +3789,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { NULL, NULL); /* Dump the bogus tag like browsers do */ while ((CUR != 0) && (CUR != '>') && - (ctxt->instate != XML_PARSER_EOF)) + (PARSER_STOPPED(ctxt) == 0)) NEXT; return -1; } @@ -4033,7 +3846,8 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { SKIP_BLANKS; while ((CUR != 0) && (CUR != '>') && - ((CUR != '/') || (NXT(1) != '>'))) { + ((CUR != '/') || (NXT(1) != '>')) && + (PARSER_STOPPED(ctxt) == 0)) { GROW; attname = htmlParseAttribute(ctxt, &attvalue); if (attname != NULL) { @@ -4059,7 +3873,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -4073,7 +3887,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { n = (const xmlChar **) xmlRealloc((void *) atts, maxatts * sizeof(const xmlChar *)); if (n == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -4094,7 +3908,8 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { * the end of the tag. */ while ((CUR != 0) && !(IS_BLANK_CH(CUR)) && (CUR != '>') && - ((CUR != '/') || (NXT(1) != '>'))) + ((CUR != '/') || (NXT(1) != '>')) && + (PARSER_STOPPED(ctxt) == 0)) NEXT; } @@ -4171,7 +3986,8 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt) htmlParseErr(ctxt, XML_ERR_GT_REQUIRED, "End tag : expected '>'\n", NULL, NULL); /* Skip to next '>' */ - while ((CUR != 0) && (CUR != '>')) + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != '>')) NEXT; } if (CUR == '>') @@ -4332,12 +4148,9 @@ htmlParseContent(htmlParserCtxtPtr ctxt) { currentNode = xmlStrdup(ctxt->name); depth = ctxt->nameNr; - while (1) { + while (!PARSER_STOPPED(ctxt)) { GROW; - if (ctxt->instate == XML_PARSER_EOF) - break; - /* * Our tag or one of it's parent or children is ending. */ @@ -4461,6 +4274,8 @@ htmlParseContent(htmlParserCtxtPtr ctxt) { else { htmlParseCharData(ctxt); } + + SHRINK; GROW; } if (currentNode != NULL) xmlFree(currentNode); @@ -4470,6 +4285,8 @@ htmlParseContent(htmlParserCtxtPtr ctxt) { * htmlParseElement: * @ctxt: an HTML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an HTML element, this is highly recursive * this is kept for compatibility with previous code versions * @@ -4488,14 +4305,8 @@ htmlParseElement(htmlParserCtxtPtr ctxt) { int depth; const xmlChar *oldptr; - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseElement: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return; - } - - if (ctxt->instate == XML_PARSER_EOF) - return; /* Capture start position */ if (ctxt->record_info) { @@ -4635,14 +4446,8 @@ htmlParseElementInternal(htmlParserCtxtPtr ctxt) { htmlParserNodeInfo node_info = { NULL, 0, 0, 0, 0 }; int failed; - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseElementInternal: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return; - } - - if (ctxt->instate == XML_PARSER_EOF) - return; /* Capture start position */ if (ctxt->record_info) { @@ -4727,14 +4532,19 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { int depth; const xmlChar *name; - currentNode = xmlStrdup(ctxt->name); depth = ctxt->nameNr; - while (1) { + if (depth <= 0) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + return; + } + } + while (PARSER_STOPPED(ctxt) == 0) { GROW; - if (ctxt->instate == XML_PARSER_EOF) - break; - /* * Our tag or one of it's parent or children is ending. */ @@ -4744,8 +4554,16 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { if (currentNode != NULL) xmlFree(currentNode); - currentNode = xmlStrdup(ctxt->name); depth = ctxt->nameNr; + if (depth <= 0) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } + } } continue; /* while */ } @@ -4766,7 +4584,15 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { if (currentNode != NULL) xmlFree(currentNode); - currentNode = xmlStrdup(ctxt->name); + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } + } depth = ctxt->nameNr; continue; } @@ -4789,7 +4615,15 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { htmlParserFinishElementParsing(ctxt); if (currentNode != NULL) xmlFree(currentNode); - currentNode = xmlStrdup(ctxt->name); + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } + } depth = ctxt->nameNr; continue; } @@ -4840,7 +4674,15 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { htmlParseElementInternal(ctxt); if (currentNode != NULL) xmlFree(currentNode); - currentNode = xmlStrdup(ctxt->name); + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } + } depth = ctxt->nameNr; } else if (CUR == '<') { @@ -4872,6 +4714,8 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { else { htmlParseCharData(ctxt); } + + SHRINK; GROW; } if (currentNode != NULL) xmlFree(currentNode); @@ -4895,53 +4739,34 @@ __htmlParseContent(void *ctxt) { * htmlParseDocument: * @ctxt: an HTML parser context * - * parse an HTML document (and build a tree if using the standard SAX - * interface). + * Parse an HTML document and invoke the SAX handlers. This is useful + * if you're only interested in custom SAX callbacks. If you want a + * document tree, use htmlCtxtParseDocument. * - * Returns 0, -1 in case of error. the parser context is augmented - * as a result of the parsing. + * Returns 0, -1 in case of error. */ int htmlParseDocument(htmlParserCtxtPtr ctxt) { - xmlChar start[4]; - xmlCharEncoding enc; xmlDtdPtr dtd; - xmlInitParser(); - - htmlDefaultSAXHandlerInit(); + if ((ctxt == NULL) || (ctxt->input == NULL)) + return(-1); - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseDocument: context error\n", NULL, NULL); - return(XML_ERR_INTERNAL_ERROR); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); } - ctxt->html = 1; - ctxt->linenumbers = 1; - GROW; - /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); - if ((ctxt->encoding == (const xmlChar *)XML_CHAR_ENCODING_NONE) && - ((ctxt->input->end - ctxt->input->cur) >= 4)) { - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. - */ - start[0] = RAW; - start[1] = NXT(1); - start[2] = NXT(2); - start[3] = NXT(3); - enc = xmlDetectCharEncoding(&start[0], 4); - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } - } + xmlDetectEncoding(ctxt); + + /* + * This is wrong but matches long-standing behavior. In most cases, + * a document starting with an XML declaration will specify UTF-8. + */ + if (((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) && + (xmlStrncmp(ctxt->input->cur, BAD_CAST "sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - /* * Parse possible comments and PIs before any content */ @@ -4984,9 +4808,10 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { /* * Parse possible comments and PIs before any content */ - while (((CUR == '<') && (NXT(1) == '!') && - (NXT(2) == '-') && (NXT(3) == '-')) || - ((CUR == '<') && (NXT(1) == '?'))) { + while ((PARSER_STOPPED(ctxt) == 0) && + (((CUR == '<') && (NXT(1) == '!') && + (NXT(2) == '-') && (NXT(3) == '-')) || + ((CUR == '<') && (NXT(1) == '?')))) { htmlParseComment(ctxt); htmlParsePI(ctxt); SKIP_BLANKS; @@ -5012,11 +4837,14 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) { dtd = xmlGetIntSubset(ctxt->myDoc); - if (dtd == NULL) + if (dtd == NULL) { ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html", BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN", BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd"); + if (ctxt->myDoc->intSubset == NULL) + htmlErrMemory(ctxt); + } } if (! ctxt->wellFormed) return(-1); return(0); @@ -5032,6 +4860,8 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { /** * htmlInitParserCtxt: * @ctxt: an HTML parser context + * @sax: SAX handler + * @userData: user data * * Initialize a parser context * @@ -5039,35 +4869,34 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { */ static int -htmlInitParserCtxt(htmlParserCtxtPtr ctxt) +htmlInitParserCtxt(htmlParserCtxtPtr ctxt, const htmlSAXHandler *sax, + void *userData) { - htmlSAXHandler *sax; - if (ctxt == NULL) return(-1); memset(ctxt, 0, sizeof(htmlParserCtxt)); ctxt->dict = xmlDictCreate(); - if (ctxt->dict == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); + if (ctxt->dict == NULL) return(-1); - } - sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler)); - if (sax == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); + + if (ctxt->sax == NULL) + ctxt->sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler)); + if (ctxt->sax == NULL) return(-1); + if (sax == NULL) { + memset(ctxt->sax, 0, sizeof(htmlSAXHandler)); + xmlSAX2InitHtmlDefaultSAXHandler(ctxt->sax); + ctxt->userData = ctxt; + } else { + memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler)); + ctxt->userData = userData ? userData : ctxt; } - memset(sax, 0, sizeof(htmlSAXHandler)); /* Allocate the Input stack */ ctxt->inputTab = (htmlParserInputPtr *) xmlMalloc(5 * sizeof(htmlParserInputPtr)); - if (ctxt->inputTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->inputTab == NULL) return(-1); - } ctxt->inputNr = 0; ctxt->inputMax = 5; ctxt->input = NULL; @@ -5078,35 +4907,16 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt) /* Allocate the Node stack */ ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr)); - if (ctxt->nodeTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nodeTab == NULL) return(-1); - } ctxt->nodeNr = 0; ctxt->nodeMax = 10; ctxt->node = NULL; /* Allocate the Name stack */ ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); - if (ctxt->nameTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nameTab == NULL) return(-1); - } ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; @@ -5115,10 +4925,6 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt) ctxt->nodeInfoNr = 0; ctxt->nodeInfoMax = 0; - ctxt->sax = sax; - xmlSAX2InitHtmlDefaultSAXHandler(sax); - - ctxt->userData = ctxt; ctxt->myDoc = NULL; ctxt->wellFormed = 1; ctxt->replaceEntities = 0; @@ -5154,127 +4960,139 @@ htmlFreeParserCtxt(htmlParserCtxtPtr ctxt) /** * htmlNewParserCtxt: * - * Allocate and initialize a new parser context. + * Allocate and initialize a new HTML parser context. + * + * This can be used to parse HTML documents into DOM trees with + * functions like xmlCtxtReadFile or xmlCtxtReadMemory. + * + * See htmlCtxtUseOptions for parser options. + * + * See xmlCtxtSetErrorHandler for advanced error handling. + * + * See xmlNewInputURL, xmlNewInputMemory, xmlNewInputIO and similar + * functions for advanced input control. + * + * See htmlNewSAXParserCtxt for custom SAX parsers. * * Returns the htmlParserCtxtPtr or NULL in case of allocation error */ htmlParserCtxtPtr htmlNewParserCtxt(void) +{ + return(htmlNewSAXParserCtxt(NULL, NULL)); +} + +/** + * htmlNewSAXParserCtxt: + * @sax: SAX handler + * @userData: user data + * + * Allocate and initialize a new HTML SAX parser context. If userData + * is NULL, the parser context will be passed as user data. + * + * Available since 2.11.0. If you want support older versions, + * it's best to invoke htmlNewParserCtxt and set ctxt->sax with + * struct assignment. + * + * Also see htmlNewParserCtxt. + * + * Returns the htmlParserCtxtPtr or NULL in case of allocation error + */ + +htmlParserCtxtPtr +htmlNewSAXParserCtxt(const htmlSAXHandler *sax, void *userData) { xmlParserCtxtPtr ctxt; + xmlInitParser(); + ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); - if (ctxt == NULL) { - htmlErrMemory(NULL, "NewParserCtxt: out of memory\n"); + if (ctxt == NULL) return(NULL); - } memset(ctxt, 0, sizeof(xmlParserCtxt)); - if (htmlInitParserCtxt(ctxt) < 0) { + if (htmlInitParserCtxt(ctxt, sax, userData) < 0) { htmlFreeParserCtxt(ctxt); return(NULL); } return(ctxt); } -/** - * htmlCreateMemoryParserCtxt: - * @buffer: a pointer to a char array - * @size: the size of the array - * - * Create a parser context for an HTML in-memory document. - * - * Returns the new parser context or NULL - */ -htmlParserCtxtPtr -htmlCreateMemoryParserCtxt(const char *buffer, int size) { +static htmlParserCtxtPtr +htmlCreateMemoryParserCtxtInternal(const char *url, + const char *buffer, size_t size, + const char *encoding) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf; if (buffer == NULL) return(NULL); - if (size <= 0) - return(NULL); ctxt = htmlNewParserCtxt(); if (ctxt == NULL) return(NULL); - buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (buf == NULL) return(NULL); - - input = xmlNewInputStream(ctxt); + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); - return(NULL); + return(NULL); } - input->filename = NULL; - input->buf = buf; - xmlBufResetInput(buf->buffer, input); - inputPush(ctxt, input); + return(ctxt); } /** - * htmlCreateDocParserCtxt: - * @cur: a pointer to an array of xmlChar - * @encoding: a free form C string describing the HTML document encoding, or NULL + * htmlCreateMemoryParserCtxt: + * @buffer: a pointer to a char array + * @size: the size of the array * - * Create a parser context for an HTML document. + * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadMemory. * - * TODO: check the need to add encoding handling there + * Create a parser context for an HTML in-memory document. The input + * buffer must not contain any terminating null bytes. * * Returns the new parser context or NULL */ +htmlParserCtxtPtr +htmlCreateMemoryParserCtxt(const char *buffer, int size) { + if (size <= 0) + return(NULL); + + return(htmlCreateMemoryParserCtxtInternal(NULL, buffer, size, NULL)); +} + +/** + * htmlCreateDocParserCtxt: + * @str: a pointer to an array of xmlChar + * @encoding: encoding (optional) + * + * Create a parser context for a null-terminated string. + * + * Returns the new parser context or NULL if a memory allocation failed. + */ static htmlParserCtxtPtr -htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) { - int len; - htmlParserCtxtPtr ctxt; +htmlCreateDocParserCtxt(const xmlChar *str, const char *url, + const char *encoding) { + xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; - if (cur == NULL) + if (str == NULL) return(NULL); - len = xmlStrlen(cur); - ctxt = htmlCreateMemoryParserCtxt((char *)cur, len); + + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) return(NULL); - if (encoding != NULL) { - xmlCharEncoding enc; - xmlCharEncodingHandlerPtr handler; + input = xmlNewInputString(ctxt, url, (const char *) str, encoding, 0); + if (input == NULL) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } - if (ctxt->input->encoding != NULL) - xmlFree((xmlChar *) ctxt->input->encoding); - ctxt->input->encoding = xmlStrdup((const xmlChar *) encoding); + inputPush(ctxt, input); - enc = xmlParseCharEncoding(encoding); - /* - * registered set of known encodings - */ - if (enc != XML_CHAR_ENCODING_ERROR) { - xmlSwitchEncoding(ctxt, enc); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", - (const xmlChar *) encoding, NULL); - } - } else { - /* - * fallback for unknown encodings - */ - handler = xmlFindCharEncodingHandler((const char *) encoding); - if (handler != NULL) { - xmlSwitchToEncoding(ctxt, handler); - } else { - htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", - (const xmlChar *) encoding, NULL); - } - } - } return(ctxt); } @@ -5307,33 +5125,20 @@ static int htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first, xmlChar next, xmlChar third, int ignoreattrval) { - int base, len; + size_t base, len; htmlParserInputPtr in; const xmlChar *buf; - int invalue = 0; - char valdellim = 0x0; + int quote; in = ctxt->input; if (in == NULL) return (-1); - base = in->cur - in->base; - if (base < 0) - return (-1); + base = ctxt->checkIndex; + quote = ctxt->endCheckState; - if (ctxt->checkIndex > base) { - base = ctxt->checkIndex; - /* Abuse hasPErefs member to restore current state. */ - invalue = ctxt->hasPErefs & 1 ? 1 : 0; - } - - if (in->buf == NULL) { - buf = in->base; - len = in->length; - } else { - buf = xmlBufContent(in->buf->buffer); - len = xmlBufUse(in->buf->buffer); - } + buf = in->cur; + len = in->end - in->cur; /* take into account the sequence length */ if (third) @@ -5341,19 +5146,19 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first, else if (next) len--; for (; base < len; base++) { + if (base >= INT_MAX / 2) { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return (base - 2); + } if (ignoreattrval) { + if (quote) { + if (buf[base] == quote) + quote = 0; + continue; + } if (buf[base] == '"' || buf[base] == '\'') { - if (invalue) { - if (buf[base] == valdellim) { - invalue = 0; - continue; - } - } else { - valdellim = buf[base]; - invalue = 1; - continue; - } - } else if (invalue) { + quote = buf[base]; continue; } } @@ -5366,41 +5171,12 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first, continue; } ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - if (next == 0) - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c' found at %d\n", - first, base); - else if (third == 0) - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c%c' found at %d\n", - first, next, base); - else - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c%c%c' found at %d\n", - first, next, third, base); -#endif - return (base - (in->cur - in->base)); + ctxt->endCheckState = 0; + return (base); } } ctxt->checkIndex = base; - /* Abuse hasPErefs member to track current state. */ - if (invalue) - ctxt->hasPErefs |= 1; - else - ctxt->hasPErefs &= ~1; -#ifdef DEBUG_PUSH - if (next == 0) - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c' failed\n", first); - else if (third == 0) - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c%c' failed\n", first, next); - else - xmlGenericError(xmlGenericErrorContext, - "HPP: lookup '%c%c%c' failed\n", first, next, - third); -#endif + ctxt->endCheckState = quote; return (-1); } @@ -5422,16 +5198,23 @@ static int htmlParseLookupCommentEnd(htmlParserCtxtPtr ctxt) { int mark = 0; - int cur = CUR_PTR - BASE_PTR; + int offset; - while (mark >= 0) { + while (1) { mark = htmlParseLookupSequence(ctxt, '-', '-', 0, 0); - if ((mark < 0) || - (NXT(mark+2) == '>') || + if (mark < 0) + break; + if ((NXT(mark+2) == '>') || ((NXT(mark+2) == '!') && (NXT(mark+3) == '>'))) { - return mark; + ctxt->checkIndex = 0; + break; } - ctxt->checkIndex = cur + mark + 1; + offset = (NXT(mark+2) == '!') ? 3 : 2; + if (mark + offset >= ctxt->input->end - ctxt->input->cur) { + ctxt->checkIndex = mark; + return(-1); + } + ctxt->checkIndex = mark + 1; } return mark; } @@ -5455,68 +5238,11 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { htmlParserNodeInfo node_info; -#ifdef DEBUG_PUSH - switch (ctxt->instate) { - case XML_PARSER_EOF: - xmlGenericError(xmlGenericErrorContext, - "HPP: try EOF\n"); break; - case XML_PARSER_START: - xmlGenericError(xmlGenericErrorContext, - "HPP: try START\n"); break; - case XML_PARSER_MISC: - xmlGenericError(xmlGenericErrorContext, - "HPP: try MISC\n");break; - case XML_PARSER_COMMENT: - xmlGenericError(xmlGenericErrorContext, - "HPP: try COMMENT\n");break; - case XML_PARSER_PROLOG: - xmlGenericError(xmlGenericErrorContext, - "HPP: try PROLOG\n");break; - case XML_PARSER_START_TAG: - xmlGenericError(xmlGenericErrorContext, - "HPP: try START_TAG\n");break; - case XML_PARSER_CONTENT: - xmlGenericError(xmlGenericErrorContext, - "HPP: try CONTENT\n");break; - case XML_PARSER_CDATA_SECTION: - xmlGenericError(xmlGenericErrorContext, - "HPP: try CDATA_SECTION\n");break; - case XML_PARSER_END_TAG: - xmlGenericError(xmlGenericErrorContext, - "HPP: try END_TAG\n");break; - case XML_PARSER_ENTITY_DECL: - xmlGenericError(xmlGenericErrorContext, - "HPP: try ENTITY_DECL\n");break; - case XML_PARSER_ENTITY_VALUE: - xmlGenericError(xmlGenericErrorContext, - "HPP: try ENTITY_VALUE\n");break; - case XML_PARSER_ATTRIBUTE_VALUE: - xmlGenericError(xmlGenericErrorContext, - "HPP: try ATTRIBUTE_VALUE\n");break; - case XML_PARSER_DTD: - xmlGenericError(xmlGenericErrorContext, - "HPP: try DTD\n");break; - case XML_PARSER_EPILOG: - xmlGenericError(xmlGenericErrorContext, - "HPP: try EPILOG\n");break; - case XML_PARSER_PI: - xmlGenericError(xmlGenericErrorContext, - "HPP: try PI\n");break; - case XML_PARSER_SYSTEM_LITERAL: - xmlGenericError(xmlGenericErrorContext, - "HPP: try SYSTEM_LITERAL\n");break; - } -#endif - - while (1) { + while (PARSER_STOPPED(ctxt) == 0) { in = ctxt->input; if (in == NULL) break; - if (in->buf == NULL) - avail = in->length - (in->cur - in->base); - else - avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) - - (in->cur - in->base); + avail = in->end - in->cur; if ((avail == 0) && (terminate)) { htmlAutoCloseOnEnd(ctxt); if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) { @@ -5549,21 +5275,28 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { */ goto done; case XML_PARSER_START: + /* + * This is wrong but matches long-standing behavior. In most + * cases, a document starting with an XML declaration will + * specify UTF-8. + */ + if (((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) && + (xmlStrncmp(ctxt->input->cur, BAD_CAST "cur[0]; if (IS_BLANK_CH(cur)) { SKIP_BLANKS; - if (in->buf == NULL) - avail = in->length - (in->cur - in->base); - else - avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) - - (in->cur - in->base); + avail = in->end - in->cur; } - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); + } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); @@ -5578,31 +5311,15 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing internal subset\n"); -#endif htmlParseDocTypeDecl(ctxt); ctxt->instate = XML_PARSER_PROLOG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering PROLOG\n"); -#endif } else { ctxt->instate = XML_PARSER_MISC; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering MISC\n"); -#endif } break; case XML_PARSER_MISC: SKIP_BLANKS; - if (in->buf == NULL) - avail = in->length - (in->cur - in->base); - else - avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) - - (in->cur - in->base); + avail = in->end - in->cur; /* * no chars in buffer */ @@ -5624,20 +5341,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (in->cur[2] == '-') && (in->cur[3] == '-')) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing Comment\n"); -#endif htmlParseComment(ctxt); ctxt->instate = XML_PARSER_MISC; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing PI\n"); -#endif htmlParsePI(ctxt); ctxt->instate = XML_PARSER_MISC; } else if ((cur == '<') && (next == '!') && @@ -5648,34 +5357,18 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing internal subset\n"); -#endif htmlParseDocTypeDecl(ctxt); ctxt->instate = XML_PARSER_PROLOG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering PROLOG\n"); -#endif } else if ((cur == '<') && (next == '!') && (avail < 9)) { goto done; } else { ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering START_TAG\n"); -#endif } break; case XML_PARSER_PROLOG: SKIP_BLANKS; - if (in->buf == NULL) - avail = in->length - (in->cur - in->base); - else - avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) - - (in->cur - in->base); + avail = in->end - in->cur; if (avail < 2) goto done; cur = in->cur[0]; @@ -5684,20 +5377,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (in->cur[2] == '-') && (in->cur[3] == '-')) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing Comment\n"); -#endif htmlParseComment(ctxt); ctxt->instate = XML_PARSER_PROLOG; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing PI\n"); -#endif htmlParsePI(ctxt); ctxt->instate = XML_PARSER_PROLOG; } else if ((cur == '<') && (next == '!') && @@ -5705,18 +5390,10 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { goto done; } else { ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering START_TAG\n"); -#endif } break; case XML_PARSER_EPILOG: - if (in->buf == NULL) - avail = in->length - (in->cur - in->base); - else - avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) - - (in->cur - in->base); + avail = in->end - in->cur; if (avail < 1) goto done; cur = in->cur[0]; @@ -5731,20 +5408,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (in->cur[2] == '-') && (in->cur[3] == '-')) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing Comment\n"); -#endif htmlParseComment(ctxt); ctxt->instate = XML_PARSER_EPILOG; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing PI\n"); -#endif htmlParsePI(ctxt); ctxt->instate = XML_PARSER_EPILOG; } else if ((cur == '<') && (next == '!') && @@ -5754,10 +5423,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { ctxt->errNo = XML_ERR_DOCUMENT_END; ctxt->wellFormed = 0; ctxt->instate = XML_PARSER_EOF; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering EOF\n"); -#endif if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); goto done; @@ -5787,19 +5452,11 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { cur = in->cur[0]; if (cur != '<') { ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif break; } if (next == '/') { ctxt->instate = XML_PARSER_END_TAG; ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering END_TAG\n"); -#endif break; } if ((!terminate) && @@ -5841,10 +5498,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { ctxt->sax->endElement(ctxt->userData, name); htmlnamePop(ctxt); ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif break; } @@ -5867,10 +5520,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { htmlNodeInfoPush(ctxt, &node_info); ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif break; } @@ -5887,10 +5536,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { htmlNodeInfoPush(ctxt, &node_info); ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif break; } case XML_PARSER_CONTENT: { @@ -5899,14 +5544,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { /* * Handle preparsed entities and charRef */ - if (ctxt->token != 0) { - chr[0] = (xmlChar) ctxt->token; - htmlCheckParagraph(ctxt); - if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL)) - ctxt->sax->characters(ctxt->userData, chr, 1); - ctxt->token = 0; - ctxt->checkIndex = 0; - } if ((avail == 1) && (terminate)) { cur = in->cur[0]; if ((cur != '<') && (cur != '&')) { @@ -5929,7 +5566,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { ctxt->userData, chr, 1); } } - ctxt->token = 0; ctxt->checkIndex = 0; in->cur++; break; @@ -5952,20 +5588,24 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if (idx < 0) goto done; val = in->cur[idx + 2]; - if (val == 0) /* bad cut of input */ + if (val == 0) { /* bad cut of input */ + /* + * FIXME: htmlParseScript checks for additional + * characters after 'checkIndex = idx; goto done; + } } htmlParseScript(ctxt); if ((cur == '<') && (next == '/')) { ctxt->instate = XML_PARSER_END_TAG; ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering END_TAG\n"); -#endif break; } } else if ((cur == '<') && (next == '!')) { + if (avail < 4) + goto done; /* * Sometimes DOCTYPE arrives in the middle of the document */ @@ -5984,10 +5624,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing Comment\n"); -#endif htmlParseComment(ctxt); ctxt->instate = XML_PARSER_CONTENT; } else { @@ -6000,31 +5636,17 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing PI\n"); -#endif htmlParsePI(ctxt); ctxt->instate = XML_PARSER_CONTENT; - } else if ((cur == '<') && (next == '!') && (avail < 4)) { - goto done; } else if ((cur == '<') && (next == '/')) { ctxt->instate = XML_PARSER_END_TAG; ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering END_TAG\n"); -#endif break; } else if ((cur == '<') && IS_ASCII_LETTER(next)) { if ((!terminate) && (next == 0)) goto done; ctxt->instate = XML_PARSER_START_TAG; ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering START_TAG\n"); -#endif break; } else if (cur == '<') { if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && @@ -6043,11 +5665,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0)) goto done; ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: Parsing char data\n"); -#endif - while ((ctxt->instate != XML_PARSER_EOF) && + while ((PARSER_STOPPED(ctxt) == 0) && (cur != '<') && (in->cur < in->end)) { if (cur == '&') { htmlParseReference(ctxt); @@ -6073,122 +5691,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { ctxt->instate = XML_PARSER_CONTENT; } ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif break; - case XML_PARSER_CDATA_SECTION: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == CDATA\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_DTD: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == DTD\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_COMMENT: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == COMMENT\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_PI: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == PI\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_ENTITY_DECL: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == ENTITY_DECL\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_ENTITY_VALUE: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == ENTITY_VALUE\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering DTD\n"); -#endif - break; - case XML_PARSER_ATTRIBUTE_VALUE: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == ATTRIBUTE_VALUE\n", - NULL, NULL); - ctxt->instate = XML_PARSER_START_TAG; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering START_TAG\n"); -#endif - break; - case XML_PARSER_SYSTEM_LITERAL: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == XML_PARSER_SYSTEM_LITERAL\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_IGNORE: - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == XML_PARSER_IGNORE\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_PUBLIC_LITERAL: + default: htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "HPP: internal error, state == XML_PARSER_LITERAL\n", - NULL, NULL); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "HPP: entering CONTENT\n"); -#endif + "HPP: internal error\n", NULL, NULL); + ctxt->instate = XML_PARSER_EOF; break; - } } done: @@ -6208,85 +5716,62 @@ done: (ctxt->instate == XML_PARSER_EPILOG))) { xmlDtdPtr dtd; dtd = xmlGetIntSubset(ctxt->myDoc); - if (dtd == NULL) + if (dtd == NULL) { ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html", BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN", BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd"); + if (ctxt->myDoc->intSubset == NULL) + htmlErrMemory(ctxt); + } } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "HPP: done %d\n", ret); -#endif return(ret); } /** * htmlParseChunk: * @ctxt: an HTML parser context - * @chunk: an char array - * @size: the size in byte of the chunk + * @chunk: chunk of memory + * @size: size of chunk in bytes * @terminate: last chunk indicator * - * Parse a Chunk of memory + * Parse a chunk of memory in push parser mode. + * + * Assumes that the parser context was initialized with + * htmlCreatePushParserCtxt. + * + * The last chunk, which will often be empty, must be marked with + * the @terminate flag. With the default SAX callbacks, the resulting + * document will be available in ctxt->myDoc. This pointer will not + * be freed by the library. + * + * If the document isn't well-formed, ctxt->myDoc is set to NULL. * - * Returns zero if no error, the xmlParserErrors otherwise. + * Returns an xmlParserErrors code (0 on success). */ int htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate) { - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseChunk: context error\n", NULL, NULL); - return(XML_ERR_INTERNAL_ERROR); - } + if ((ctxt == NULL) || (ctxt->input == NULL)) + return(XML_ERR_ARGUMENT); + if (PARSER_STOPPED(ctxt) != 0) + return(ctxt->errNo); if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input); - size_t cur = ctxt->input->cur - ctxt->input->base; + (ctxt->input->buf != NULL)) { + size_t pos = ctxt->input->cur - ctxt->input->base; int res; res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); + xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { - ctxt->errNo = XML_PARSER_EOF; - ctxt->disableSAX = 1; - return (XML_PARSER_EOF); - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size); -#endif - -#if 0 - if ((terminate) || (ctxt->input->buf->buffer->use > 80)) - htmlParseTryOrFinish(ctxt, terminate); -#endif - } else if (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->input != NULL) && ctxt->input->buf != NULL) { - xmlParserInputBufferPtr in = ctxt->input->buf; - if ((in->encoder != NULL) && (in->buffer != NULL) && - (in->raw != NULL)) { - int nbchars; - size_t base = xmlBufGetInputBase(in->buffer, ctxt->input); - size_t current = ctxt->input->cur - ctxt->input->base; - - nbchars = xmlCharEncInput(in, terminate); - xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current); - if (nbchars < 0) { - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "encoder error\n", NULL, NULL); - return(XML_ERR_INVALID_ENCODING); - } - } + htmlParseErr(ctxt, ctxt->input->buf->error, + "xmlParserInputBufferPush failed", NULL, NULL); + xmlHaltParser(ctxt); + return (ctxt->errNo); } } htmlParseTryOrFinish(ctxt, terminate); if (terminate) { - if ((ctxt->instate != XML_PARSER_EOF) && - (ctxt->instate != XML_PARSER_EPILOG) && - (ctxt->instate != XML_PARSER_MISC)) { - ctxt->errNo = XML_ERR_DOCUMENT_END; - ctxt->wellFormed = 0; - } if (ctxt->instate != XML_PARSER_EOF) { if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); @@ -6304,88 +5789,37 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size, /** * htmlCreatePushParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks - * @chunk: a pointer to an array of chars + * @sax: a SAX handler (optional) + * @user_data: The user data returned on SAX callbacks (optional) + * @chunk: a pointer to an array of chars (optional) * @size: number of chars in the array - * @filename: an optional file name or URI - * @enc: an optional encoding + * @filename: only used for error reporting (optional) + * @enc: encoding (deprecated, pass XML_CHAR_ENCODING_NONE) * - * Create a parser context for using the HTML parser in push mode - * The value of @filename is used for fetching external entities - * and error/warning reports. + * Create a parser context for using the HTML parser in push mode. * - * Returns the new parser context or NULL + * Returns the new parser context or NULL if a memory allocation + * failed. */ htmlParserCtxtPtr htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename, xmlCharEncoding enc) { htmlParserCtxtPtr ctxt; - htmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - - xmlInitParser(); - - buf = xmlAllocParserInputBuffer(enc); - if (buf == NULL) return(NULL); + htmlParserInputPtr input; + const char *encoding; - ctxt = htmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); + ctxt = htmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) return(NULL); - } - if(enc==XML_CHAR_ENCODING_UTF8 || buf->encoder) - ctxt->charset=XML_CHAR_ENCODING_UTF8; - if (sax != NULL) { - if (ctxt->sax != (xmlSAXHandlerPtr) &htmlDefaultSAXHandler) - xmlFree(ctxt->sax); - ctxt->sax = (htmlSAXHandlerPtr) xmlMalloc(sizeof(htmlSAXHandler)); - if (ctxt->sax == NULL) { - xmlFree(buf); - xmlFree(ctxt); - return(NULL); - } - memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler)); - if (user_data != NULL) - ctxt->userData = user_data; - } - if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - } - inputStream = htmlNewInputStream(ctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(ctxt); - xmlFree(buf); + encoding = xmlGetCharEncodingName(enc); + input = xmlNewInputPush(ctxt, filename, chunk, size, encoding); + if (input == NULL) { + htmlFreeParserCtxt(ctxt); return(NULL); } - - if (filename == NULL) - inputStream->filename = NULL; - else - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - inputStream->buf = buf; - xmlBufResetInput(buf->buffer, inputStream); - - inputPush(ctxt, inputStream); - - if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input); - size_t cur = ctxt->input->cur - ctxt->input->base; - - xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size); -#endif - } - ctxt->progressive = 1; + inputPush(ctxt, input); return(ctxt); } @@ -6398,6 +5832,8 @@ htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data, * @sax: the SAX handler block * @userData: if using SAX, this pointer will be provided on callbacks. * + * DEPRECATED: Use htmlNewSAXParserCtxt and htmlCtxtReadDoc. + * * Parse an HTML in-memory document. If sax is not NULL, use the SAX callbacks * to handle parse events. If sax is NULL, fallback to the default DOM * behavior and return a tree. @@ -6412,25 +5848,20 @@ htmlSAXParseDoc(const xmlChar *cur, const char *encoding, htmlDocPtr ret; htmlParserCtxtPtr ctxt; - xmlInitParser(); - - if (cur == NULL) return(NULL); + if (cur == NULL) + return(NULL); + ctxt = htmlCreateDocParserCtxt(cur, NULL, encoding); + if (ctxt == NULL) + return(NULL); - ctxt = htmlCreateDocParserCtxt(cur, encoding); - if (ctxt == NULL) return(NULL); if (sax != NULL) { - if (ctxt->sax != NULL) xmlFree (ctxt->sax); - ctxt->sax = sax; + *ctxt->sax = *sax; ctxt->userData = userData; } htmlParseDocument(ctxt); ret = ctxt->myDoc; - if (sax != NULL) { - ctxt->sax = NULL; - ctxt->userData = NULL; - } htmlFreeParserCtxt(ctxt); return(ret); @@ -6439,9 +5870,13 @@ htmlSAXParseDoc(const xmlChar *cur, const char *encoding, /** * htmlParseDoc: * @cur: a pointer to an array of xmlChar - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: the encoding (optional) + * + * DEPRECATED: Use htmlReadDoc. * - * parse an HTML in-memory document and build a tree. + * Parse an HTML in-memory document and build a tree. + * + * This function uses deprecated global parser options. * * Returns the resulting document tree */ @@ -6455,22 +5890,24 @@ htmlParseDoc(const xmlChar *cur, const char *encoding) { /** * htmlCreateFileParserCtxt: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: optional encoding + * + * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadFile. + * + * Create a parser context to read from a file. + * + * A non-NULL encoding overrides encoding declarations in the document. * - * Create a parser context for a file content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * - * Returns the new parser context or NULL + * Returns the new parser context or NULL if a memory allocation failed. */ htmlParserCtxtPtr htmlCreateFileParserCtxt(const char *filename, const char *encoding) { htmlParserCtxtPtr ctxt; - htmlParserInputPtr inputStream; - char *canonicFilename; - /* htmlCharEncoding enc; */ - xmlChar *content, *content_line = (xmlChar *) "charset="; + htmlParserInputPtr input; if (filename == NULL) return(NULL); @@ -6479,40 +5916,13 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding) if (ctxt == NULL) { return(NULL); } - canonicFilename = (char *) xmlCanonicPath((const xmlChar *) filename); - if (canonicFilename == NULL) { -#ifdef LIBXML_SAX1_ENABLED - if (xmlDefaultSAXHandler.error != NULL) { - xmlDefaultSAXHandler.error(NULL, "out of memory\n"); - } -#endif - xmlFreeParserCtxt(ctxt); - return(NULL); - } - inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt); - xmlFree(canonicFilename); - if (inputStream == NULL) { + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + if (input == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); } - - inputPush(ctxt, inputStream); - - /* set encoding */ - if (encoding) { - size_t l = strlen(encoding); - - if (l < 1000) { - content = xmlMallocAtomic (xmlStrlen(content_line) + l + 1); - if (content) { - strcpy ((char *)content, (char *)content_line); - strcat ((char *)content, (char *)encoding); - htmlCheckEncoding (ctxt, content); - xmlFree (content); - } - } - } + inputPush(ctxt, input); return(ctxt); } @@ -6520,10 +5930,12 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding) /** * htmlSAXParseFile: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: encoding (optional) * @sax: the SAX handler block * @userData: if using SAX, this pointer will be provided on callbacks. * + * DEPRECATED: Use htmlNewSAXParserCtxt and htmlCtxtReadFile. + * * parse an HTML 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. @@ -6540,8 +5952,6 @@ htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr s htmlParserCtxtPtr ctxt; htmlSAXHandlerPtr oldsax = NULL; - xmlInitParser(); - ctxt = htmlCreateFileParserCtxt(filename, encoding); if (ctxt == NULL) return(NULL); if (sax != NULL) { @@ -6565,10 +5975,11 @@ htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr s /** * htmlParseFile: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: encoding (optional) * - * parse an HTML file and build a tree. Automatic support for ZLIB/Compress - * compressed document is provided by default if found at compile-time. + * Parse an HTML file and build a tree. + * + * See xmlNewInputURL for details. * * Returns the resulting document tree */ @@ -6582,6 +5993,8 @@ htmlParseFile(const char *filename, const char *encoding) { * htmlHandleOmittedElem: * @val: int 0 or 1 * + * DEPRECATED: Use HTML_PARSE_NOIMPLIED + * * Set and return the previous value for handling HTML omitted tags. * * Returns the last value for 0 for no handling, 1 for auto insertion. @@ -6687,7 +6100,7 @@ htmlAttrAllowed(const htmlElemDesc* elt, const xmlChar* attr, int legacy) { * for other nodes, HTML_NA (no checks performed) */ htmlStatus -htmlNodeStatus(const htmlNodePtr node, int legacy) { +htmlNodeStatus(htmlNodePtr node, int legacy) { if ( ! node ) return HTML_INVALID ; @@ -6739,7 +6152,6 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) if (ctxt == NULL) return; - xmlInitParser(); dict = ctxt->dict; while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ @@ -6769,12 +6181,16 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) ctxt->version = NULL; DICT_FREE(ctxt->encoding); ctxt->encoding = NULL; - DICT_FREE(ctxt->directory); - ctxt->directory = NULL; DICT_FREE(ctxt->extSubURI); ctxt->extSubURI = NULL; DICT_FREE(ctxt->extSubSystem); ctxt->extSubSystem = NULL; + + if (ctxt->directory != NULL) { + xmlFree(ctxt->directory); + ctxt->directory = NULL; + } + if (ctxt->myDoc != NULL) xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -6783,23 +6199,22 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 1; - ctxt->external = 0; ctxt->instate = XML_PARSER_START; - ctxt->token = 0; ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; ctxt->disableSAX = 0; ctxt->valid = 1; ctxt->vctxt.userData = ctxt; + ctxt->vctxt.flags = XML_VCTXT_USE_PCTXT; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning; ctxt->record_info = 0; ctxt->checkIndex = 0; + ctxt->endCheckState = 0; ctxt->inSubset = 0; ctxt->errNo = XML_ERR_OK; ctxt->depth = 0; - ctxt->charset = XML_CHAR_ENCODING_NONE; ctxt->catalogs = NULL; xmlInitNodeInfoSeq(&ctxt->node_seq); @@ -6811,6 +6226,11 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) xmlHashFree(ctxt->attsSpecial, NULL); ctxt->attsSpecial = NULL; } + + ctxt->nbErrors = 0; + ctxt->nbWarnings = 0; + if (ctxt->lastError.code != XML_ERR_OK) + xmlResetError(&ctxt->lastError); } /** @@ -6881,253 +6301,286 @@ htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options) options -= HTML_PARSE_NOIMPLIED; } ctxt->dictNames = 0; + ctxt->linenumbers = 1; return (options); } /** - * htmlDoRead: + * htmlCtxtParseDocument: * @ctxt: an HTML parser context - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) - * @reuse: keep the context for reuse + * @input: parser input * - * Common front-end for the htmlRead functions + * Parse an HTML document and return the resulting document tree. + * + * Available since 2.13.0. * * Returns the resulting document tree or NULL */ -static htmlDocPtr -htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding, - int options, int reuse) +htmlDocPtr +htmlCtxtParseDocument(htmlParserCtxtPtr ctxt, xmlParserInputPtr input) { htmlDocPtr ret; - htmlCtxtUseOptions(ctxt, options); - ctxt->html = 1; - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - if (ctxt->input->encoding != NULL) - xmlFree((xmlChar *) ctxt->input->encoding); - ctxt->input->encoding = xmlStrdup((xmlChar *)encoding); - } + if ((ctxt == NULL) || (input == NULL)) + return(NULL); + + /* assert(ctxt->inputNr == 0); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + if (inputPush(ctxt, input) < 0) { + xmlFreeInputStream(input); + return(NULL); } - if ((URL != NULL) && (ctxt->input != NULL) && - (ctxt->input->filename == NULL)) - ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + + ctxt->html = 1; htmlParseDocument(ctxt); - ret = ctxt->myDoc; - ctxt->myDoc = NULL; - if (!reuse) { - if ((ctxt->dictNames) && - (ret != NULL) && - (ret->dict == ctxt->dict)) - ctxt->dict = NULL; - xmlFreeParserCtxt(ctxt); + + if (ctxt->errNo != XML_ERR_NO_MEMORY) { + ret = ctxt->myDoc; + } else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); } - return (ret); + ctxt->myDoc = NULL; + + /* assert(ctxt->inputNr == 1); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + return(ret); } /** * htmlReadDoc: - * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @str: a pointer to a zero terminated string + * @url: only used for error reporting (optoinal) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an HTML document from a zero-terminated + * string. * - * Returns the resulting document tree + * See htmlCtxtReadDoc for details. + * + * Returns the resulting document tree. */ htmlDocPtr -htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) +htmlReadDoc(const xmlChar *str, const char *url, const char *encoding, + int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc; - if (cur == NULL) - return (NULL); - - xmlInitParser(); - ctxt = htmlCreateDocParserCtxt(cur, NULL); + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, url, (const char *) str, encoding, + XML_INPUT_BUF_STATIC); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); } /** * htmlReadFile: * @filename: a file or URL - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML file from the filesystem or the network. + * Convenience function to parse an HTML file from the filesystem, + * the network or a global user-defined resource loader. * - * Returns the resulting document tree + * See htmlCtxtReadFile for details. + * + * Returns the resulting document tree. */ htmlDocPtr htmlReadFile(const char *filename, const char *encoding, int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc; - xmlInitParser(); - ctxt = htmlCreateFileParserCtxt(filename, encoding); + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (htmlDoRead(ctxt, NULL, NULL, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); } /** * htmlReadMemory: * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document + * @url: only used for error reporting (optional) * @encoding: the document encoding, or NULL * @options: a combination of htmlParserOption(s) * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an HTML document from memory. + * The input buffer must not contain any terminating null bytes. + * + * See htmlCtxtReadMemory for details. * * Returns the resulting document tree */ htmlDocPtr -htmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) +htmlReadMemory(const char *buffer, int size, const char *url, + const char *encoding, int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc; - xmlInitParser(); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (size < 0) + return(NULL); + + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - htmlDefaultSAXHandlerInit(); - if (ctxt->sax != NULL) - memcpy(ctxt->sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1)); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, + XML_INPUT_BUF_STATIC); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); } /** * htmlReadFd: * @fd: an open file descriptor - * @URL: the base URL to use for the document + * @url: only used for error reporting (optional) * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @options: a combination of htmlParserOptions + * + * Convenience function to parse an HTML document from a + * file descriptor. * - * parse an HTML from a file descriptor and build a tree. * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. + * + * See htmlCtxtReadFd for details. * * Returns the resulting document tree */ htmlDocPtr -htmlReadFd(int fd, const char *URL, const char *encoding, int options) +htmlReadFd(int fd, const char *url, const char *encoding, int options) { htmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - htmlParserInputPtr stream; - - if (fd < 0) - return (NULL); + xmlParserInputPtr input; + htmlDocPtr doc; - xmlInitParser(); - input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); - if (input == NULL) - return (NULL); - input->closecallback = NULL; ctxt = htmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - htmlFreeParserCtxt(ctxt); - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + if (ctxt == NULL) + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputFd(ctxt, url, fd, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); } /** * htmlReadIO: * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @url: only used for error reporting (optional) + * @encoding: the document encoding (optional) * @options: a combination of htmlParserOption(s) * - * parse an HTML document from I/O functions and source and build a tree. + * Convenience function to parse an HTML document from I/O functions + * and context. + * + * See htmlCtxtReadIO for details. * * Returns the resulting document tree */ htmlDocPtr htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, - void *ioctx, const char *URL, const char *encoding, int options) + void *ioctx, const char *url, const char *encoding, int options) { htmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; - - if (ioread == NULL) - return (NULL); - xmlInitParser(); + xmlParserInputPtr input; + htmlDocPtr doc; - input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } ctxt = htmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - xmlFreeParserCtxt(ctxt); + if (ctxt == NULL) return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputIO(ctxt, url, ioread, ioclose, ioctx, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); } /** * htmlCtxtReadDoc: * @ctxt: an HTML parser context - * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @str: a pointer to a zero terminated string + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML in-memory document and build a tree. + * + * See htmlCtxtUseOptions for details. * * Returns the resulting document tree */ htmlDocPtr -htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar * cur, - const char *URL, const char *encoding, int options) +htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar *str, + const char *URL, const char *encoding, int options) { - if (cur == NULL) + xmlParserInputPtr input; + + if (ctxt == NULL) return (NULL); - return (htmlCtxtReadMemory(ctxt, (const char *) cur, xmlStrlen(cur), URL, - encoding, options)); + + htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, URL, (const char *) str, encoding, 0); + + return(htmlCtxtParseDocument(ctxt, input)); } /** * htmlCtxtReadFile: * @ctxt: an HTML parser context * @filename: a file or URL - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions + * + * Parse an HTML file from the filesystem, the network or a + * user-defined resource loader. * - * parse an XML file from the filesystem or the network. - * This reuses the existing @ctxt parser context + * See xmlNewInputURL and htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -7135,22 +6588,17 @@ htmlDocPtr htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options) { - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (filename == NULL) - return (NULL); if (ctxt == NULL) return (NULL); - xmlInitParser(); htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options); - stream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (stream == NULL) { - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, NULL, encoding, options, 1)); + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + return(htmlCtxtParseDocument(ctxt, input)); } /** @@ -7158,12 +6606,14 @@ htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename, * @ctxt: an HTML parser context * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optinal) + * @options: a combination of htmlParserOptions * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML in-memory document and build a tree. The input buffer must + * not contain any terminating null bytes. + * + * See htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -7171,42 +6621,34 @@ htmlDocPtr htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (ctxt == NULL) + if ((ctxt == NULL) || (size < 0)) return (NULL); - if (buffer == NULL) - return (NULL); - xmlInitParser(); htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options); - input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (input == NULL) { - return(NULL); - } - - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return(NULL); - } + input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding, + XML_INPUT_BUF_STATIC); - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + return(htmlCtxtParseDocument(ctxt, input)); } /** * htmlCtxtReadFd: * @ctxt: an HTML parser context * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optinal) + * @options: a combination of htmlParserOptions * - * parse an XML from a file descriptor and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML from a file descriptor and build a tree. + * + * See htmlCtxtUseOptions for details. + * + * NOTE that the file descriptor will not be closed when the + * context is freed or reset. * * Returns the resulting document tree */ @@ -7214,28 +6656,17 @@ htmlDocPtr htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (fd < 0) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL); htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options); + input = xmlNewInputFd(ctxt, URL, fd, encoding, 0); - input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); - if (input == NULL) - return (NULL); - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + return(htmlCtxtParseDocument(ctxt, input)); } /** @@ -7248,8 +6679,9 @@ htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd, * @encoding: the document encoding, or NULL * @options: a combination of htmlParserOption(s) * - * parse an HTML document from I/O functions and source and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML document from I/O functions and source and build a tree. + * + * See xmlNewInputIO and htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -7259,31 +6691,17 @@ htmlCtxtReadIO(htmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (ioread == NULL) - return (NULL); if (ctxt == NULL) return (NULL); - xmlInitParser(); htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options); - input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + return(htmlCtxtParseDocument(ctxt, input)); } #endif /* LIBXML_HTML_ENABLED */ diff --git a/HTMLtree.c b/HTMLtree.c index 3dd78a91eba..8fa022c11b8 100644 --- a/HTMLtree.c +++ b/HTMLtree.c @@ -19,13 +19,14 @@ #include #include #include -#include #include #include -#include #include -#include "buf.h" +#include "private/buf.h" +#include "private/error.h" +#include "private/io.h" +#include "private/save.h" /************************************************************************ * * @@ -328,27 +329,11 @@ htmlIsBooleanAttr(const xmlChar *name) } #ifdef LIBXML_OUTPUT_ENABLED -/* - * private routine exported from xmlIO.c - */ -xmlOutputBufferPtr -xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); /************************************************************************ * * * Output error handlers * * * ************************************************************************/ -/** - * htmlSaveErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ -static void -htmlSaveErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} /** * htmlSaveErr: @@ -362,6 +347,7 @@ static void htmlSaveErr(int code, xmlNodePtr node, const char *extra) { const char *msg = NULL; + int res; switch(code) { case XML_SAVE_NOT_UTF8: @@ -379,7 +365,13 @@ htmlSaveErr(int code, xmlNodePtr node, const char *extra) default: msg = "unexpected error number\n"; } - __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, node, + XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + msg, extra); + if (res < 0) + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL); } /************************************************************************ @@ -388,6 +380,27 @@ htmlSaveErr(int code, xmlNodePtr node, const char *extra) * * ************************************************************************/ +static xmlCharEncodingHandler * +htmlFindOutputEncoder(const char *encoding) { + xmlCharEncodingHandler *handler = NULL; + + if (encoding != NULL) { + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, + &handler); + if (res != XML_ERR_OK) + htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); + } else { + /* + * Fallback to HTML when the encoding is unspecified + */ + xmlOpenCharEncodingHandler("HTML", /* output */ 1, &handler); + } + + return(handler); +} + /** * htmlBufNodeDumpFormat: * @buf: the xmlBufPtr output @@ -403,21 +416,19 @@ static size_t htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int format) { size_t use; - int ret; + size_t ret; xmlOutputBufferPtr outbuf; if (cur == NULL) { - return (-1); + return ((size_t) -1); } if (buf == NULL) { - return (-1); + return ((size_t) -1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); - if (outbuf == NULL) { - htmlSaveErrMemory("allocating HTML output buffer"); - return (-1); - } - memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); + if (outbuf == NULL) + return ((size_t) -1); + memset(outbuf, 0, sizeof(xmlOutputBuffer)); outbuf->buffer = buf; outbuf->encoder = NULL; outbuf->writecallback = NULL; @@ -427,8 +438,11 @@ htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, use = xmlBufUse(buf); htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format); + if (outbuf->error) + ret = (size_t) -1; + else + ret = xmlBufUse(buf) - use; xmlFree(outbuf); - ret = xmlBufUse(buf) - use; return (ret); } @@ -456,6 +470,7 @@ htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) { if (buffer == NULL) return(-1); + xmlBufSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1); xmlBufBackToBuffer(buffer); @@ -483,35 +498,20 @@ int htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc, xmlNodePtr cur, const char *encoding, int format) { xmlOutputBufferPtr buf; - xmlCharEncodingHandlerPtr handler = NULL; + xmlCharEncodingHandlerPtr handler; int ret; xmlInitParser(); - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - /* * save the content to a temp buffer. */ + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFile(out, handler); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + } htmlNodeDumpFormatOutput(buf, doc, cur, NULL, format); @@ -553,52 +553,34 @@ htmlDocDumpMemoryFormat(xmlDocPtr cur, xmlChar**mem, int *size, int format) { if ((mem == NULL) || (size == NULL)) return; - if (cur == NULL) { - *mem = NULL; - *size = 0; + *mem = NULL; + *size = 0; + if (cur == NULL) return; - } encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - + handler = htmlFindOutputEncoder(encoding); buf = xmlAllocOutputBufferInternal(handler); if (buf == NULL) { - *mem = NULL; - *size = 0; + xmlCharEncCloseFunc(handler); return; } htmlDocContentDumpFormatOutput(buf, cur, NULL, format); xmlOutputBufferFlush(buf); - if (buf->conv != NULL) { - *size = xmlBufUse(buf->conv); - *mem = xmlStrndup(xmlBufContent(buf->conv), *size); - } else { - *size = xmlBufUse(buf->buffer); - *mem = xmlStrndup(xmlBufContent(buf->buffer), *size); + + if (!buf->error) { + if (buf->conv != NULL) { + *size = xmlBufUse(buf->conv); + *mem = xmlStrndup(xmlBufContent(buf->conv), *size); + } else { + *size = xmlBufUse(buf->buffer); + *mem = xmlStrndup(xmlBufContent(buf->buffer), *size); + } } - (void)xmlOutputBufferClose(buf); + + xmlOutputBufferClose(buf); } /** @@ -622,8 +604,6 @@ htmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { * * ************************************************************************/ -void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); - /** * htmlDtdDumpOutput: * @buf: the HTML buffer output @@ -647,15 +627,15 @@ htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->ExternalID != NULL) { xmlOutputBufferWriteString(buf, " PUBLIC "); - xmlBufWriteQuotedString(buf->buffer, cur->ExternalID); + xmlOutputBufferWriteQuotedString(buf, cur->ExternalID); if (cur->SystemID != NULL) { xmlOutputBufferWriteString(buf, " "); - xmlBufWriteQuotedString(buf->buffer, cur->SystemID); + xmlOutputBufferWriteQuotedString(buf, cur->SystemID); } } else if (cur->SystemID != NULL && xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) { xmlOutputBufferWriteString(buf, " SYSTEM "); - xmlBufWriteQuotedString(buf->buffer, cur->SystemID); + xmlOutputBufferWriteQuotedString(buf, cur->SystemID); } xmlOutputBufferWriteString(buf, ">\n"); } @@ -705,22 +685,27 @@ htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) { while (IS_BLANK_CH(*tmp)) tmp++; /* - * the < and > have already been escaped at the entity level - * And doing so here breaks server side includes + * Angle brackets are technically illegal in URIs, but they're + * used in server side includes, for example. Curly brackets + * are illegal as well and often used in templates. + * Don't escape non-whitespace, printable ASCII chars for + * improved interoperability. Only escape space, control + * and non-ASCII chars. */ - escaped = xmlURIEscapeStr(tmp, BAD_CAST"@/:=?;#%&,+<>"); + escaped = xmlURIEscapeStr(tmp, + BAD_CAST "\"#$%&+,/:;<=>?@[\\]^`{|}"); if (escaped != NULL) { - xmlBufWriteQuotedString(buf->buffer, escaped); + xmlOutputBufferWriteQuotedString(buf, escaped); xmlFree(escaped); } else { - xmlBufWriteQuotedString(buf->buffer, value); + buf->error = XML_ERR_NO_MEMORY; } } else { - xmlBufWriteQuotedString(buf->buffer, value); + xmlOutputBufferWriteQuotedString(buf, value); } xmlFree(value); } else { - xmlOutputBufferWriteString(buf, "=\"\""); + buf->error = XML_ERR_NO_MEMORY; } } } @@ -861,10 +846,12 @@ htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlChar *buffer; buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); + if (buffer == NULL) { + buf->error = XML_ERR_NO_MEMORY; + return; } + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); } else { xmlOutputBufferWriteString(buf, (const char *)cur->content); } @@ -1040,28 +1027,12 @@ htmlDocDump(FILE *f, xmlDocPtr cur) { } encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFile(f, handler); - if (buf == NULL) return(-1); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(-1); + } htmlDocContentDumpOutput(buf, cur, NULL); ret = xmlOutputBufferClose(buf); @@ -1090,31 +1061,12 @@ htmlSaveFile(const char *filename, xmlDocPtr cur) { xmlInitParser(); encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - - /* - * save the content to a temp buffer. - */ + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + } htmlDocContentDumpOutput(buf, cur, NULL); @@ -1145,33 +1097,20 @@ htmlSaveFileFormat(const char *filename, xmlDocPtr cur, xmlInitParser(); - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - htmlSetMetaEncoding(cur, (const xmlChar *) encoding); - } else { + handler = htmlFindOutputEncoder(encoding); + if (handler != NULL) + htmlSetMetaEncoding(cur, (const xmlChar *) handler->name); + else htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8"); - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - /* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFilename(filename, handler, 0); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + } htmlDocContentDumpFormatOutput(buf, cur, encoding, format); diff --git a/README.md b/README.md index ad423e686f9..58c9433f9aa 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,17 @@ libxml2 is an XML toolkit implemented in C, originally developed for the GNOME Project. -Full documentation is available at -. +Official releases can be downloaded from + + +The git repository is hosted on GNOME's GitLab server: + Bugs should be reported at -. + -A mailing list xml@gnome.org is available. You can subscribe at -. The list archive is at -. +Documentation is available at + ## License @@ -19,31 +21,64 @@ This code is released under the MIT License, see the Copyright file. ## Build instructions -libxml2 can be built with GNU Autotools, CMake, or several other build -systems in platform-specific subdirectories. +libxml2 can be built with GNU Autotools, CMake, meson or several other +build systems in platform-specific subdirectories. ### Autotools (for POSIX systems like Linux, BSD, macOS) If you build from a Git tree, you have to install Autotools and start by generating the configuration files with: - ./autogen.sh + ./autogen.sh [configuration options] If you build from a source tarball, extract the archive with: tar xf libxml2-xxx.tar.gz cd libxml2-xxx -To see a list of build options: - - ./configure --help +Then you can configure and build the library: -Also see the INSTALL file for additional instructions. Then you can -configure and build the library: - - ./configure [possible options] + ./configure [configuration options] make +The following options disable or enable code modules and relevant symbols: + + --with-c14n Canonical XML 1.0 support (on) + --with-catalog XML Catalogs support (on) + --with-debug debugging module and shell (on) + --with-history history support for shell (off) + --with-readline[=DIR] use readline in DIR (for shell history) + --with-html HTML parser (on) + --with-http HTTP support (off) + --with-iconv[=DIR] iconv support (on) + --with-icu ICU support (off) + --with-iso8859x ISO-8859-X support if no iconv (on) + --with-lzma[=DIR] use liblzma in DIR (off) + --with-modules dynamic modules support (on) + --with-output serialization support (on) + --with-pattern xmlPattern selection interface (on) + --with-push push parser interfaces (on) + --with-python Python bindings (on) + --with-reader xmlReader parsing interface (on) + --with-regexps regular expressions support (on) + --with-sax1 older SAX1 interface (on) + --with-schemas XML Schemas 1.0 and RELAX NG support (on) + --with-schematron Schematron support (on) + --with-threads multithreading support (on) + --with-thread-alloc per-thread malloc hooks (off) + --with-tree DOM like tree manipulation APIs (on) + --with-valid DTD validation support (on) + --with-writer xmlWriter serialization interface (on) + --with-xinclude XInclude 1.0 support (on) + --with-xpath XPath 1.0 support (on) + --with-xptr XPointer support (on) + --with-zlib[=DIR] use libz in DIR (off) + +Other options: + + --with-minimum build a minimally sized library (off) + --with-legacy maximum ABI compatibility (off) + Note that by default, no optimization options are used. You have to enable them manually, for example with: @@ -53,7 +88,7 @@ Now you can run the test suite with: make check -Please report test failures to the mailing list or bug tracker. +Please report test failures to the bug tracker. Then you can install the library: @@ -84,33 +119,46 @@ Common CMake options include: You can also open the libxml source directory with its CMakeLists.txt directly in various IDEs such as CLion, QtCreator, or Visual Studio. +### Meson + +Libxml can also be built with meson. Without option, simply call + +meson setup builddir +ninja -C builddir + +To add options, see the meson_options.txt file. For example: + +meson setup -Dprefix=$prefix -Dftp=true -Dhistory=true -Dicu=true -Dhttp=true builddir + +To install libxml: + +ninja -C builddir install + +To launch tests: + +meson test -C builddir + ## Dependencies Libxml does not require any other libraries. A platform with somewhat recent POSIX support should be sufficient (please report any violation to this rule you may find). -However, if found at configuration time, libxml will detect and use -the following libraries: +The iconv function is required for conversion of character encodings. +This function is part of POSIX.1-2001. If your platform doesn't provide +iconv, you need an external libiconv library, for example +[GNU libiconv](https://www.gnu.org/software/libiconv/). Alternatively, +you can use [ICU](https://icu.unicode.org/). -- [libz](https://zlib.net/), a highly portable and widely available - compression library. -- [liblzma](https://tukaani.org/xz/), another compression library. -- [libiconv](https://www.gnu.org/software/libiconv/), a character encoding - conversion library. The iconv function is part of POSIX.1-2001, so - libiconv isn't required on modern UNIX-like systems like Linux, BSD or - macOS. -- [ICU](https://icu.unicode.org/), a Unicode library. Mainly useful as an - alternative to iconv on Windows. Unnecessary on most other systems. +If enabled, libxml uses [libz](https://zlib.net/) or +[liblzma](https://tukaani.org/xz/) to support reading compressed files. +Use of this feature is discouraged. ## Contributing The current version of the code can be found in GNOME's GitLab at at . The best way to get involved -is by creating issues and merge requests on GitLab. Alternatively, you can -start discussions and send patches to the mailing list. If you want to -work with patches, please format them with git-format-patch and use plain -text attachments. +is by creating issues and merge requests on GitLab. All code must conform to C89 and pass the GitLab CI tests. Add regression tests if possible. diff --git a/SAX.c b/SAX.c index d8e972b84c2..7f2f297406c 100644 --- a/SAX.c +++ b/SAX.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #ifdef LIBXML_LEGACY_ENABLED diff --git a/SAX2.c b/SAX2.c index ec89046b1d6..32db6b4c1a4 100644 --- a/SAX2.c +++ b/SAX2.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -22,66 +23,24 @@ #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 */ +#include "private/error.h" +#include "private/parser.h" +#include "private/tree.h" -/* #define DEBUG_SAX2 */ -/* #define DEBUG_SAX2_TREE */ - -/** - * TODO: - * - * macro to flag unimplemented blocks - * XML_CATALOG_PREFER user env to select between system/public preferred - * 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_MAX_URI_LENGTH 2000 /* * xmlSAX2ErrMemory: * @ctxt: an XML validation parser context * @msg: a string to accompany the error message */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { - xmlStructuredErrorFunc schannel = NULL; - const char *str1 = "out of memory\n"; - - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - __xmlRaiseError(schannel, - ctxt->vctxt.error, ctxt->vctxt.userData, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } else { - __xmlRaiseError(schannel, - NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - } +static void +xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt) { + xmlCtxtErrMemory(ctxt); } /** @@ -96,32 +55,12 @@ xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { */ static void LIBXML_ATTR_FORMAT(3,0) xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error, - const char *msg, const char *str1, const char *str2) + const char *msg, const xmlChar *str1, const xmlChar *str2) { - xmlStructuredErrorFunc schannel = NULL; - - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = error; - if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - __xmlRaiseError(schannel, - ctxt->vctxt.error, ctxt->vctxt.userData, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); + if (ctxt != NULL) ctxt->valid = 0; - } else { - __xmlRaiseError(schannel, - NULL, NULL, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } } /** @@ -138,21 +77,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - ctxt->valid = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -169,15 +95,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, NULL, - NULL, 0, 0, msg, str1); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, + str1, NULL, NULL, 0, msg, str1); } /** @@ -193,15 +112,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -332,11 +244,6 @@ xmlSAX2InternalSubset(void *ctx, const xmlChar *name, 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; @@ -351,7 +258,7 @@ xmlSAX2InternalSubset(void *ctx, const xmlChar *name, ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID); if (ctxt->myDoc->intSubset == NULL) - xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset"); + xmlSAX2ErrMemory(ctxt); } /** @@ -369,13 +276,9 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, { 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)) && + if ((SystemID != NULL) && + ((ctxt->options & XML_PARSE_NO_XXE) == 0) && + (((ctxt->validate) || (ctxt->loadsubset)) && (ctxt->wellFormed && ctxt->myDoc))) { /* * Try to fetch and parse the external subset. @@ -385,9 +288,9 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, int oldinputMax; xmlParserInputPtr *oldinputTab; xmlParserInputPtr input = NULL; - xmlCharEncoding enc; - int oldcharset; const xmlChar *oldencoding; + unsigned long consumed; + size_t buffered; /* * Ask the Entity resolver to load the damn thing @@ -399,7 +302,11 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, return; } - xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID); + if (xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID) == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFreeInputStream(input); + return; + } /* * make sure we won't destroy the main document context @@ -408,19 +315,18 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, oldinputNr = ctxt->inputNr; oldinputMax = ctxt->inputMax; oldinputTab = ctxt->inputTab; - oldcharset = ctxt->charset; oldencoding = ctxt->encoding; ctxt->encoding = NULL; ctxt->inputTab = (xmlParserInputPtr *) xmlMalloc(5 * sizeof(xmlParserInputPtr)); if (ctxt->inputTab == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset"); + xmlSAX2ErrMemory(ctxt); + xmlFreeInputStream(input); ctxt->input = oldinput; ctxt->inputNr = oldinputNr; ctxt->inputMax = oldinputMax; ctxt->inputTab = oldinputTab; - ctxt->charset = oldcharset; ctxt->encoding = oldencoding; return; } @@ -429,14 +335,6 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, 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; @@ -456,6 +354,18 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, while (ctxt->inputNr > 1) xmlPopInput(ctxt); + + consumed = ctxt->input->consumed; + buffered = ctxt->input->cur - ctxt->input->base; + if (buffered > ULONG_MAX - consumed) + consumed = ULONG_MAX; + else + consumed += buffered; + if (consumed > ULONG_MAX - ctxt->sizeentities) + ctxt->sizeentities = ULONG_MAX; + else + ctxt->sizeentities += consumed; + xmlFreeInputStream(ctxt->input); xmlFree(ctxt->inputTab); @@ -466,7 +376,6 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, ctxt->inputNr = oldinputNr; ctxt->inputMax = oldinputMax; ctxt->inputTab = oldinputTab; - ctxt->charset = oldcharset; if ((ctxt->encoding != NULL) && ((ctxt->dict == NULL) || (!xmlDictOwns(ctxt->dict, ctxt->encoding)))) @@ -494,27 +403,44 @@ xmlParserInputPtr xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr ret; + xmlParserInputPtr ret = NULL; xmlChar *URI; - const char *base = NULL; + const xmlChar *base = NULL; + int res; if (ctx == NULL) return(NULL); if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory; + base = BAD_CAST ctxt->input->filename; - URI = xmlBuildURI(systemId, (const xmlChar *) base); + /* + * We don't really need the 'directory' struct member, but some + * users set it manually to a base URI for memory streams. + */ + if (base == NULL) + base = BAD_CAST ctxt->directory; -#ifdef DEBUG_SAX - xmlGenericError(xmlGenericErrorContext, - "SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId); -#endif + if ((xmlStrlen(systemId) > XML_MAX_URI_LENGTH) || + (xmlStrlen(base) > XML_MAX_URI_LENGTH)) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + return(NULL); + } + res = xmlBuildURISafe(systemId, base, &URI); + if (URI == NULL) { + if (res < 0) + xmlSAX2ErrMemory(ctxt); + else + xmlWarnMsg(ctxt, XML_ERR_INVALID_URI, + "Can't resolve URI: %s\n", systemId); + return(NULL); + } + if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + } else { + ret = xmlLoadExternalEntity((const char *) URI, + (const char *) publicId, ctxt); + } - ret = xmlLoadExternalEntity((const char *) URI, - (const char *) publicId, ctxt); - if (URI != NULL) - xmlFree(URI); + xmlFree(URI); return(ret); } @@ -534,10 +460,6 @@ xmlSAX2GetEntity(void *ctx, const xmlChar *name) 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); @@ -584,10 +506,6 @@ xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name) 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); @@ -611,55 +529,80 @@ xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type, { xmlEntityPtr ent; xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + int extSubset; + int res; - 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); + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) + return; + + extSubset = ctxt->inSubset == 2; + res = xmlAddEntity(ctxt->myDoc, extSubset, name, type, publicId, systemId, + content, &ent); + switch (res) { + case XML_ERR_OK: + break; + case XML_ERR_NO_MEMORY: + xmlSAX2ErrMemory(ctxt); + return; + case XML_WAR_ENTITY_REDEFINED: + if (ctxt->pedantic) { + if (extSubset) + xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the" + " external subset\n", name); + else + xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the" + " internal subset\n", name); + } + return; + case XML_ERR_REDECL_PREDEF_ENTITY: + /* + * Technically an error but it's a common mistake to get double + * escaping according to "4.6 Predefined Entities" wrong. + */ + xmlWarnMsg(ctxt, res, "Invalid redeclaration of predefined" + " entity '%s'", name); + return; + default: + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "Unexpected error code from xmlAddEntity\n", + NULL, NULL); + return; + } + + if ((ent->URI == NULL) && (systemId != NULL)) { + xmlChar *URI; + const char *base = NULL; + int i; + + for (i = ctxt->inputNr - 1; i >= 0; i--) { + if (ctxt->inputTab[i]->filename != NULL) { + base = ctxt->inputTab[i]->filename; + break; + } + } + + /* + * We don't really need the 'directory' struct member, but some + * users set it manually to a base URI for memory streams. + */ + if (base == NULL) + base = ctxt->directory; + + res = xmlBuildURISafe(systemId, (const xmlChar *) base, &URI); + + if (URI == NULL) { + if (res < 0) { + xmlSAX2ErrMemory(ctxt); + } else { + xmlWarnMsg(ctxt, XML_ERR_INVALID_URI, + "Can't resolve URI: %s\n", systemId); + } + } else if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + xmlFree(URI); + } else { + ent->URI = URI; + } } } @@ -690,11 +633,6 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, 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)) { /* @@ -707,6 +645,8 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, } /* TODO: optimize name/prefix allocation */ name = xmlSplitQName(ctxt, fullname, &prefix); + if (name == NULL) + xmlSAX2ErrMemory(ctxt); ctxt->vctxt.valid = 1; if (ctxt->inSubset == 1) attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem, @@ -721,6 +661,7 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n", name, NULL); xmlFree(name); + xmlFree(prefix); xmlFreeEnumeration(tree); return; } @@ -760,11 +701,6 @@ xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type, 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); @@ -809,11 +745,6 @@ xmlSAX2NotationDecl(void *ctx, const xmlChar *name, 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", @@ -855,59 +786,8 @@ xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName) { - xmlEntityPtr ent; - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - if (ctx == NULL) return; -#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); - } + xmlSAX2EntityDecl(ctx, name, XML_EXTERNAL_GENERAL_UNPARSED_ENTITY, + publicId, systemId, (xmlChar *) notationName); } /** @@ -921,11 +801,6 @@ xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name, void xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) { - /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ -#ifdef DEBUG_SAX - xmlGenericError(xmlGenericErrorContext, - "SAX.xmlSAX2SetDocumentLocator()\n"); -#endif } /** @@ -942,42 +817,28 @@ xmlSAX2StartDocument(void *ctx) if (ctx == NULL) return; -#ifdef DEBUG_SAX - xmlGenericError(xmlGenericErrorContext, - "SAX.xmlSAX2StartDocument()\n"); -#endif - if (ctxt->html) { #ifdef LIBXML_HTML_ENABLED + if (ctxt->html) { if (ctxt->myDoc == NULL) ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL); if (ctxt->myDoc == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + xmlSAX2ErrMemory(ctxt); return; } ctxt->myDoc->properties = XML_DOC_HTML; ctxt->myDoc->parseFlags = ctxt->options; -#else - xmlGenericError(xmlGenericErrorContext, - "libxml2 built without HTML support\n"); - ctxt->errNo = XML_ERR_INTERNAL_ERROR; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - return; + } else #endif - } else { + { doc = ctxt->myDoc = xmlNewDoc(ctxt->version); if (doc != NULL) { doc->properties = 0; 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"); + xmlSAX2ErrMemory(ctxt); return; } if ((ctxt->dictNames) && (doc != NULL)) { @@ -989,7 +850,7 @@ xmlSAX2StartDocument(void *ctx) (ctxt->input != NULL) && (ctxt->input->filename != NULL)) { ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename); if (ctxt->myDoc->URL == NULL) - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + xmlSAX2ErrMemory(ctxt); } } @@ -1003,10 +864,8 @@ void xmlSAX2EndDocument(void *ctx) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; -#ifdef DEBUG_SAX - xmlGenericError(xmlGenericErrorContext, - "SAX.xmlSAX2EndDocument()\n"); -#endif + xmlDocPtr doc; + if (ctx == NULL) return; #ifdef LIBXML_VALID_ENABLED if (ctxt->validate && ctxt->wellFormed && @@ -1014,23 +873,51 @@ xmlSAX2EndDocument(void *ctx) 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; + doc = ctxt->myDoc; + if ((doc != NULL) && (doc->encoding == NULL)) { + const xmlChar *encoding = xmlGetActualEncoding(ctxt); + + if (encoding != NULL) { + doc->encoding = xmlStrdup(encoding); + if (doc->encoding == NULL) + xmlSAX2ErrMemory(ctxt); + } + } +} + +static void +xmlSAX2AppendChild(xmlParserCtxtPtr ctxt, xmlNodePtr node) { + xmlNodePtr parent; + xmlNodePtr last; + + if (ctxt->inSubset == 1) { + parent = (xmlNodePtr) ctxt->myDoc->intSubset; + } else if (ctxt->inSubset == 2) { + parent = (xmlNodePtr) ctxt->myDoc->extSubset; + } else { + parent = ctxt->node; + if (parent == NULL) + parent = (xmlNodePtr) ctxt->myDoc; } - 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); + + last = parent->last; + if (last == NULL) { + parent->children = node; + } else { + last->next = node; + node->prev = last; } - if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) && - (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) { - ctxt->myDoc->charset = ctxt->charset; + + parent->last = node; + node->parent = parent; + + if ((node->type != XML_TEXT_NODE) && + (ctxt->linenumbers) && + (ctxt->input != NULL)) { + if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) + node->line = ctxt->input->line; + else + node->line = USHRT_MAX; } } @@ -1049,15 +936,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlNsErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -1110,7 +990,7 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, } } if (name == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); if (ns != NULL) xmlFree(ns); return; @@ -1120,6 +1000,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((ctxt->html) && (value == NULL) && (htmlIsBooleanAttr(fullname))) { nval = xmlStrdup(fullname); + if (nval == NULL) + xmlSAX2ErrMemory(ctxt); value = (const xmlChar *) nval; } else #endif @@ -1157,12 +1039,10 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, (void) nsret; if (!ctxt->replaceEntities) { - ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0); if (val == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); if (name != NULL) xmlFree(name); if (nval != NULL) @@ -1176,16 +1056,16 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if (val[0] != 0) { xmlURIPtr uri; - uri = xmlParseURI((const char *)val); + if (xmlParseURISafe((const char *)val, &uri) < 0) + xmlSAX2ErrMemory(ctxt); if (uri == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "xmlns: %s not a valid URI\n", val); + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI, + "xmlns:%s: %s not a valid URI\n", name, value); } else { if (uri->scheme == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "xmlns: URI %s is not absolute\n", val); + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI_RELATIVE, + "xmlns:%s: URI %s is not absolute\n", + name, value); } xmlFreeURI(uri); } @@ -1193,16 +1073,19 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, /* a default namespace definition */ nsret = xmlNewNs(ctxt->node, val, NULL); - + if (nsret == NULL) { + xmlSAX2ErrMemory(ctxt); + } #ifdef LIBXML_VALID_ENABLED /* * Validate also for namespace decls, they are attributes from * an XML-1.0 perspective */ - if (nsret != NULL && ctxt->validate && ctxt->wellFormed && - ctxt->myDoc && ctxt->myDoc->intSubset) + else if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, ctxt->node, prefix, nsret, val); + } #endif /* LIBXML_VALID_ENABLED */ if (name != NULL) xmlFree(name); @@ -1222,12 +1105,10 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, (void) nsret; if (!ctxt->replaceEntities) { - ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0); if (val == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); xmlFree(ns); if (name != NULL) xmlFree(name); @@ -1246,7 +1127,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((ctxt->pedantic != 0) && (val[0] != 0)) { xmlURIPtr uri; - uri = xmlParseURI((const char *)val); + if (xmlParseURISafe((const char *)val, &uri) < 0) + xmlSAX2ErrMemory(ctxt); if (uri == NULL) { xmlNsWarnMsg(ctxt, XML_WAR_NS_URI, "xmlns:%s: %s not a valid URI\n", name, value); @@ -1262,15 +1144,20 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, /* a standard namespace definition */ nsret = xmlNewNs(ctxt->node, val, name); xmlFree(ns); + + if (nsret == NULL) { + xmlSAX2ErrMemory(ctxt); + } #ifdef LIBXML_VALID_ENABLED /* * Validate also for namespace decls, they are attributes from * an XML-1.0 perspective */ - if (nsret != NULL && ctxt->validate && ctxt->wellFormed && - ctxt->myDoc && ctxt->myDoc->intSubset) + else if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, ctxt->node, prefix, nsret, value); + } #endif /* LIBXML_VALID_ENABLED */ if (name != NULL) xmlFree(name); @@ -1282,7 +1169,11 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, } if (ns != NULL) { - namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns); + int res; + + res = xmlSearchNsSafe(ctxt->node, ns, &namespace); + if (res < 0) + xmlSAX2ErrMemory(ctxt); if (namespace == NULL) { xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, @@ -1297,11 +1188,11 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((xmlStrEqual(name, prop->name)) && ((namespace == prop->ns) || (xmlStrEqual(namespace->href, prop->ns->href)))) { - xmlNsErrMsg(ctxt, XML_ERR_ATTRIBUTE_REDEFINED, - "Attribute %s in %s redefined\n", - name, namespace->href); - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) ctxt->disableSAX = 1; + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, + XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, + name, NULL, NULL, 0, + "Attribute %s in %s redefined\n", + name, namespace->href); if (name != NULL) xmlFree(name); goto error; @@ -1316,25 +1207,22 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, /* !!!!!! */ ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + goto error; + } - 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; - } + if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { + if (xmlNodeParseContent((xmlNodePtr) ret, value, INT_MAX) < 0) + xmlSAX2ErrMemory(ctxt); + } else if (value != NULL) { + ret->children = xmlNewDocText(ctxt->myDoc, value); + if (ret->children == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { + ret->last = ret->children; + ret->children->parent = (xmlNodePtr) ret; + } } #ifdef LIBXML_VALID_ENABLED @@ -1348,10 +1236,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if (!ctxt->replaceEntities) { xmlChar *val; - ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0); if (val == NULL) ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, @@ -1364,8 +1250,9 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, * It need to be done twice ... it's an extra burden related * to the ability to keep xmlSAX2References in attributes */ - nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc, - ctxt->node, fullname, val); + nvalnorm = xmlValidCtxtNormalizeAttributeValue( + &ctxt->vctxt, ctxt->myDoc, + ctxt->node, fullname, val); if (nvalnorm != NULL) { xmlFree(val); val = nvalnorm; @@ -1382,8 +1269,7 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, } else #endif /* LIBXML_VALID_ENABLED */ if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && - (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || - ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) && + (ctxt->input->entity == NULL) && /* Don't create IDs containing entity references */ (ret->children != NULL) && (ret->children->type == XML_TEXT_NODE) && @@ -1401,14 +1287,20 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, */ if (xmlValidateNCName(content, 1) != 0) { xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, - "xml:id : attribute value %s is not an NCName\n", - (const char *) content, NULL); + "xml:id : attribute value %s is not an NCName\n", + content, NULL); } xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) - xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) - xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } else { + int res = xmlIsID(ctxt->myDoc, ctxt->node, ret); + + if (res < 0) + xmlCtxtErrMemory(ctxt); + else if (res > 0) + xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } } error: @@ -1460,13 +1352,15 @@ process_external_subset: if (attr->prefix != NULL) { fulln = xmlStrdup(attr->prefix); - fulln = xmlStrcat(fulln, BAD_CAST ":"); - fulln = xmlStrcat(fulln, attr->name); + if (fulln != NULL) + fulln = xmlStrcat(fulln, BAD_CAST ":"); + if (fulln != NULL) + fulln = xmlStrcat(fulln, attr->name); } else { fulln = xmlStrdup(attr->name); } if (fulln == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); break; } @@ -1488,8 +1382,8 @@ process_external_subset: if (att == NULL) { xmlErrValid(ctxt, XML_DTD_STANDALONE_DEFAULTED, "standalone: attribute %s on %s defaulted from external subset\n", - (const char *)fulln, - (const char *)attr->elem); + fulln, + attr->elem); } xmlFree(fulln); } @@ -1532,7 +1426,7 @@ process_external_subset: fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50); if (fulln == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); return; } @@ -1593,11 +1487,6 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) 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: @@ -1613,12 +1502,19 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) ctxt->validate = 0; } - - /* - * Split the full name into a namespace prefix and the tag name - */ - name = xmlSplitQName(ctxt, fullname, &prefix); - + if (ctxt->html) { + prefix = NULL; + name = xmlStrdup(fullname); + } else { + /* + * Split the full name into a namespace prefix and the tag name + */ + name = xmlSplitQName(ctxt, fullname, &prefix); + if (name == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + } /* * Note : the namespace resolution is deferred until the end of the @@ -1627,35 +1523,25 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) */ ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL); if (ret == NULL) { - if (prefix != NULL) - xmlFree(prefix); - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlFree(prefix); + xmlSAX2ErrMemory(ctxt); return; } - 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 < USHRT_MAX) - ret->line = (unsigned short) ctxt->input->line; - else - ret->line = USHRT_MAX; - } - } + + /* Initialize parent before pushing node */ + parent = ctxt->node; + if (parent == NULL) + parent = (xmlNodePtr) ctxt->myDoc; + + /* + * Link the child element + */ + xmlSAX2AppendChild(ctxt, ret); /* * We are parsing a new node. */ -#ifdef DEBUG_SAX_TREE - xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name); -#endif if (nodePush(ctxt, ret) < 0) { xmlUnlinkNode(ret); xmlFreeNode(ret); @@ -1664,27 +1550,9 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) return; } - /* - * 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); - } - } - if (!ctxt->html) { + int res; + /* * Insert all the defaulted attributes from the DTD especially * namespaces @@ -1715,14 +1583,21 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) * Search the namespace, note that since the attributes have been * processed, the local namespaces are available. */ - ns = xmlSearchNs(ctxt->myDoc, ret, prefix); - if ((ns == NULL) && (parent != NULL)) - ns = xmlSearchNs(ctxt->myDoc, parent, prefix); + res = xmlSearchNsSafe(ret, prefix, &ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); + if ((ns == NULL) && (parent != NULL)) { + res = xmlSearchNsSafe(parent, prefix, &ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); + } if ((prefix != NULL) && (ns == NULL)) { - ns = xmlNewNs(ret, NULL, prefix); xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s is not defined\n", prefix, NULL); + ns = xmlNewNs(ret, NULL, prefix); + if (ns == NULL) + xmlSAX2ErrMemory(ctxt); } /* @@ -1797,40 +1672,22 @@ void xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - 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) { - ctxt->nodeInfo->end_pos = ctxt->input->cur - ctxt->input->base; - ctxt->nodeInfo->end_line = ctxt->input->line; - ctxt->nodeInfo->node = cur; - xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo); - } 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); + ctxt->node); #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_ENABLED || LIBXML_LEGACY_ENABLED */ @@ -1861,7 +1718,7 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); } if (ret == NULL) { - xmlErrMemory(ctxt, "xmlSAX2Characters"); + xmlCtxtErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlNode)); @@ -1882,6 +1739,11 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { } else if ((len <= 3) && ((cur == '"') || (cur == '\'') || ((cur == '<') && (str[len + 1] != '!')))) { intern = xmlDictLookup(ctxt->dict, str, len); + if (intern == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFree(ret); + return(NULL); + } } else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') && (str[len + 1] != '!')) { int i; @@ -1890,6 +1752,11 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { if (!IS_BLANK_CH(str[i])) goto skip; } intern = xmlDictLookup(ctxt->dict, str, len); + if (intern == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFree(ret); + return(NULL); + } } } skip: @@ -1899,25 +1766,13 @@ skip: if (intern == NULL) { ret->content = xmlStrndup(str, len); if (ret->content == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode"); + xmlSAX2ErrMemory(ctxt); xmlFree(ret); return(NULL); } } else ret->content = (xmlChar *) intern; - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if (ctxt->input->line < USHRT_MAX) - ret->line = (unsigned short) ctxt->input->line; - else { - ret->line = USHRT_MAX; - if (ctxt->options & XML_PARSE_BIG_LINES) - ret->psvi = (void *) (ptrdiff_t) ctxt->input->line; - } - } - } - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(ret); return(ret); @@ -1938,7 +1793,6 @@ static xmlChar * xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, const xmlChar *end) { const xmlChar *in; - xmlChar *ret; in = str; while (in < end) @@ -1946,11 +1800,12 @@ xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, goto decode; return(NULL); decode: - ctxt->depth++; - ret = xmlStringLenDecodeEntities(ctxt, str, end - str, - XML_SUBSTITUTE_REF, 0,0,0); - ctxt->depth--; - return(ret); + /* + * If the value contains '&', we can be sure it was allocated and is + * zero-terminated. + */ + /* TODO: normalize if needed */ + return(xmlExpandEntitiesInAttValue(ctxt, str, /* normalize */ 0)); } #endif /* LIBXML_VALID_ENABLED */ @@ -1967,8 +1822,10 @@ decode: * The default handling is to convert the attribute into an * DOM subtree and past it in a new xmlAttr element added to * the element. + * + * Returns the new attribute or NULL in case of error. */ -static void +static xmlAttrPtr xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, const xmlChar * localname, const xmlChar * prefix, @@ -1982,8 +1839,16 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, /* * Note: if prefix == NULL, the attribute is not in the default namespace */ - if (prefix != NULL) - namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix); + if (prefix != NULL) { + namespace = xmlParserNsLookupSax(ctxt, prefix); + if ((namespace == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { + int res; + + res = xmlSearchNsSafe(ctxt->node, prefix, &namespace); + if (res < 0) + xmlSAX2ErrMemory(ctxt); + } + } /* * allocate the node @@ -1992,43 +1857,41 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, ret = ctxt->freeAttrs; ctxt->freeAttrs = ret->next; ctxt->freeAttrsNr--; - memset(ret, 0, sizeof(xmlAttr)); - ret->type = XML_ATTRIBUTE_NODE; + } else { + ret = xmlMalloc(sizeof(*ret)); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return(NULL); + } + } - ret->parent = ctxt->node; - ret->doc = ctxt->myDoc; - ret->ns = namespace; + memset(ret, 0, sizeof(xmlAttr)); + ret->type = XML_ATTRIBUTE_NODE; - if (ctxt->dictNames) - ret->name = localname; - else - ret->name = xmlStrdup(localname); + /* + * xmlParseBalancedChunkMemoryRecover had a bug that could result in + * a mismatch between ctxt->node->doc and ctxt->myDoc. We use + * ctxt->node->doc here, but we should somehow make sure that the + * document pointers match. + */ - /* link at the end to preserve order, TODO speed up with a last */ - if (ctxt->node->properties == NULL) { - ctxt->node->properties = ret; - } else { - xmlAttrPtr prev = ctxt->node->properties; + /* assert(ctxt->node->doc == ctxt->myDoc); */ - while (prev->next != NULL) prev = prev->next; - prev->next = ret; - ret->prev = prev; - } + ret->parent = ctxt->node; + ret->doc = ctxt->node->doc; + ret->ns = namespace; - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue((xmlNodePtr)ret); + if (ctxt->dictNames) { + ret->name = localname; } 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; - } + ret->name = xmlStrdup(localname); + if (ret->name == NULL) + xmlSAX2ErrMemory(ctxt); } + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)ret); + if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { xmlNodePtr tmp; @@ -2045,17 +1908,10 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, tmp->doc = ret->doc; tmp->parent = (xmlNodePtr) ret; } - } else { - ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value, - valueend - value); - tmp = ret->children; - while (tmp != NULL) { - tmp->doc = ret->doc; - tmp->parent = (xmlNodePtr) ret; - if (tmp->next == NULL) - ret->last = tmp; - tmp = tmp->next; - } + } else if (valueend > value) { + if (xmlNodeParseContent((xmlNodePtr) ret, value, + valueend - value) < 0) + xmlSAX2ErrMemory(ctxt); } } else if (value != NULL) { xmlNodePtr tmp; @@ -2089,6 +1945,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, * entry points in the full validation code */ dup = xmlStrndup(value, valueend - value); + if (dup == NULL) + xmlSAX2ErrMemory(ctxt); ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc, ctxt->node, ret, dup); @@ -2107,7 +1965,9 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, xmlChar *fullname; fullname = xmlBuildQName(localname, prefix, fn, 50); - if (fullname != NULL) { + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { ctxt->vctxt.valid = 1; nvalnorm = xmlValidCtxtNormalizeAttributeValue( &ctxt->vctxt, ctxt->myDoc, @@ -2133,6 +1993,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, * the attribute as passed is already normalized */ dup = xmlStrndup(value, valueend - value); + if (dup == NULL) + xmlSAX2ErrMemory(ctxt); ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc, ctxt->node, ret, dup); @@ -2140,8 +2002,7 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, } else #endif /* LIBXML_VALID_ENABLED */ if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && - (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || - ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) && + (ctxt->input->entity == NULL) && /* Don't create IDs containing entity references */ (ret->children != NULL) && (ret->children->type == XML_TEXT_NODE) && @@ -2159,24 +2020,27 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, * * Open issue: normalization of the value. */ -#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED) -#ifdef LIBXML_VALID_ENABLED if (xmlValidateNCName(content, 1) != 0) { xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, - "xml:id : attribute value %s is not an NCName\n", - (const char *) content, NULL); + "xml:id : attribute value %s is not an NCName\n", + content, NULL); } -#endif -#endif xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) { - xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) { - xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } else { + int res = xmlIsID(ctxt->myDoc, ctxt->node, ret); + + if (res < 0) + xmlCtxtErrMemory(ctxt); + else if (res > 0) + xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); } } if (dup != NULL) xmlFree(dup); + + return(ret); } /** @@ -2209,14 +2073,12 @@ xmlSAX2StartElementNs(void *ctx, { 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: */ @@ -2239,10 +2101,17 @@ xmlSAX2StartElementNs(void *ctx, const xmlChar *fullname; fullname = xmlDictQLookup(ctxt->dict, prefix, localname); - if (fullname != NULL) - localname = fullname; + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + localname = fullname; } else { lname = xmlBuildQName(localname, prefix, NULL, 0); + if (lname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } } } /* @@ -2264,7 +2133,8 @@ xmlSAX2StartElementNs(void *ctx, else ret->name = lname; if (ret->name == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); + xmlFree(ret); return; } } @@ -2280,22 +2150,11 @@ xmlSAX2StartElementNs(void *ctx, ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, (xmlChar *) lname, NULL); if (ret == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); return; } } - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if (ctxt->input->line < USHRT_MAX) - ret->line = (unsigned short) ctxt->input->line; - else - ret->line = USHRT_MAX; - } - } - if (parent == NULL) { - xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); - } /* * Build the namespace list */ @@ -2313,13 +2172,12 @@ xmlSAX2StartElementNs(void *ctx, if ((URI != NULL) && (prefix == pref)) ret->ns = ns; } else { - /* - * any out of memory error would already have been raised - * but we can't be guaranteed it's the actual error due to the - * API, best is to skip in this case - */ + xmlSAX2ErrMemory(ctxt); continue; } + + xmlParserNsUpdateSax(ctxt, pref, ns); + #ifdef LIBXML_VALID_ENABLED if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && ctxt->myDoc && ctxt->myDoc->intSubset) { @@ -2330,6 +2188,11 @@ xmlSAX2StartElementNs(void *ctx, } ctxt->nodemem = -1; + /* + * Link the child element + */ + xmlSAX2AppendChild(ctxt, ret); + /* * We are parsing a new node. */ @@ -2339,17 +2202,6 @@ xmlSAX2StartElementNs(void *ctx, return; } - /* - * 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: */ @@ -2362,15 +2214,19 @@ xmlSAX2StartElementNs(void *ctx, * 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); + ret->ns = xmlParserNsLookupSax(ctxt, prefix); if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { - ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix); + int res; + + res = xmlSearchNsSafe(ret, prefix, &ret->ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); } if (ret->ns == NULL) { ns = xmlNewNs(ret, NULL, prefix); if (ns == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); return; } if (prefix != NULL) @@ -2388,7 +2244,11 @@ xmlSAX2StartElementNs(void *ctx, * process all the other attributes */ if (nb_attributes > 0) { + xmlAttrPtr prev = NULL; + for (j = 0,i = 0;i < nb_attributes;i++,j+=5) { + xmlAttrPtr attr = NULL; + /* * Handle the rare case of an undefined attribute prefix */ @@ -2398,24 +2258,43 @@ xmlSAX2StartElementNs(void *ctx, fullname = xmlDictQLookup(ctxt->dict, attributes[j+1], attributes[j]); - if (fullname != NULL) { - xmlSAX2AttributeNs(ctxt, fullname, NULL, - attributes[j+3], attributes[j+4]); - continue; - } + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + attr = xmlSAX2AttributeNs(ctxt, fullname, NULL, + attributes[j+3], + attributes[j+4]); + goto have_attr; } else { lname = xmlBuildQName(attributes[j], attributes[j+1], NULL, 0); - if (lname != NULL) { - xmlSAX2AttributeNs(ctxt, lname, NULL, - attributes[j+3], attributes[j+4]); - xmlFree(lname); - continue; - } + if (lname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + attr = xmlSAX2AttributeNs(ctxt, lname, NULL, + attributes[j+3], + attributes[j+4]); + xmlFree(lname); + goto have_attr; } } - xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], - attributes[j+3], attributes[j+4]); + attr = xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], + attributes[j+3], attributes[j+4]); +have_attr: + if (attr == NULL) + continue; + + /* link at the end to preserve order */ + if (prev == NULL) { + ctxt->node->properties = attr; + } else { + prev->next = attr; + attr->prev = prev; + } + + prev = attr; } } @@ -2456,24 +2335,15 @@ xmlSAX2EndElementNs(void *ctx, 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); + ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, + ctxt->node); #endif /* LIBXML_VALID_ENABLED */ /* @@ -2496,21 +2366,13 @@ xmlSAX2Reference(void *ctx, const xmlChar *name) 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); + ret = xmlNewReference(ctxt->myDoc, name); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; } + + xmlSAX2AppendChild(ctxt, ret); } /** @@ -2529,10 +2391,6 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, xmlNodePtr lastChild; if (ctxt == 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, @@ -2540,17 +2398,9 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, */ 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 @@ -2569,7 +2419,7 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, ctxt->nodelen = len; ctxt->nodemem = len + 1; } else { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); return; } } else { @@ -2578,6 +2428,10 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, ((type != XML_TEXT_NODE) || (lastChild->name == xmlStringText)); if ((coalesceText) && (ctxt->nodemem != 0)) { + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + /* * The whole point of maintaining nodelen and nodemem, * xmlTextConcat is too costly, i.e. compute length, @@ -2593,28 +2447,26 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, lastChild->content = xmlStrdup(lastChild->content); } if (lastChild->content == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: xmlStrdup returned NULL"); + xmlSAX2ErrMemory(ctxt); return; } - if (((size_t)ctxt->nodelen + (size_t)len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: huge text node"); + if ((len > maxLength) || (ctxt->nodelen > maxLength - len)) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Text node too long, try XML_PARSE_HUGE"); + xmlHaltParser(ctxt); return; } - if ((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; + int size; - size = ctxt->nodemem + len; - size *= 2; + size = ctxt->nodemem > INT_MAX - len ? + INT_MAX : + ctxt->nodemem + len; + size = size > INT_MAX / 2 ? INT_MAX : size * 2; newbuf = (xmlChar *) xmlRealloc(lastChild->content,size); if (newbuf == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); return; } ctxt->nodemem = size; @@ -2625,7 +2477,7 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, lastChild->content[ctxt->nodelen] = 0; } else if (coalesceText) { if (xmlTextConcat(lastChild, ch, len)) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); } if (ctxt->node->children != NULL) { ctxt->nodelen = xmlStrlen(lastChild->content); @@ -2635,11 +2487,14 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, /* Mixed content, first time */ if (type == XML_TEXT_NODE) { lastChild = xmlSAX2TextNode(ctxt, ch, len); - lastChild->doc = ctxt->myDoc; + if (lastChild != NULL) + lastChild->doc = ctxt->myDoc; } else lastChild = xmlNewCDataBlock(ctxt->myDoc, ch, len); - if (lastChild != NULL) { - xmlAddChild(ctxt->node, lastChild); + if (lastChild == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { + xmlSAX2AppendChild(ctxt, lastChild); if (ctxt->node->children != NULL) { ctxt->nodelen = len; ctxt->nodemem = len + 1; @@ -2647,6 +2502,19 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, } } } + + if ((lastChild != NULL) && + (type == XML_TEXT_NODE) && + (ctxt->linenumbers) && + (ctxt->input != NULL)) { + if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) + lastChild->line = ctxt->input->line; + else { + lastChild->line = USHRT_MAX; + if (ctxt->options & XML_PARSE_BIG_LINES) + lastChild->psvi = (void *) (ptrdiff_t) ctxt->input->line; + } + } } /** @@ -2675,11 +2543,6 @@ xmlSAX2Characters(void *ctx, const xmlChar *ch, int len) 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 } /** @@ -2696,55 +2559,16 @@ xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target, { 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 < USHRT_MAX) - ret->line = (unsigned short) ctxt->input->line; - else - ret->line = USHRT_MAX; - } - } - if (ctxt->inSubset == 1) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); - return; - } else if (ctxt->inSubset == 2) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); - return; - } - if (parent == NULL) { -#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); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; } + + xmlSAX2AppendChild(ctxt, ret); } /** @@ -2759,53 +2583,16 @@ 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 < USHRT_MAX) - ret->line = (unsigned short) ctxt->input->line; - else - ret->line = USHRT_MAX; - } + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; } - if (ctxt->inSubset == 1) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); - return; - } else if (ctxt->inSubset == 2) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); - return; - } - if (parent == NULL) { -#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); - } + xmlSAX2AppendChild(ctxt, ret); } /** @@ -2829,6 +2616,8 @@ static int xmlSAX2DefaultVersionValue = 2; * xmlSAXDefaultVersion: * @version: the version, 1 or 2 * + * DEPRECATED: Use parser option XML_PARSE_SAX1. + * * 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 @@ -2863,20 +2652,23 @@ 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); +#ifdef LIBXML_SAX1_ENABLED + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; +#else + hdlr->startElement = NULL; + hdlr->endElement = NULL; +#endif /* LIBXML_SAX1_ENABLED */ hdlr->internalSubset = xmlSAX2InternalSubset; hdlr->externalSubset = xmlSAX2ExternalSubset; hdlr->isStandalone = xmlSAX2IsStandalone; @@ -2929,7 +2721,7 @@ xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) /** * xmlDefaultSAXHandlerInit: * - * DEPRECATED: This function will be made private. Call xmlInitParser to + * DEPRECATED: This function is a no-op. Call xmlInitParser to * initialize the library. * * Initialize the default SAX2 handler @@ -2937,9 +2729,6 @@ xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) void xmlDefaultSAXHandlerInit(void) { -#ifdef LIBXML_SAX1_ENABLED - xmlSAXVersion((xmlSAXHandlerPtr) &xmlDefaultSAXHandler, 1); -#endif /* LIBXML_SAX1_ENABLED */ } #ifdef LIBXML_HTML_ENABLED @@ -2990,15 +2779,12 @@ xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr) /** * htmlDefaultSAXHandlerInit: * - * DEPRECATED: This function will be made private. Call xmlInitParser to + * DEPRECATED: This function is a no-op. Call xmlInitParser to * initialize the library. - * - * Initialize the default SAX handler */ void htmlDefaultSAXHandlerInit(void) { - xmlSAX2InitHtmlDefaultSAXHandler((xmlSAXHandlerPtr) &htmlDefaultSAXHandler); } #endif /* LIBXML_HTML_ENABLED */ diff --git a/buf.c b/buf.c index 6749d975717..f9f59b26b51 100644 --- a/buf.c +++ b/buf.c @@ -20,11 +20,11 @@ #include #include -#include -#include #include #include /* for XML_MAX_TEXT_LENGTH */ -#include "buf.h" + +#include "private/buf.h" +#include "private/error.h" #ifndef SIZE_MAX #define SIZE_MAX ((size_t) -1) @@ -89,10 +89,9 @@ struct _xmlBuf { * To be improved... */ static void -xmlBufMemoryError(xmlBufPtr buf, const char *extra) +xmlBufMemoryError(xmlBufPtr buf) { - __xmlSimpleError(XML_FROM_BUFFER, XML_ERR_NO_MEMORY, NULL, NULL, extra); - if ((buf) && (buf->error == 0)) + if (buf->error == 0) buf->error = XML_ERR_NO_MEMORY; } @@ -104,10 +103,9 @@ xmlBufMemoryError(xmlBufPtr buf, const char *extra) * To be improved... */ static void -xmlBufOverflowError(xmlBufPtr buf, const char *extra) +xmlBufOverflowError(xmlBufPtr buf) { - __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra); - if ((buf) && (buf->error == 0)) + if (buf->error == 0) buf->error = XML_BUF_OVERFLOW; } @@ -123,19 +121,16 @@ xmlBufCreate(void) { xmlBufPtr ret; ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); - if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->error = 0; ret->buffer = NULL; ret->size = xmlDefaultBufferSize; UPDATE_COMPAT(ret); ret->alloc = xmlBufferAllocScheme; - ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlBufMemoryError(ret, "creating buffer"); xmlFree(ret); return(NULL); } @@ -158,10 +153,8 @@ xmlBufCreateSize(size_t size) { if (size == SIZE_MAX) return(NULL); ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); - if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->error = 0; ret->buffer = NULL; @@ -169,9 +162,8 @@ xmlBufCreateSize(size_t size) { ret->size = (size ? size + 1 : 0); /* +1 for ending null */ UPDATE_COMPAT(ret); if (ret->size){ - ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlBufMemoryError(ret, "creating buffer"); xmlFree(ret); return(NULL); } @@ -198,15 +190,21 @@ xmlBufDetach(xmlBufPtr buf) { if (buf == NULL) return(NULL); - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) - return(NULL); if (buf->buffer != NULL) return(NULL); if (buf->error) return(NULL); - ret = buf->content; + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && + (buf->content != buf->contentIO)) { + ret = xmlStrndup(buf->content, buf->use); + xmlFree(buf->contentIO); + } else { + ret = buf->content; + } + buf->content = NULL; + buf->contentIO = NULL; buf->size = 0; buf->use = 0; UPDATE_COMPAT(buf); @@ -214,40 +212,6 @@ xmlBufDetach(xmlBufPtr buf) { return ret; } - -/** - * xmlBufCreateStatic: - * @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. - */ -xmlBufPtr -xmlBufCreateStatic(void *mem, size_t size) { - xmlBufPtr ret; - - if (mem == NULL) - return(NULL); - - ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); - if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); - return(NULL); - } - ret->use = size; - ret->size = size; - UPDATE_COMPAT(ret); - ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; - ret->content = (xmlChar *) mem; - ret->error = 0; - ret->buffer = NULL; - return(ret); -} - /** * xmlBufGetAllocationScheme: * @buf: the buffer @@ -259,10 +223,6 @@ xmlBufCreateStatic(void *mem, size_t size) { int xmlBufGetAllocationScheme(xmlBufPtr buf) { if (buf == NULL) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufGetAllocationScheme: buf == NULL\n"); -#endif return(-1); } return(buf->alloc); @@ -281,19 +241,13 @@ int xmlBufSetAllocationScheme(xmlBufPtr buf, xmlBufferAllocationScheme scheme) { if ((buf == NULL) || (buf->error != 0)) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufSetAllocationScheme: buf == NULL or in error\n"); -#endif return(-1); } - if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || - (buf->alloc == XML_BUFFER_ALLOC_IO)) + if (buf->alloc == XML_BUFFER_ALLOC_IO) return(-1); if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || (scheme == XML_BUFFER_ALLOC_EXACT) || (scheme == XML_BUFFER_ALLOC_HYBRID) || - (scheme == XML_BUFFER_ALLOC_IMMUTABLE) || (scheme == XML_BUFFER_ALLOC_BOUNDED)) { buf->alloc = scheme; if (buf->buffer) @@ -321,18 +275,13 @@ xmlBufSetAllocationScheme(xmlBufPtr buf, void xmlBufFree(xmlBufPtr buf) { if (buf == NULL) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufFree: 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)) { + } else if (buf->content != NULL) { xmlFree(buf->content); } xmlFree(buf); @@ -350,9 +299,7 @@ xmlBufEmpty(xmlBufPtr buf) { if (buf->content == NULL) return; CHECK_COMPAT(buf) buf->use = 0; - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { - buf->content = BAD_CAST ""; - } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) && + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO; @@ -385,8 +332,7 @@ xmlBufShrink(xmlBufPtr buf, size_t len) { if (len > buf->use) return(0); buf->use -= len; - if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || - ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) { + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { /* * we just move the content pointer, but also make sure * the perceived buffer size has shrunk accordingly @@ -434,11 +380,10 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { if ((buf == NULL) || (buf->error != 0)) return(0); CHECK_COMPAT(buf) - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); if (len < buf->size - buf->use) return(buf->size - buf->use - 1); if (len >= SIZE_MAX - buf->use) { - xmlBufMemoryError(buf, "growing buffer past SIZE_MAX"); + xmlBufMemoryError(buf); return(0); } @@ -455,7 +400,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { */ if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) || (buf->size >= XML_MAX_TEXT_LENGTH)) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(0); } if (size >= XML_MAX_TEXT_LENGTH) @@ -466,7 +411,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); if (newbuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return(0); } buf->contentIO = newbuf; @@ -474,7 +419,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { } else { newbuf = (xmlChar *) xmlRealloc(buf->content, size); if (newbuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return(0); } buf->content = newbuf; @@ -504,7 +449,7 @@ xmlBufGrow(xmlBufPtr buf, int len) { ret = xmlBufGrowInternal(buf, len); if (buf->error != 0) return(-1); - return((int) ret); + return(ret > INT_MAX ? INT_MAX : ret); } /** @@ -520,23 +465,15 @@ xmlBufDump(FILE *file, xmlBufPtr buf) { size_t ret; if ((buf == NULL) || (buf->error != 0)) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufDump: buf == NULL or in error\n"); -#endif return(0); } if (buf->content == NULL) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufDump: buf->content == NULL\n"); -#endif return(0); } CHECK_COMPAT(buf) if (file == NULL) file = stdout; - ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); + ret = fwrite(buf->content, 1, buf->use, file); return(ret); } @@ -699,13 +636,12 @@ xmlBufResize(xmlBufPtr buf, size_t size) return(0); CHECK_COMPAT(buf) - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) { /* * Used to provide parsing limits */ if (size >= XML_MAX_TEXT_LENGTH) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(0); } } @@ -726,7 +662,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } while (size > newSize) { if (newSize > SIZE_MAX / 2) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } newSize *= 2; @@ -742,7 +678,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) newSize = buf->size; while (size > newSize) { if (newSize > SIZE_MAX / 2) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } newSize *= 2; @@ -767,7 +703,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } else { rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); if (rebuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } buf->contentIO = rebuf; @@ -777,7 +713,8 @@ xmlBufResize(xmlBufPtr buf, size_t size) if (buf->content == NULL) { rebuf = (xmlChar *) xmlMallocAtomic(newSize); buf->use = 0; - rebuf[buf->use] = 0; + if (rebuf != NULL) + rebuf[buf->use] = 0; } else if (buf->size - buf->use < 100) { rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); } else { @@ -794,7 +731,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } } if (rebuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } buf->content = rebuf; @@ -814,8 +751,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) * Add a string range to an XML buffer. if len == -1, the length of * str is recomputed. * - * Returns 0 successful, a positive error code number otherwise - * and -1 in case of internal or API error. + * Returns 0 if successful, -1 in case of error. */ int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { @@ -825,12 +761,7 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { return -1; CHECK_COMPAT(buf) - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; if (len < -1) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufAdd: len < 0\n"); -#endif return -1; } if (len == 0) return 0; @@ -844,7 +775,7 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { /* Note that both buf->size and buf->use can be zero here. */ if ((size_t) len >= buf->size - buf->use) { if ((size_t) len >= SIZE_MAX - buf->use) { - xmlBufMemoryError(buf, "growing buffer past SIZE_MAX"); + xmlBufMemoryError(buf); return(-1); } needSize = buf->use + len + 1; @@ -853,17 +784,15 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { * Used to provide parsing limits */ if (needSize >= XML_MAX_TEXT_LENGTH) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(-1); } } - if (!xmlBufResize(buf, needSize)){ - xmlBufMemoryError(buf, "growing buffer"); - return XML_ERR_NO_MEMORY; - } + if (!xmlBufResize(buf, needSize)) + return(-1); } - memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); + memmove(&buf->content[buf->use], str, len); buf->use += len; buf->content[buf->use] = 0; UPDATE_COMPAT(buf) @@ -885,83 +814,10 @@ xmlBufCat(xmlBufPtr buf, const xmlChar *str) { if ((buf == NULL) || (buf->error)) return(-1); CHECK_COMPAT(buf) - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; if (str == NULL) return -1; return xmlBufAdd(buf, str, -1); } -/** - * xmlBufCCat: - * @buf: the buffer to dump - * @str: the C char string - * - * Append a zero terminated C string to an XML buffer. - * - * Returns 0 successful, a positive error code number otherwise - * and -1 in case of internal or API error. - */ -int -xmlBufCCat(xmlBufPtr buf, const char *str) { - return xmlBufCat(buf, (const xmlChar *) str); -} - -/** - * xmlBufWriteQuotedString: - * @buf: the XML buffer output - * @string: the string to add - * - * routine which manage and grows an output buffer. This one writes - * a quoted or double quoted #xmlChar string, checking first if it holds - * quote or double-quotes internally - * - * Returns 0 if successful, a positive error code number otherwise - * and -1 in case of internal or API error. - */ -int -xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) { - const xmlChar *cur, *base; - if ((buf == NULL) || (buf->error)) - return(-1); - CHECK_COMPAT(buf) - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) - return(-1); - if (xmlStrchr(string, '\"')) { - if (xmlStrchr(string, '\'')) { -#ifdef DEBUG_BUFFER - xmlGenericError(xmlGenericErrorContext, - "xmlBufWriteQuotedString: string contains quote and double-quotes !\n"); -#endif - xmlBufCCat(buf, "\""); - base = cur = string; - while(*cur != 0){ - if(*cur == '"'){ - if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST """, 6); - cur++; - base = cur; - } - else { - cur++; - } - } - if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufCCat(buf, "\""); - } - else{ - xmlBufCCat(buf, "\'"); - xmlBufCat(buf, string); - xmlBufCCat(buf, "\'"); - } - } else { - xmlBufCCat(buf, "\""); - xmlBufCat(buf, string); - xmlBufCCat(buf, "\""); - } - return(0); -} - /** * xmlBufFromBuffer: * @buffer: incoming old buffer to convert to a new one @@ -982,7 +838,6 @@ xmlBufFromBuffer(xmlBufferPtr buffer) { ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); return(NULL); } ret->use = buffer->use; @@ -1016,12 +871,19 @@ xmlBufBackToBuffer(xmlBufPtr buf) { if (buf == NULL) return(NULL); CHECK_COMPAT(buf) - if ((buf->error) || (buf->buffer == NULL)) { + ret = buf->buffer; + + if ((buf->error) || (ret == NULL)) { xmlBufFree(buf); + if (ret != NULL) { + ret->content = NULL; + ret->contentIO = NULL; + ret->use = 0; + ret->size = 0; + } return(NULL); } - ret = buf->buffer; /* * What to do in case of error in the buffer ??? */ @@ -1031,7 +893,7 @@ xmlBufBackToBuffer(xmlBufPtr buf) { * maximum allowed memory for an xmlBuffer on this architecture. * Keep the buffer but provide a truncated size value. */ - xmlBufOverflowError(buf, "Used size too big for xmlBuffer"); + xmlBufOverflowError(buf); ret->use = INT_MAX; ret->size = INT_MAX; } else if (buf->size > INT_MAX) { @@ -1041,12 +903,12 @@ xmlBufBackToBuffer(xmlBufPtr buf) { * limit. * Keep the buffer but provide a truncated size value. */ - xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer"); - ret->use = (int) buf->use; + xmlBufOverflowError(buf); + ret->use = buf->use; ret->size = INT_MAX; } else { - ret->use = (int) buf->use; - ret->size = (int) buf->size; + ret->use = buf->use; + ret->size = buf->size; } ret->alloc = buf->alloc; ret->content = buf->content; @@ -1055,32 +917,6 @@ xmlBufBackToBuffer(xmlBufPtr buf) { return(ret); } -/** - * xmlBufMergeBuffer: - * @buf: an xmlBufPtr - * @buffer: the buffer to consume into @buf - * - * The content of @buffer is appended to @buf and @buffer is freed - * - * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed - */ -int -xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) { - int ret = 0; - - if ((buf == NULL) || (buf->error)) { - xmlBufferFree(buffer); - return(-1); - } - CHECK_COMPAT(buf) - if ((buffer != NULL) && (buffer->content != NULL) && - (buffer->use > 0)) { - ret = xmlBufAdd(buf, buffer->content, buffer->use); - } - xmlBufferFree(buffer); - return(ret); -} - /** * xmlBufResetInput: * @buf: an xmlBufPtr @@ -1092,48 +928,14 @@ xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) { */ int xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) { - if ((input == NULL) || (buf == NULL) || (buf->error)) - return(-1); - CHECK_COMPAT(buf) - input->base = input->cur = buf->content; - input->end = &buf->content[buf->use]; - return(0); -} - -/** - * xmlBufGetInputBase: - * @buf: an xmlBufPtr - * @input: an xmlParserInputPtr - * - * Get the base of the @input relative to the beginning of the buffer - * - * Returns the size_t corresponding to the displacement - */ -size_t -xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) { - size_t base; - - if ((input == NULL) || (buf == NULL) || (buf->error)) - return(-1); - CHECK_COMPAT(buf) - base = input->base - buf->content; - /* - * We could do some pointer arithmetic checks but that's probably - * sufficient. - */ - if (base > buf->size) { - xmlBufOverflowError(buf, "Input reference outside of the buffer"); - base = 0; - } - return(base); + return(xmlBufUpdateInput(buf, input, 0)); } /** - * xmlBufSetInputBaseCur: + * xmlBufUpdateInput: * @buf: an xmlBufPtr * @input: an xmlParserInputPtr - * @base: the base value relative to the beginning of the buffer - * @cur: the cur value relative to the beginning of the buffer + * @pos: the cur value relative to the beginning of the buffer * * Update the input to use the base and cur relative to the buffer * after a possible reallocation of its content @@ -1141,17 +943,12 @@ xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) { * Returns -1 in case of error, 0 otherwise */ int -xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input, - size_t base, size_t cur) { - if (input == NULL) - return(-1); - if ((buf == NULL) || (buf->error)) { - input->base = input->cur = input->end = BAD_CAST ""; +xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) { + if ((buf == NULL) || (input == NULL)) return(-1); - } CHECK_COMPAT(buf) - input->base = &buf->content[base]; - input->cur = input->base + cur; + input->base = buf->content; + input->cur = input->base + pos; input->end = &buf->content[buf->use]; return(0); } diff --git a/buf.h b/buf.h deleted file mode 100644 index b7bcf61fe2e..00000000000 --- a/buf.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Summary: Internal Interfaces for memory buffers in libxml2 - * Description: this module describes most of the new xmlBuf buffer - * entry points, those are private routines, with a - * few exceptions exported in tree.h. This was added - * in 2.9.0. - * - * Copy: See Copyright for the status of this software. - * - * Author: Daniel Veillard - */ - -#ifndef __XML_BUF_H__ -#define __XML_BUF_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -xmlBufPtr xmlBufCreate(void); -xmlBufPtr xmlBufCreateSize(size_t size); -xmlBufPtr xmlBufCreateStatic(void *mem, size_t size); - -int xmlBufSetAllocationScheme(xmlBufPtr buf, - xmlBufferAllocationScheme scheme); -int xmlBufGetAllocationScheme(xmlBufPtr buf); - -void xmlBufFree(xmlBufPtr buf); -void xmlBufEmpty(xmlBufPtr buf); - -/* size_t xmlBufShrink(xmlBufPtr buf, size_t len); */ -int xmlBufGrow(xmlBufPtr buf, int len); -int xmlBufResize(xmlBufPtr buf, size_t len); - -int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len); -int xmlBufCat(xmlBufPtr buf, const xmlChar *str); -int xmlBufCCat(xmlBufPtr buf, const char *str); -int xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string); - -size_t xmlBufAvail(const xmlBufPtr buf); -size_t xmlBufLength(const xmlBufPtr buf); -/* size_t xmlBufUse(const xmlBufPtr buf); */ -int xmlBufIsEmpty(const xmlBufPtr buf); -int xmlBufAddLen(xmlBufPtr buf, size_t len); - -/* const xmlChar * xmlBufContent(const xmlBuf *buf); */ -/* const xmlChar * xmlBufEnd(xmlBufPtr buf); */ - -xmlChar * xmlBufDetach(xmlBufPtr buf); - -size_t xmlBufDump(FILE *file, xmlBufPtr buf); - -xmlBufPtr xmlBufFromBuffer(xmlBufferPtr buffer); -xmlBufferPtr xmlBufBackToBuffer(xmlBufPtr buf); -int xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer); - -int xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input); -size_t xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input); -int xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input, - size_t base, size_t cur); -#ifdef __cplusplus -} -#endif -#endif /* __XML_BUF_H__ */ - diff --git a/c14n.c b/c14n.c index d55729ccc59..964ac998973 100644 --- a/c14n.c +++ b/c14n.c @@ -12,7 +12,6 @@ #define IN_LIBXML #include "libxml.h" #ifdef LIBXML_C14N_ENABLED -#ifdef LIBXML_OUTPUT_ENABLED #include #include @@ -21,11 +20,11 @@ #include #include #include -#include #include #include -#include "buf.h" +#include "private/error.h" +#include "private/io.h" /************************************************************************ * * @@ -73,7 +72,7 @@ typedef struct _xmlC14NCtx { static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void); static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur); -static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur, +static int xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node); static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur, @@ -135,87 +134,85 @@ static xmlChar *xmlC11NNormalizeString(const xmlChar * input, * Handle a redefinition of memory error */ static void -xmlC14NErrMemory(const char *extra) +xmlC14NErrMemory(xmlC14NCtxPtr ctxt) { - __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); + if (ctxt != NULL) + ctxt->error = XML_ERR_NO_MEMORY; + + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_C14N, NULL); } -/** - * xmlC14NErrParam: - * @extra: extra information - * - * Handle a redefinition of param error - */ static void -xmlC14NErrParam(const char *extra) +xmlC14NErrFull(xmlC14NCtxPtr ctxt, xmlNodePtr node, int code, const char *str1, + const char *msg, ...) { - __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); + va_list ap; + int res; + + if (ctxt != NULL) + ctxt->error = code; + + va_start(ap, msg); + res = xmlVRaiseError(NULL, NULL, NULL, ctxt, node, + XML_FROM_C14N, code, XML_ERR_ERROR, NULL, 0, + str1, NULL, NULL, 0, 0, + msg, ap); + va_end(ap); + if (res < 0) + xmlC14NErrMemory(ctxt); } /** - * xmlC14NErrInternal: + * xmlC14NErrParam: * @extra: extra information * - * Handle a redefinition of internal error + * Handle a param error */ static void -xmlC14NErrInternal(const char *extra) +xmlC14NErrParam(xmlC14NCtxPtr ctxt) { - __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); + xmlC14NErrFull(ctxt, NULL, XML_ERR_ARGUMENT, NULL, + "Invalid argument\n", NULL); } /** * xmlC14NErrInvalidNode: * @extra: extra information * - * Handle a redefinition of invalid node error + * Handle an invalid node error */ static void -xmlC14NErrInvalidNode(const char *node_type, const char *extra) +xmlC14NErrInvalidNode(xmlC14NCtxPtr ctxt, 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); + xmlC14NErrFull(ctxt, NULL, XML_C14N_INVALID_NODE, extra, + "Node %s is invalid here : %s\n", node_type, extra); } /** * xmlC14NErrUnknownNode: * @extra: extra information * - * Handle a redefinition of unknown node error + * Handle an unknown node error */ static void -xmlC14NErrUnknownNode(int node_type, const char *extra) +xmlC14NErrUnknownNode(xmlC14NCtxPtr ctxt, 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); + xmlC14NErrFull(ctxt, NULL, XML_C14N_UNKNOW_NODE, extra, + "Unknown node type %d found : %s\n", node_type, extra); } /** * xmlC14NErrRelativeNamespace: * @extra: extra information * - * Handle a redefinition of relative namespace error + * Handle a relative namespace error */ static void -xmlC14NErrRelativeNamespace(const char *ns_uri) +xmlC14NErrRelativeNamespace(xmlC14NCtxPtr ctxt, 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); + xmlC14NErrFull(ctxt, NULL, XML_C14N_RELATIVE_NAMESPACE, ns_uri, + "Relative namespace UR is invalid here : %s\n", ns_uri); } @@ -228,18 +225,13 @@ xmlC14NErrRelativeNamespace(const char *ns_uri) * @msg: the message * @extra: extra information * - * Handle a redefinition of attribute error + * Handle an 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); + xmlC14NErrFull(ctxt, node, error, NULL, "%s", msg); } /************************************************************************ @@ -282,18 +274,16 @@ xmlC14NVisibleNsStackCreate(void) { xmlC14NVisibleNsStackPtr ret; ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack)); - if (ret == NULL) { - xmlC14NErrMemory("creating namespaces stack"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack)); + memset(ret, 0, sizeof(xmlC14NVisibleNsStack)); return(ret); } static void xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) { if(cur == NULL) { - xmlC14NErrParam("destroying namespaces stack"); + xmlC14NErrParam(NULL); return; } if(cur->nsTab != NULL) { @@ -309,22 +299,18 @@ xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) { } -static void +static int 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; - } + ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) + return (1); 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; - } + if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) + return (-1); memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr)); memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr)); cur->nsMax = XML_NAMESPACES_DEFAULT; @@ -334,17 +320,13 @@ xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr n tmpSize = 2 * cur->nsMax; tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr)); - if (tmp == NULL) { - xmlC14NErrMemory("adding node to stack"); - return; - } + if (tmp == NULL) + return (-1); cur->nsTab = (xmlNsPtr*)tmp; tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr)); - if (tmp == NULL) { - xmlC14NErrMemory("adding node to stack"); - return; - } + if (tmp == NULL) + return (-1); cur->nodeTab = (xmlNodePtr*)tmp; cur->nsMax = tmpSize; @@ -353,12 +335,14 @@ xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr n cur->nodeTab[cur->nsCurEnd] = node; ++cur->nsCurEnd; + + return (0); } static void xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { if((cur == NULL) || (state == NULL)) { - xmlC14NErrParam("saving namespaces stack"); + xmlC14NErrParam(NULL); return; } @@ -370,7 +354,7 @@ xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr static void xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { if((cur == NULL) || (state == NULL)) { - xmlC14NErrParam("restoring namespaces stack"); + xmlC14NErrParam(NULL); return; } cur->nsCurEnd = state->nsCurEnd; @@ -381,7 +365,7 @@ xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStack static void xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) { if(cur == NULL) { - xmlC14NErrParam("shifting namespaces stack"); + xmlC14NErrParam(NULL); return; } cur->nsPrevStart = cur->nsPrevEnd; @@ -417,7 +401,7 @@ xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns) int has_empty_ns; if(cur == NULL) { - xmlC14NErrParam("searching namespaces stack (c14n)"); + xmlC14NErrParam(NULL); return (0); } @@ -450,7 +434,7 @@ xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NC int has_empty_ns; if(cur == NULL) { - xmlC14NErrParam("searching namespaces stack (exc c14n)"); + xmlC14NErrParam(ctx); return (0); } @@ -514,8 +498,8 @@ xmlC14NIsXmlNs(xmlNsPtr ns) static int xmlC14NNsCompare(const void *data1, const void *data2) { - const xmlNsPtr ns1 = (const xmlNsPtr) data1; - const xmlNsPtr ns2 = (const xmlNsPtr) data2; + const xmlNs *ns1 = data1; + const xmlNs *ns2 = data2; if (ns1 == ns2) return (0); if (ns1 == NULL) @@ -537,11 +521,11 @@ xmlC14NNsCompare(const void *data1, const void *data2) * Returns 1 on success or 0 on fail. */ static int -xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx) +xmlC14NPrintNamespaces(const xmlNs *ns, xmlC14NCtxPtr ctx) { if ((ns == NULL) || (ctx == NULL)) { - xmlC14NErrParam("writing namespaces"); + xmlC14NErrParam(ctx); return 0; } @@ -553,7 +537,7 @@ xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx) xmlOutputBufferWriteString(ctx->buf, " xmlns="); } if(ns->href != NULL) { - xmlBufWriteQuotedString(ctx->buf->buffer, ns->href); + xmlOutputBufferWriteQuotedString(ctx->buf, ns->href); } else { xmlOutputBufferWriteString(ctx->buf, "\"\""); } @@ -562,7 +546,7 @@ xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx) static int xmlC14NPrintNamespacesWalker(const void *ns, void *ctx) { - return xmlC14NPrintNamespaces((const xmlNsPtr) ns, (xmlC14NCtxPtr) ctx); + return xmlC14NPrintNamespaces(ns, ctx); } /** @@ -614,7 +598,7 @@ xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) int has_empty_ns = 0; if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { - xmlC14NErrParam("processing namespaces axis (c14n)"); + xmlC14NErrParam(ctx); return (-1); } @@ -623,7 +607,7 @@ xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) */ list = xmlListCreate(NULL, xmlC14NNsCompare); if (list == NULL) { - xmlC14NErrInternal("creating namespaces list (c14n)"); + xmlC14NErrMemory(ctx); return (-1); } @@ -635,7 +619,10 @@ xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) 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 (xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur) < 0) { + xmlC14NErrMemory(ctx); + goto error; + } } if(!already_rendered) { xmlListInsert(list, ns); @@ -674,6 +661,7 @@ xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) /* * Cleanup */ +error: xmlListDelete(list); return (0); } @@ -721,12 +709,12 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) int has_empty_ns_in_inclusive_list = 0; if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { - xmlC14NErrParam("processing namespaces axis (exc c14n)"); + xmlC14NErrParam(ctx); return (-1); } if(!xmlC14NIsExclusive(ctx)) { - xmlC14NErrParam("processing namespaces axis (exc c14n)"); + xmlC14NErrParam(ctx); return (-1); } @@ -736,7 +724,7 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) */ list = xmlListCreate(NULL, xmlC14NNsCompare); if (list == NULL) { - xmlC14NErrInternal("creating namespaces list (exc c14n)"); + xmlC14NErrMemory(ctx); return (-1); } @@ -764,7 +752,10 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) 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 (xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur) < 0) { + xmlC14NErrMemory(ctx); + goto error; + } } if(!already_rendered) { xmlListInsert(list, ns); @@ -790,7 +781,10 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) } } if(visible) { - xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); + if (xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur) < 0) { + xmlC14NErrMemory(ctx); + goto error; + } } if(xmlStrlen(ns->prefix) == 0) { has_empty_ns = 1; @@ -807,7 +801,10 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) */ 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 (xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur) < 0) { + xmlC14NErrMemory(ctx); + goto error; + } if(!already_rendered && visible) { xmlListInsert(list, attr->ns); } @@ -851,6 +848,7 @@ xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) /* * Cleanup */ +error: xmlListDelete(list); return (0); } @@ -887,8 +885,8 @@ xmlC14NIsXmlAttr(xmlAttrPtr attr) static int xmlC14NAttrsCompare(const void *data1, const void *data2) { - const xmlAttrPtr attr1 = (const xmlAttrPtr) data1; - const xmlAttrPtr attr2 = (const xmlAttrPtr) data2; + const xmlAttr *attr1 = data1; + const xmlAttr *attr2 = data2; int ret = 0; /* @@ -941,13 +939,13 @@ xmlC14NAttrsCompare(const void *data1, const void *data2) static int xmlC14NPrintAttrs(const void *data, void *user) { - const xmlAttrPtr attr = (const xmlAttrPtr) data; + const xmlAttr *attr = data; xmlC14NCtxPtr ctx = (xmlC14NCtxPtr) user; xmlChar *value; xmlChar *buffer; if ((attr == NULL) || (ctx == NULL)) { - xmlC14NErrParam("writing attributes"); + xmlC14NErrParam(ctx); return (0); } @@ -969,7 +967,7 @@ xmlC14NPrintAttrs(const void *data, void *user) xmlOutputBufferWriteString(ctx->buf, (const char *) buffer); xmlFree(buffer); } else { - xmlC14NErrInternal("normalizing attributes axis"); + xmlC14NErrMemory(ctx); return (0); } } @@ -1018,20 +1016,22 @@ xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) int tmp_str_len; if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) { - xmlC14NErrParam("processing xml:base attribute"); + xmlC14NErrParam(ctx); 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"); + xmlC14NErrMemory(ctx); 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))) { + int code; + attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); if(attr != NULL) { /* get attr value */ @@ -1039,7 +1039,7 @@ xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) if(tmp_str == NULL) { xmlFree(res); - xmlC14NErrInternal("processing xml:base attribute - can't get attr value"); + xmlC14NErrMemory(ctx); return (NULL); } @@ -1052,7 +1052,7 @@ xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) xmlFree(tmp_str); xmlFree(res); - xmlC14NErrInternal("processing xml:base attribute - can't modify uri"); + xmlC14NErrMemory(ctx); return (NULL); } @@ -1060,12 +1060,17 @@ xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) } /* build uri */ - tmp_str2 = xmlBuildURI(res, tmp_str); - if(tmp_str2 == NULL) { + code = xmlBuildURISafe(res, tmp_str, &tmp_str2); + if (code != 0) { xmlFree(tmp_str); xmlFree(res); - xmlC14NErrInternal("processing xml:base attribute - can't construct uri"); + if (code < 0) + xmlC14NErrMemory(ctx); + else + xmlC14NErr(ctx, cur, XML_ERR_INVALID_URI, + "processing xml:base attribute - " + "can't construct uri"); return (NULL); } @@ -1090,7 +1095,7 @@ xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) if(attr == NULL) { xmlFree(res); - xmlC14NErrInternal("processing xml:base attribute - can't construct attribute"); + xmlC14NErrMemory(ctx); return (NULL); } @@ -1145,7 +1150,7 @@ xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible) xmlAttrPtr xml_space_attr = NULL; if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { - xmlC14NErrParam("processing attributes axis"); + xmlC14NErrParam(ctx); return (-1); } @@ -1154,7 +1159,7 @@ xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible) */ list = xmlListCreate(NULL, xmlC14NAttrsCompare); if (list == NULL) { - xmlC14NErrInternal("creating attributes list"); + xmlC14NErrMemory(ctx); return (-1); } @@ -1366,7 +1371,7 @@ xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur) xmlNsPtr ns; if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { - xmlC14NErrParam("checking for relative namespaces"); + xmlC14NErrParam(ctx); return (-1); } @@ -1374,14 +1379,19 @@ xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur) while (ns != NULL) { if (xmlStrlen(ns->href) > 0) { xmlURIPtr uri; + int code; - uri = xmlParseURI((const char *) ns->href); + code = xmlParseURISafe((const char *) ns->href, &uri); if (uri == NULL) { - xmlC14NErrInternal("parsing namespace uri"); + if (code < 0) + xmlC14NErrMemory(ctx); + else + xmlC14NErr(ctx, cur, XML_ERR_INVALID_URI, + "parsing namespace uri"); return (-1); } if (xmlStrlen((const xmlChar *) uri->scheme) == 0) { - xmlC14NErrRelativeNamespace(uri->scheme); + xmlC14NErrRelativeNamespace(ctx, uri->scheme); xmlFreeURI(uri); return (-1); } @@ -1423,7 +1433,7 @@ xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) int parent_is_doc = 0; if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { - xmlC14NErrParam("processing element node"); + xmlC14NErrParam(ctx); return (-1); } @@ -1432,11 +1442,8 @@ xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) * 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"); + if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) return (-1); - } - /* * Save ns_rendered stack position @@ -1466,30 +1473,24 @@ xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) } else { ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible); } - if (ret < 0) { - xmlC14NErrInternal("processing namespaces axis"); + if (ret < 0) 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"); + if (ret < 0) return (-1); - } if (visible) { xmlOutputBufferWriteString(ctx->buf, ">"); } if (cur->children != NULL) { ret = xmlC14NProcessNodeList(ctx, cur->children); - if (ret < 0) { - xmlC14NErrInternal("processing childrens list"); + if (ret < 0) return (-1); - } } if (visible) { xmlOutputBufferWriteString(ctx->buf, "type, "processing node"); + xmlC14NErrUnknownNode(ctx, cur->type, "processing node"); return (-1); } @@ -1717,7 +1718,7 @@ xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur) int ret; if (ctx == NULL) { - xmlC14NErrParam("processing node list"); + xmlC14NErrParam(ctx); return (-1); } @@ -1739,7 +1740,7 @@ static void xmlC14NFreeCtx(xmlC14NCtxPtr ctx) { if (ctx == NULL) { - xmlC14NErrParam("freeing context"); + xmlC14NErrParam(ctx); return; } @@ -1779,7 +1780,7 @@ xmlC14NNewCtx(xmlDocPtr doc, xmlC14NCtxPtr ctx = NULL; if ((doc == NULL) || (buf == NULL)) { - xmlC14NErrParam("creating new context"); + xmlC14NErrParam(ctx); return (NULL); } @@ -1797,7 +1798,7 @@ xmlC14NNewCtx(xmlDocPtr doc, */ ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx)); if (ctx == NULL) { - xmlC14NErrMemory("creating context"); + xmlC14NErrMemory(ctx); return (NULL); } memset(ctx, 0, sizeof(xmlC14NCtx)); @@ -1815,8 +1816,7 @@ xmlC14NNewCtx(xmlDocPtr doc, ctx->ns_rendered = xmlC14NVisibleNsStackCreate(); if(ctx->ns_rendered == NULL) { - xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK, - "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n"); + xmlC14NErrMemory(ctx); xmlC14NFreeCtx(ctx); return (NULL); } @@ -1829,6 +1829,7 @@ xmlC14NNewCtx(xmlDocPtr doc, if(xmlC14NIsExclusive(ctx)) { ctx->inclusive_ns_prefixes = inclusive_ns_prefixes; } + return (ctx); } @@ -1865,7 +1866,7 @@ xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, int ret; if ((buf == NULL) || (doc == NULL)) { - xmlC14NErrParam("executing c14n"); + xmlC14NErrParam(NULL); return (-1); } @@ -1878,7 +1879,7 @@ xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, c14n_mode = (xmlC14NMode)mode; break; default: - xmlC14NErrParam("invalid mode for executing c14n"); + xmlC14NErrParam(NULL); return (-1); } @@ -1913,7 +1914,6 @@ xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, if (doc->children != NULL) { ret = xmlC14NProcessNodeList(ctx, doc->children); if (ret < 0) { - xmlC14NErrInternal("processing docs children list"); xmlC14NFreeCtx(ctx); return (-1); } @@ -1924,7 +1924,7 @@ xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, */ ret = xmlOutputBufferFlush(buf); if (ret < 0) { - xmlC14NErrInternal("flushing output buffer"); + xmlC14NErr(ctx, NULL, buf->error, "flushing output buffer"); xmlC14NFreeCtx(ctx); return (-1); } @@ -2001,7 +2001,7 @@ xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, xmlOutputBufferPtr buf; if (doc_txt_ptr == NULL) { - xmlC14NErrParam("dumping doc to memory"); + xmlC14NErrParam(NULL); return (-1); } @@ -2012,7 +2012,7 @@ xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, */ buf = xmlAllocOutputBuffer(NULL); if (buf == NULL) { - xmlC14NErrMemory("creating output buffer"); + xmlC14NErrMemory(NULL); return (-1); } @@ -2022,7 +2022,6 @@ xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, 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); } @@ -2034,7 +2033,7 @@ xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, (void) xmlOutputBufferClose(buf); if ((*doc_txt_ptr == NULL) && (ret >= 0)) { - xmlC14NErrMemory("copying canonicalized document"); + xmlC14NErrMemory(NULL); return (-1); } return (ret); @@ -2072,7 +2071,7 @@ xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, int ret; if (filename == NULL) { - xmlC14NErrParam("saving doc"); + xmlC14NErrParam(NULL); return (-1); } #ifdef LIBXML_ZLIB_ENABLED @@ -2085,7 +2084,7 @@ xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, */ buf = xmlOutputBufferCreateFilename(filename, NULL, compression); if (buf == NULL) { - xmlC14NErrInternal("creating temporary filename"); + xmlC14NErr(NULL, NULL, XML_IO_UNKNOWN, "creating temporary filename"); return (-1); } @@ -2095,7 +2094,6 @@ xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes, with_comments, buf); if (ret < 0) { - xmlC14NErrInternal("canonize document to buffer"); (void) xmlOutputBufferClose(buf); return (-1); } @@ -2107,21 +2105,6 @@ xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, 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 @@ -2150,18 +2133,23 @@ xmlC11NNormalizeString(const xmlChar * input, * allocate an translation buffer. */ buffer_size = 1000; - buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); - if (buffer == NULL) { - xmlC14NErrMemory("allocating buffer"); + buffer = (xmlChar *) xmlMallocAtomic(buffer_size); + if (buffer == NULL) return (NULL); - } out = buffer; while (*cur != '\0') { if ((out - buffer) > (buffer_size - 10)) { + xmlChar *tmp; int indx = out - buffer; - growBufferReentrant(); + buffer_size *= 2; + tmp = xmlRealloc(buffer, buffer_size); + if (tmp == NULL) { + xmlFree(buffer); + return(NULL); + } + buffer = tmp; out = &buffer[indx]; } @@ -2223,6 +2211,5 @@ xmlC11NNormalizeString(const xmlChar * input, *out = 0; return (buffer); } -#endif /* LIBXML_OUTPUT_ENABLED */ #endif /* LIBXML_C14N_ENABLED */ diff --git a/catalog.c b/catalog.c index b7837e3da75..27af95f47ab 100644 --- a/catalog.c +++ b/catalog.c @@ -16,16 +16,16 @@ #include "libxml.h" #ifdef LIBXML_CATALOG_ENABLED +#include #include #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include +#elif defined (_WIN32) +#include #endif #ifdef HAVE_FCNTL_H #include @@ -37,9 +37,9 @@ #include #include #include -#include -#include "buf.h" +#include "private/buf.h" +#include "private/error.h" #define MAX_DELEGATE 50 #define MAX_CATAL_DEPTH 50 @@ -50,21 +50,6 @@ # define PATH_SEPARATOR ':' #endif -/** - * TODO: - * - * macro to flag unimplemented blocks - * XML_CATALOG_PREFER user env to select between system/public preferred - * option. C.f. Richard Tobin - *> 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 @@ -74,15 +59,6 @@ #define XML_SGML_DEFAULT_CATALOG "file://" SYSCONFDIR "/sgml/catalog" #endif -#if defined(_WIN32) && defined(_MSC_VER) -#undef XML_XML_DEFAULT_CATALOG -static char XML_XML_DEFAULT_CATALOG[256] = "file://" SYSCONFDIR "/xml/catalog"; -#if !defined(_WINDOWS_) -void* __stdcall GetModuleHandleA(const char*); -unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long); -#endif -#endif - static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID); static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename); @@ -213,12 +189,9 @@ static int xmlCatalogInitialized = 0; * Handle an out of memory condition */ static void -xmlCatalogErrMemory(const char *extra) +xmlCatalogErrMemory(void) { - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_CATALOG, NULL); } /** @@ -235,11 +208,15 @@ xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error, const char *msg, const xmlChar *str1, const xmlChar *str2, const xmlChar *str3) { - __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, 0, - msg, str1, str2, str3); + int res; + + res = __xmlRaiseError(NULL, NULL, NULL, catal, node, + XML_FROM_CATALOG, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, + (const char *) str3, 0, 0, + msg, str1, str2, str3); + if (res < 0) + xmlCatalogErrMemory(); } @@ -271,7 +248,7 @@ xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); if (ret == NULL) { - xmlCatalogErrMemory("allocating catalog entry"); + xmlCatalogErrMemory(); return(NULL); } ret->next = NULL; @@ -329,13 +306,13 @@ xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { if (xmlDebugCatalogs) { if (ret->name != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry %s\n", ret->name); else if (ret->value != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry %s\n", ret->value); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry\n"); } @@ -409,7 +386,7 @@ xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) { ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog)); if (ret == NULL) { - xmlCatalogErrMemory("allocating catalog"); + xmlCatalogErrMemory(); return(NULL); } memset(ret, 0, sizeof(xmlCatalog)); @@ -793,7 +770,7 @@ xmlConvertSGMLCatalog(xmlCatalogPtr catal) { return(-1); if (xmlDebugCatalogs) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Converting SGML catalog to XML\n"); } xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal); @@ -885,17 +862,12 @@ 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 + xmlCatalogErrMemory(); return(NULL); } @@ -917,10 +889,7 @@ xmlParseCatalogFile(const char *filename) { xmlBufResetInput(buf->buffer, inputStream); inputPush(ctxt, inputStream); - if (ctxt->directory == NULL) - directory = xmlParserGetDirectory(filename); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; + ctxt->valid = 0; ctxt->validate = 0; ctxt->loadsubset = 0; @@ -991,7 +960,7 @@ xmlLoadFileContent(const char *filename) #endif content = (xmlChar*)xmlMallocAtomic(size + 10); if (content == NULL) { - xmlCatalogErrMemory("allocating catalog data"); + xmlCatalogErrMemory(); #ifdef HAVE_STAT close(fd); #else @@ -1176,10 +1145,10 @@ xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, if (URL != NULL) { if (xmlDebugCatalogs > 1) { if (nameValue != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s: '%s' '%s'\n", name, nameValue, URL); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s: '%s'\n", name, URL); } ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup); @@ -1348,13 +1317,13 @@ xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { doc = xmlParseCatalogFile((const char *) filename); if (doc == NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Failed to parse catalog %s\n", filename); return(NULL); } if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%d Parsing catalog %s\n", xmlGetThreadId(), filename); cur = xmlDocGetRootElement(doc); @@ -1427,7 +1396,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { xmlHashLookup(xmlCatalogXMLFiles, catal->URL); if (doc != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s in file hash\n", catal->URL); if (catal->type == XML_CATA_CATALOG) @@ -1439,7 +1408,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { return(0); } if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s not found in file hash\n", catal->URL); } @@ -1466,7 +1435,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { xmlCatalogXMLFiles = xmlHashCreate(10); if (xmlCatalogXMLFiles != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s added to file hash\n", catal->URL); xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); } @@ -1512,7 +1481,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, typ = xmlGetXMLCatalogEntryType(type); if (typ == XML_CATA_NONE) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Failed to add unknown element %s to catalog\n", type); return(-1); } @@ -1526,7 +1495,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, if ((orig != NULL) && (cur->type == typ) && (xmlStrEqual(orig, cur->name))) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Updating element %s to catalog\n", type); if (cur->value != NULL) xmlFree(cur->value); @@ -1542,7 +1511,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, } } if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Adding element %s to catalog\n", type); if (cur == NULL) catal->children = xmlNewCatalogEntry(typ, orig, replace, @@ -1594,10 +1563,10 @@ xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { (xmlStrEqual(value, cur->value))) { if (xmlDebugCatalogs) { if (cur->name != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Removing element %s from catalog\n", cur->name); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Removing element %s from catalog\n", cur->value); } cur->type = XML_CATA_REMOVED; @@ -1653,7 +1622,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, case XML_CATA_SYSTEM: if (xmlStrEqual(sysID, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found system match %s, using %s\n", cur->name, cur->URL); catal->depth--; @@ -1682,7 +1651,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (rewrite != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Using rewriting rule %s\n", rewrite->name); ret = xmlStrdup(rewrite->URL); if (ret != NULL) @@ -1717,7 +1686,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying system delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolve( cur->children, NULL, sysID); @@ -1747,7 +1716,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, case XML_CATA_PUBLIC: if (xmlStrEqual(pubID, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found public match %s\n", cur->name); catal->depth--; return(xmlStrdup(cur->URL)); @@ -1796,7 +1765,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying public delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolve( cur->children, pubID, NULL); @@ -1886,7 +1855,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { case XML_CATA_URI: if (xmlStrEqual(URI, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found URI match %s\n", cur->name); return(xmlStrdup(cur->URL)); } @@ -1913,7 +1882,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { } if (rewrite != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Using rewriting rule %s\n", rewrite->name); ret = xmlStrdup(rewrite->URL); if (ret != NULL) @@ -1948,7 +1917,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying URI delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolveURI( cur->children, URI); @@ -2017,10 +1986,10 @@ xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, urnID = xmlCatalogUnWrapURN(pubID); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Public URN ID %s expanded to NULL\n", pubID); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Public URN ID expanded to %s\n", urnID); } ret = xmlCatalogListXMLResolve(catal, urnID, sysID); @@ -2034,10 +2003,10 @@ xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, urnID = xmlCatalogUnWrapURN(sysID); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "System URN ID %s expanded to NULL\n", sysID); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "System URN ID expanded to %s\n", urnID); } if (pubID == NULL) @@ -2101,10 +2070,10 @@ xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { urnID = xmlCatalogUnWrapURN(URI); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "URN ID %s expanded to NULL\n", URI); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "URN ID expanded to %s\n", urnID); } ret = xmlCatalogListXMLResolve(catal, urnID, NULL); @@ -2177,7 +2146,6 @@ xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { int len = 0; int size = 50; xmlChar stop; - int count = 0; *id = NULL; @@ -2190,9 +2158,9 @@ xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { } else { stop = ' '; } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlCatalogErrMemory("allocating public ID"); + xmlCatalogErrMemory(); return(NULL); } while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) { @@ -2202,16 +2170,15 @@ xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { break; if (len + 1 >= size) { size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlCatalogErrMemory("allocating public ID"); + xmlCatalogErrMemory(); xmlFree(buf); return(NULL); } buf = tmp; } buf[len++] = *cur; - count++; NEXT; } buf[len] = 0; @@ -2785,7 +2752,7 @@ xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { return(NULL); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve sysID %s\n", sysID); if (catal->type == XML_XML_CATALOG_TYPE) { @@ -2820,7 +2787,7 @@ xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { return(NULL); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve pubID %s\n", pubID); if (catal->type == XML_XML_CATALOG_TYPE) { @@ -2859,13 +2826,13 @@ xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID, if (xmlDebugCatalogs) { if ((pubID != NULL) && (sysID != NULL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: pubID %s sysID %s\n", pubID, sysID); } else if (pubID != NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: pubID %s\n", pubID); } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: sysID %s\n", sysID); } } @@ -2902,7 +2869,7 @@ xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { return(NULL); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve URI %s\n", URI); if (catal->type == XML_XML_CATALOG_TYPE) { @@ -2975,6 +2942,8 @@ xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, if (catal->sgml == NULL) catal->sgml = xmlHashCreate(10); res = xmlHashAddEntry(catal->sgml, orig, entry); + if (res < 0) + xmlFreeCatalogEntry(entry, NULL); } } return (res); @@ -3117,35 +3086,7 @@ xmlInitializeCatalog(void) { catalogs = (const char *) getenv("XML_CATALOG_FILES"); if (catalogs == NULL) -#if defined(_WIN32) && defined(_MSC_VER) - { - void* hmodule; - hmodule = GetModuleHandleA("libxml2.dll"); - if (hmodule == NULL) - hmodule = GetModuleHandleA(NULL); - if (hmodule != NULL) { - char buf[256]; - unsigned long len = GetModuleFileNameA(hmodule, buf, 255); - if (len != 0) { - char* p = &(buf[len]); - while (*p != '\\' && p > buf) - p--; - if (p != buf) { - xmlChar* uri; - strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf)); - uri = xmlCanonicPath((const xmlChar*)buf); - if (uri != NULL) { - strncpy(XML_XML_DEFAULT_CATALOG, uri, 255); - xmlFree(uri); - } - } - } - } - catalogs = XML_XML_DEFAULT_CATALOG; - } -#else catalogs = XML_XML_DEFAULT_CATALOG; -#endif catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); @@ -3277,7 +3218,7 @@ xmlCatalogCleanup(void) { xmlRMutexLock(xmlCatalogMutex); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Catalogs cleanup\n"); if (xmlCatalogXMLFiles != NULL) xmlHashFree(xmlCatalogXMLFiles, xmlFreeCatalogHashEntryList); @@ -3505,19 +3446,19 @@ xmlCatalogSetDefaults(xmlCatalogAllow allow) { if (xmlDebugCatalogs) { switch (allow) { case XML_CATA_ALLOW_NONE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Disabling catalog usage\n"); break; case XML_CATA_ALLOW_GLOBAL: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing only global catalogs\n"); break; case XML_CATA_ALLOW_DOCUMENT: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing only catalogs from the document\n"); break; case XML_CATA_ALLOW_ALL: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing all catalogs\n"); break; } @@ -3545,11 +3486,11 @@ xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { if (xmlDebugCatalogs) { switch (prefer) { case XML_CATA_PREFER_PUBLIC: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Setting catalog preference to PUBLIC\n"); break; case XML_CATA_PREFER_SYSTEM: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Setting catalog preference to SYSTEM\n"); break; default: @@ -3625,7 +3566,7 @@ xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { return(catalogs); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Adding document catalog %s\n", URL); add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, @@ -3669,13 +3610,13 @@ xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, if (xmlDebugCatalogs) { if ((pubID != NULL) && (sysID != NULL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: pubID %s sysID %s\n", pubID, sysID); } else if (pubID != NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: pubID %s\n", pubID); } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: sysID %s\n", sysID); } } @@ -3712,7 +3653,7 @@ xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { return(NULL); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve URI %s\n", URI); catal = (xmlCatalogEntryPtr) catalogs; @@ -3748,7 +3689,7 @@ xmlCatalogGetSystem(const xmlChar *sysID) { xmlInitializeCatalog(); if (msg == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Use of deprecated xmlCatalogGetSystem() call\n"); msg++; } @@ -3792,7 +3733,7 @@ xmlCatalogGetPublic(const xmlChar *pubID) { xmlInitializeCatalog(); if (msg == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Use of deprecated xmlCatalogGetPublic() call\n"); msg++; } diff --git a/chvalid.c b/chvalid.c index f4fa44acbb8..fb2c715a875 100644 --- a/chvalid.c +++ b/chvalid.c @@ -14,6 +14,8 @@ #include "libxml.h" #include +#include + /* * The initial tables ({func_name}_tab) are used to validate whether a * single-byte character is within the specified group. Each table diff --git a/config.h.cmake.in b/config.h.cmake.in index 1f8be710f53..2f4aeba3b49 100644 --- a/config.h.cmake.in +++ b/config.h.cmake.in @@ -1,20 +1,11 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if __attribute__((destructor)) is accepted */ +/* A form that will not confuse apibuild.py */ #cmakedefine ATTRIBUTE_DESTRUCTOR @ATTRIBUTE_DESTRUCTOR@ -/* Type cast for the gethostbyname() argument */ -#cmakedefine GETHOSTBYNAME_ARG_CAST @GETHOSTBYNAME_ARG_CAST@ - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_INET_H 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_ARPA_NAMESER_H 1 - -/* Whether struct sockaddr::__ss_family exists */ -#cmakedefine HAVE_BROKEN_SS_FAMILY 1 +/* Define if __attribute__((destructor)) is accepted */ +#cmakedefine HAVE_ATTRIBUTE_DESTRUCTOR 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H 1 @@ -31,18 +22,12 @@ /* Define to 1 if you have the `ftime' function. */ #cmakedefine HAVE_FTIME 1 -/* Define if getaddrinfo is there */ -#cmakedefine HAVE_GETADDRINFO 1 +/* Define to 1 if you have the `getentropy' function. */ +#cmakedefine HAVE_GETENTROPY 1 /* Define to 1 if you have the `gettimeofday' function. */ #cmakedefine HAVE_GETTIMEOFDAY 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `isascii' function. */ -#cmakedefine HAVE_ISASCII 1 - /* Define if history library is there (-lhistory) */ #cmakedefine HAVE_LIBHISTORY 1 @@ -69,18 +54,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_POLL_H 1 -/* Define if is there */ +/* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTHREAD_H 1 -/* Define to 1 if you have the `putenv' function. */ -#cmakedefine HAVE_PUTENV 1 - -/* Define to 1 if you have the `rand_r' function. */ -#cmakedefine HAVE_RAND_R 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_RESOLV_H 1 - /* Have shl_load based dso */ #cmakedefine HAVE_SHLLOAD 1 @@ -93,6 +69,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_MMAN_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RANDOM_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 @@ -108,68 +87,20 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SYS_TYPES_H 1 - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 -/* Whether va_copy() is available */ -#cmakedefine HAVE_VA_COPY 1 - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ZLIB_H 1 -/* Whether __va_copy() is available */ -#cmakedefine HAVE___VA_COPY 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#cmakedefine LT_OBJDIR "@LT_OBJDIR@" - -/* Name of package */ -#define PACKAGE "@PACKAGE@" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "@PACKAGE_NAME@" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "@PACKAGE_STRING@" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "@PACKAGE_TARNAME@" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "@PACKAGE_URL@" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "@PACKAGE_VERSION@" - -/* Type cast for the send() function 2nd arg */ -#cmakedefine SEND_ARG2_CAST @SEND_ARG2_CAST@ - /* Support for IPv6 */ #cmakedefine SUPPORT_IP6 1 -/* Define if va_list is an array type */ -#cmakedefine VA_LIST_IS_ARRAY 1 - /* Version number of package */ #cmakedefine VERSION "@VERSION@" /* Determine what socket length (socklen_t) data type is */ #cmakedefine XML_SOCKLEN_T @XML_SOCKLEN_T@ -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -#cmakedefine _UINT32_T @_UINT32_T@ - -/* ss_family is not defined here, use __ss_family instead */ -#cmakedefine ss_family @ss_family@ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -#cmakedefine uint32_t @uint32_t@ +/* TLS specifier */ +#cmakedefine XML_THREAD_LOCAL @XML_THREAD_LOCAL@ diff --git a/configure.ac b/configure.ac index 4d8e0cb49b1..36e74e4e967 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) m4_define([MAJOR_VERSION], 2) -m4_define([MINOR_VERSION], 10) -m4_define([MICRO_VERSION], 1) +m4_define([MINOR_VERSION], 13) +m4_define([MICRO_VERSION], 4) AC_INIT([libxml2],[MAJOR_VERSION.MINOR_VERSION.MICRO_VERSION]) AC_CONFIG_SRCDIR([entities.c]) @@ -21,7 +21,7 @@ LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML LIBXML_VERSION_NUMBER=`expr $LIBXML_MAJOR_VERSION \* 10000 + $LIBXML_MINOR_VERSION \* 100 + $LIBXML_MICRO_VERSION` if test -d .git ; then - extra=`git describe 2>/dev/null | sed 's+LIBXML[[0-9.]]*-++'` + extra=`git describe 2>/dev/null` echo extra=$extra if test "$extra" != "" then @@ -39,7 +39,7 @@ AC_SUBST(LIBXML_VERSION_EXTRA) VERSION=${LIBXML_VERSION} -AM_INIT_AUTOMAKE([1.15 foreign no-dist-gzip dist-xz]) +AM_INIT_AUTOMAKE([1.16.3 foreign no-dist-gzip dist-xz]) AM_MAINTAINER_MODE([enable]) AM_SILENT_RULES([yes]) @@ -48,542 +48,384 @@ AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MKDIR_P -AC_PROG_CPP -AC_PATH_PROG(MV, mv, /bin/mv) AC_PATH_PROG(TAR, tar, /bin/tar) AC_PATH_PROG(PERL, perl, /usr/bin/perl) AC_PATH_PROG(WGET, wget, /usr/bin/wget) -AC_PATH_PROG(XMLLINT, xmllint, /usr/bin/xmllint) AC_PATH_PROG(XSLTPROC, xsltproc, /usr/bin/xsltproc) PKG_PROG_PKG_CONFIG LT_INIT([disable-static]) LT_LIB_M -dnl -dnl if the system support linker version scripts for symbol versioning -dnl then add it -dnl -VERSION_SCRIPT_FLAGS= -# lt_cv_prog_gnu_ld is from libtool 2.+ -if test "$lt_cv_prog_gnu_ld" = yes; then - VERSION_SCRIPT_FLAGS=-Wl,--version-script= -else - case $host in - *-*-sunos*) VERSION_SCRIPT_FLAGS="-Wl,-M -Wl,";; - esac -fi -AC_SUBST(VERSION_SCRIPT_FLAGS) -AM_CONDITIONAL([USE_VERSION_SCRIPT], [test -n "$VERSION_SCRIPT_FLAGS"]) - dnl dnl We process the AC_ARG_WITH first so that later we can modify dnl some of them to try to prevent impossible combinations. This dnl also allows up so alphabetize the choices dnl -dnl -dnl zlib option might change flags, so we save them initially -dnl -_cppflags="${CPPFLAGS}" -_libs="${LIBS}" - AC_ARG_WITH(c14n, -[ --with-c14n add the Canonicalization support (on)]) +[ --with-c14n Canonical XML 1.0 support (on)]) AC_ARG_WITH(catalog, -[ --with-catalog add the Catalog support (on)]) +[ --with-catalog XML Catalogs support (on)]) AC_ARG_WITH(debug, -[ --with-debug add the debugging module (on)]) -AC_ARG_WITH(fexceptions, -[ --with-fexceptions add GCC flag -fexceptions for C++ exceptions (off)]) +[ --with-debug debugging module and shell (on)]) AC_ARG_WITH(ftp, -[ --with-ftp add the FTP support (off)]) +[ --with-ftp FTP support (off)]) AC_ARG_WITH(history, -[ --with-history add history support to xmllint shell(off)]) +[ --with-history history support for shell (off)]) +AC_ARG_WITH(readline, +[ --with-readline[[=DIR]] use readline in DIR (for shell history)]) AC_ARG_WITH(html, -[ --with-html add the HTML support (on)]) +[ --with-html HTML parser (on)]) AC_ARG_WITH(http, -[ --with-http add the HTTP support (on)]) +[ --with-http HTTP support (off)]) AC_ARG_WITH(iconv, -[ --with-iconv[[=DIR]] add ICONV support (on)]) +[ --with-iconv[[=DIR]] iconv support (on)]) AC_ARG_WITH(icu, -[ --with-icu add ICU support (off)]) +[ --with-icu ICU support (off)]) AC_ARG_WITH(iso8859x, -[ --with-iso8859x add ISO8859X support if no iconv (on)]) -AC_ARG_WITH(legacy, -[ --with-legacy add deprecated APIs for compatibility (off)]) -AC_ARG_WITH(mem_debug, -[ --with-mem-debug add the memory debugging module (off)]) -AC_ARG_WITH(minimum, -[ --with-minimum build a minimally sized library (off)]) +[ --with-iso8859x ISO-8859-X support if no iconv (on)]) +AC_ARG_WITH(lzma, +[ --with-lzma[[=DIR]] use liblzma in DIR (off)]) +AC_ARG_WITH(modules, +[ --with-modules dynamic modules support (on)]) AC_ARG_WITH(output, -[ --with-output add the serialization support (on)]) +[ --with-output serialization support (on)]) AC_ARG_WITH(pattern, -[ --with-pattern add the xmlPattern selection interface (on)]) +[ --with-pattern xmlPattern selection interface (on)]) AC_ARG_WITH(push, -[ --with-push add the PUSH parser interfaces (on)]) +[ --with-push push parser interfaces (on)]) AC_ARG_WITH(python, -[ --with-python build Python bindings (on)]) +[ --with-python Python bindings (on)]) AC_ARG_WITH(reader, -[ --with-reader add the xmlReader parsing interface (on)]) -AC_ARG_WITH(readline, -[ --with-readline=DIR use readline in DIR],[ - if test "$withval" != "no" && test "$withval" != "yes"; then - RDL_DIR=$withval - CPPFLAGS="${CPPFLAGS} -I$withval/include" - LDFLAGS="${LDFLAGS} -L$withval/lib" - fi -]) +[ --with-reader xmlReader parsing interface (on)]) AC_ARG_WITH(regexps, -[ --with-regexps add Regular Expressions support (on)]) -AC_ARG_WITH(run_debug, -[ --with-run-debug add the runtime debugging module (off)]) +[ --with-regexps regular expressions support (on)]) AC_ARG_WITH(sax1, -[ --with-sax1 add the older SAX1 interface (on)]) +[ --with-sax1 older SAX1 interface (on)]) AC_ARG_WITH(schemas, -[ --with-schemas add Relax-NG and Schemas support (on)]) +[ --with-schemas XML Schemas 1.0 and RELAX NG support (on)]) AC_ARG_WITH(schematron, -[ --with-schematron add Schematron support (on)]) +[ --with-schematron Schematron support (on)]) AC_ARG_WITH(threads, -[ --with-threads add multithread support(on)]) +[ --with-threads multithreading support (on)]) AC_ARG_WITH(thread-alloc, -[ --with-thread-alloc add per-thread memory(off)]) +[ --with-thread-alloc per-thread malloc hooks (off)]) AC_ARG_WITH(tree, -[ --with-tree add the DOM like tree manipulation APIs (on)]) +[ --with-tree DOM like tree manipulation APIs (on)]) AC_ARG_WITH(valid, -[ --with-valid add the DTD validation support (on)]) +[ --with-valid DTD validation support (on)]) AC_ARG_WITH(writer, -[ --with-writer add the xmlWriter saving interface (on)]) +[ --with-writer xmlWriter serialization interface (on)]) AC_ARG_WITH(xinclude, -[ --with-xinclude add the XInclude support (on)]) +[ --with-xinclude XInclude 1.0 support (on)]) AC_ARG_WITH(xpath, -[ --with-xpath add the XPATH support (on)]) +[ --with-xpath XPath 1.0 support (on)]) AC_ARG_WITH(xptr, -[ --with-xptr add the XPointer support (on)]) +[ --with-xptr XPointer support (on)]) AC_ARG_WITH(xptr-locs, -[ --with-xptr-locs add support for XPointer locations (off)]) -AC_ARG_WITH(modules, -[ --with-modules add the dynamic modules support (on)]) +[ --with-xptr-locs XPointer ranges and points (off)]) AC_ARG_WITH(zlib, -[ --with-zlib[[=DIR]] use libz in DIR],[ - if test "$withval" != "no" && test "$withval" != "yes"; then - Z_DIR=$withval - CPPFLAGS="${CPPFLAGS} -I$withval/include" - LDFLAGS="${LDFLAGS} -L$withval/lib" - fi -]) -AC_ARG_WITH(lzma, -[ --with-lzma[[=DIR]] use liblzma in DIR],[ - if test "$withval" != "no" && test "$withval" != "yes"; then - LZMA_DIR=$withval - CPPFLAGS="${CPPFLAGS} -I$withval/include" - LDFLAGS="${LDFLAGS} -L$withval/lib" - fi -]) -AC_ARG_WITH(coverage, -[ --with-coverage build for code coverage with GCC (off)]) +[ --with-zlib[[=DIR]] use libz in DIR (off)]) + +AC_ARG_WITH(minimum, +[ --with-minimum build a minimally sized library (off)]) +AC_ARG_WITH(legacy, +[ --with-legacy maximum ABI compatibility (off)]) + +AC_ARG_WITH(tls, +[ --with-tls thread-local storage (off)]) dnl -dnl hard dependencies on options -dnl -if test "$with_schemas" = "yes" -then - with_pattern=yes - with_regexps=yes -fi -if test "$with_schematron" = "yes" -then - with_pattern=yes - with_tree=yes - with_xpath=yes -fi -if test "$with_reader" = "yes" -then - with_push=yes -fi -if test "$with_xptr_locs" = "yes" -then - with_xptr=yes -fi -if test "$with_xptr" = "yes" -then - with_xpath=yes -fi -dnl -dnl option to build a minimal libxml2 library +dnl Legacy defaults dnl -if test "$with_minimum" = "yes" -then - echo "Configuring for a minimal library" - if test "$with_c14n" = "" - then - with_c14n=no - fi - if test "$with_catalog" = "" - then - with_catalog=no - fi - echo So far so good! - if test "$with_debug" = "" - then - with_debug=no - fi - if test "$with_fexceptions" = "" - then - with_fexceptions=no - fi - if test "$with_history" = "" - then - with_history=no - fi - if test "$with_html" = "" - then - with_html=no +if test "$with_legacy" = "yes"; then + if test "$with_http" = ""; then + with_http=yes fi - if test "$with_http" = "" - then - with_http=no - fi - if test "$with_iconv" = "" - then - with_iconv=no - fi - if test "$with_iso8859x" = "" - then - with_iso8859x=no - fi - if test "$with_mem_debug" = "" - then - with_mem_debug=no - fi - if test "$with_output" = "" - then - with_output=no - fi - if test "$with_pattern" = "" - then - with_pattern=no - fi - if test "$with_push" = "" - then - with_push=no - fi - if test "$with_python" = "" - then - with_python=no - fi - if test "$with_reader" = "" - then - with_reader=no + if test "$with_lzma" = ""; then + with_lzma=yes fi - if test "$with_readline" = "" - then - with_readline=no + if test "$with_zlib" = ""; then + with_zlib=yes fi - if test "$with_regexps" = "" - then - with_regexps=no +fi + +dnl +dnl hard dependencies on options +dnl +if test "$with_c14n" = "yes"; then + if test "$with_output" = "no"; then + echo WARNING: --with-c14n overrides --without-output fi - if test "$with_run_debug" = "" - then - with_run_debug=no + with_output=yes + if test "$with_xpath" = "no"; then + echo WARNING: --with-c14n overrides --without-xpath fi - if test "$with_sax1" = "" - then - with_sax1=no + with_xpath=yes +fi +if test "$with_schemas" = "yes"; then + if test "$with_pattern" = "no"; then + echo WARNING: --with-schemas overrides --without-pattern fi - if test "$with_schemas" = "" - then - with_schemas=no + with_pattern=yes + if test "$with_regexps" = "no"; then + echo WARNING: --with-schemas overrides --without-regexps fi - if test "$with_schematron" = "" - then - with_schematron=no + with_regexps=yes +fi +if test "$with_schematron" = "yes"; then + if test "$with_pattern" = "no"; then + echo WARNING: --with-schematron overrides --without-pattern fi - if test "$with_threads" = "" - then - with_threads=no + with_pattern=yes + if test "$with_tree" = "no"; then + echo WARNING: --with-schematron overrides --without-tree fi - if test "$with_thread_alloc" = "" - then - with_thread_alloc=no - fi - if test "$with_tree" = "" - then - with_tree=no + with_tree=yes + if test "$with_xpath" = "no"; then + echo WARNING: --with-schematron overrides --without-xpath fi - if test "$with_valid" = "" - then - with_valid=no + with_xpath=yes +fi +if test "$with_reader" = "yes"; then + if test "$with_push" = "no"; then + echo WARNING: --with-reader overrides --without-push fi - if test "$with_writer" = "" - then - with_writer=no + with_push=yes + if test "$with_tree" = "no"; then + echo WARNING: --with-reader overrides --without-tree fi - if test "$with_xinclude" = "" - then - with_xinclude=no + with_tree=yes +fi +if test "$with_writer" = "yes"; then + if test "$with_output" = "no"; then + echo WARNING: --with-writer overrides --without-output fi - if test "$with_xpath" = "" - then - with_xpath=no + with_output=yes + if test "$with_push" = "no"; then + echo WARNING: --with-writer overrides --without-push fi - if test "$with_xptr" = "" - then - with_xptr=no + with_push=yes +fi +if test "$with_xinclude" = "yes"; then + if test "$with_xpath" = "no"; then + echo WARNING: --with-xinclude overrides --without-xpath fi - if test "$with_zlib" = "" - then - with_zlib=no + with_xpath=yes +fi +if test "$with_xptr_locs" = "yes"; then + if test "$with_xptr" = "no"; then + echo WARNING: --with-xptr-locs overrides --without-xptr fi - if test "$with_modules" = "" - then - with_modules=no + with_xptr=yes +fi +if test "$with_xptr" = "yes"; then + if test "$with_xpath" = "no"; then + echo WARNING: --with-xptr overrides --without-xpath fi + with_xpath=yes fi -echo Checking zlib - -dnl Checks for zlib library. - -WITH_ZLIB=0 -if test "$with_zlib" = "no"; then - echo "Disabling zlib compression support" +if test "$with_minimum" = "yes"; then + dnl + dnl option to build a minimal libxml2 library + dnl + echo "Configuring for a minimal library" + test "$with_c14n" = "" && with_c14n=no + test "$with_catalog" = "" && with_catalog=no + test "$with_debug" = "" && with_debug=no + test "$with_history" = "" && with_history=no + test "$with_html" = "" && with_html=no + test "$with_http" = "" && with_http=no + test "$with_iconv" = "" && with_iconv=no + test "$with_iso8859x" = "" && with_iso8859x=no + test "$with_lzma" = "" && with_lzma=no + test "$with_output" = "" && with_output=no + test "$with_pattern" = "" && with_pattern=no + test "$with_push" = "" && with_push=no + test "$with_python" = "" && with_python=no + test "$with_reader" = "" && with_reader=no + test "$with_readline" = "" && with_readline=no + test "$with_regexps" = "" && with_regexps=no + test "$with_sax1" = "" && with_sax1=no + test "$with_schemas" = "" && with_schemas=no + test "$with_schematron" = "" && with_schematron=no + test "$with_threads" = "" && with_threads=no + test "$with_thread_alloc" = "" && with_thread_alloc=no + test "$with_tree" = "" && with_tree=no + test "$with_valid" = "" && with_valid=no + test "$with_writer" = "" && with_writer=no + test "$with_xinclude" = "" && with_xinclude=no + test "$with_xpath" = "" && with_xpath=no + test "$with_xptr" = "" && with_xptr=no + test "$with_zlib" = "" && with_zlib=no + test "$with_modules" = "" && with_modules=no else - # Don't run pkg-config if with_zlib contains a path. - if test "x$Z_DIR" = "x"; then - # Try pkg-config first so that static linking works. - PKG_CHECK_MODULES([Z],[zlib], - [WITH_ZLIB=1], - [:]) + dnl + dnl Disable dependent modules + dnl + if test "$with_output" = "no"; then + with_c14n=no + with_writer=no fi - - if test "$WITH_ZLIB" = "0"; then - AC_CHECK_HEADERS(zlib.h, - AC_CHECK_LIB(z, gzread,[ - WITH_ZLIB=1 - if test "x${Z_DIR}" != "x"; then - Z_CFLAGS="-I${Z_DIR}/include" - Z_LIBS="-L${Z_DIR}/lib -lz" - [case ${host} in - *-*-solaris*) - Z_LIBS="-L${Z_DIR}/lib -R${Z_DIR}/lib -lz" - ;; - esac] - else - Z_LIBS="-lz" - fi]) - ) + if test "$with_pattern" = "no"; then + with_schemas=no + with_schematron=no fi -fi - -AC_SUBST(Z_CFLAGS) -AC_SUBST(Z_LIBS) -AC_SUBST(WITH_ZLIB) - -echo Checking lzma - -dnl Checks for lzma library. - -WITH_LZMA=0 -if test "$with_lzma" = "no"; then - echo "Disabling lzma compression support" -else - # Don't run pkg-config if with_lzma contains a path. - if test "x$LZMA_DIR" = "x"; then - # Try pkg-config first so that static linking works. - PKG_CHECK_MODULES([LZMA],[liblzma], - [WITH_LZMA=1], - [:]) + if test "$with_push" = "no"; then + with_reader=no + with_writer=no fi - - # If pkg-config failed, fall back to AC_CHECK_LIB. This - # will not pick up the necessary LIBS flags for liblzma's - # private dependencies, though, so static linking may fail. - if test "$WITH_LZMA" = "0"; then - AC_CHECK_HEADERS(lzma.h, - AC_CHECK_LIB(lzma, lzma_code,[ - WITH_LZMA=1 - if test "x${LZMA_DIR}" != "x"; then - LZMA_CFLAGS="-I${LZMA_DIR}/include" - LZMA_LIBS="-L${LZMA_DIR}/lib -llzma" - else - LZMA_LIBS="-llzma" - fi]) - ) + if test "$with_regexps" = "no"; then + with_schemas=no + fi + if test "$with_tree" = "no"; then + with_reader=no + with_schematron=no + fi + if test "$with_xpath" = "no"; then + with_c14n=no + with_schematron=no + with_xinclude=no + with_xptr=no fi fi -AC_SUBST(LZMA_CFLAGS) -AC_SUBST(LZMA_LIBS) -AC_SUBST(WITH_LZMA) - -CPPFLAGS=${_cppflags} -LIBS=${_libs} - -echo Checking headers +XML_PRIVATE_LIBS= +XML_PRIVATE_CFLAGS= +XML_PC_LIBS= +XML_PC_REQUIRES= +dnl dnl Checks for header files. -AC_CHECK_HEADERS([fcntl.h]) -AC_CHECK_HEADERS([unistd.h]) -AC_CHECK_HEADERS([sys/stat.h]) -AC_CHECK_HEADERS([sys/types.h]) +dnl AC_CHECK_HEADERS([stdint.h]) -AC_CHECK_HEADERS([inttypes.h]) -AC_CHECK_HEADERS([sys/socket.h], [], [], -[#if HAVE_SYS_TYPES_H -# include -# endif -]) -AC_CHECK_HEADERS([netinet/in.h], [], [], -[#if HAVE_SYS_TYPES_H -# include -# endif -]) -AC_CHECK_HEADERS([arpa/inet.h], [], [], -[#if HAVE_SYS_TYPES_H -# include -# endif -#if HAVE_ARPA_INET_H -# include -# endif -]) -AC_CHECK_HEADERS([netdb.h]) -AC_CHECK_HEADERS([sys/time.h]) -AC_CHECK_HEADERS([sys/select.h]) -AC_CHECK_HEADERS([poll.h]) +AC_CHECK_HEADERS([fcntl.h unistd.h sys/stat.h]) AC_CHECK_HEADERS([sys/mman.h]) -AC_CHECK_HEADERS([sys/timeb.h]) -AC_CHECK_HEADERS([arpa/nameser.h], [], [], -[#if HAVE_SYS_TYPES_H -# include -# endif -]) -AC_CHECK_HEADERS([resolv.h], [], [], -[#if HAVE_SYS_TYPES_H -# include -# endif -#if HAVE_NETINET_IN_H -# include -# endif -#if HAVE_ARPA_NAMESER_H -# include -# endif -]) -AC_CHECK_HEADERS([dl.h]) -AC_CHECK_HEADERS([dlfcn.h]) - - -echo Checking types - -AC_TYPE_UINT32_T - - -echo Checking libraries +AC_CHECK_HEADERS([sys/time.h sys/timeb.h]) +AC_CHECK_HEADERS([sys/random.h]) +AC_CHECK_HEADERS([dl.h dlfcn.h]) +AC_CHECK_HEADERS([glob.h]) +AM_CONDITIONAL(WITH_GLOB, test "$ac_cv_header_glob_h" = "yes") dnl Checks for library functions. -AC_CHECK_FUNCS(gettimeofday ftime) -AC_CHECK_FUNCS(stat) -AC_CHECK_FUNCS(rand_r) -AC_CHECK_FUNCS(isascii mmap munmap putenv) +AC_CHECK_FUNCS([gettimeofday ftime stat mmap munmap]) AH_VERBATIM([HAVE_MUNMAP_AFTER],[/* mmap() is no good without munmap() */ #if defined(HAVE_MMAP) && !defined(HAVE_MUNMAP) # undef /**/ HAVE_MMAP #endif]) -dnl Checking for va_copy availability -AC_MSG_CHECKING([for va_copy]) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -va_list ap1,ap2;]], [[va_copy(ap1,ap2);]])], -have_va_copy=yes, -have_va_copy=no) -AC_MSG_RESULT($have_va_copy) -if test x"$have_va_copy" = x"yes"; then - AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available]) -else - AC_MSG_CHECKING([for __va_copy]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include - va_list ap1,ap2;]], [[__va_copy(ap1,ap2);]])], - have___va_copy=yes, - have___va_copy=no) - AC_MSG_RESULT($have___va_copy) - if test x"$have___va_copy" = x"yes"; then - AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available]) - fi -fi - -dnl Checking whether va_list is an array type -AC_MSG_CHECKING([whether va_list is an array type]) -AC_TRY_COMPILE2([ -#include -void a(va_list * ap) {}],[ -va_list ap1, ap2; a(&ap1); ap2 = (va_list) ap1],[ - AC_MSG_RESULT(no)],[ - AC_MSG_RESULT(yes) - AC_DEFINE([VA_LIST_IS_ARRAY], [1],[Define if va_list is an array type])]) +AC_CHECK_DECL([getentropy], + [AC_DEFINE([HAVE_GETENTROPY], [1], [getentropy])], [], + [#include ]) -dnl Checks for inet libraries: -AC_SEARCH_LIBS(gethostent, [nsl]) -AC_SEARCH_LIBS(setsockopt, [socket net network]) -AC_SEARCH_LIBS(connect, [inet]) +dnl +dnl Checks for inet libraries +dnl +if test "$with_http" = "yes" || test "$with_ftp" = "yes"; then + AC_CHECK_HEADERS([sys/socket.h netinet/in.h arpa/inet.h netdb.h]) + AC_CHECK_HEADERS([sys/select.h poll.h]) + + case "$host" in + *-*-mingw*) + dnl AC_SEARCH_LIBS doesn't work because of non-standard calling + dnl conventions on 32-bit Windows. + NET_LIBS="$NET_LIBS -lws2_32" + ;; + *) + _libs=$LIBS + AC_SEARCH_LIBS(gethostbyname, [nsl], [ + if test "$ac_cv_search_gethostbyname" != "none required"; then + NET_LIBS="$NET_LIBS $ac_cv_search_gethostbyname" + fi], [:], [$NET_LIBS]) + AC_SEARCH_LIBS(connect, [bsd socket inet], [ + if test "$ac_cv_search_connect" != "none required"; then + NET_LIBS="$NET_LIBS $ac_cv_search_connect" + fi], [:], [$NET_LIBS]) + LIBS=$_libs + ;; + esac -dnl Determine what socket length (socklen_t) data type is -AC_MSG_CHECKING([for type of socket length (socklen_t)]) -AC_TRY_COMPILE2([ -#include -#include -#include ],[ -(void)getsockopt (1, 1, 1, NULL, (socklen_t *)NULL)],[ - AC_MSG_RESULT(socklen_t *) - XML_SOCKLEN_T=socklen_t],[ - AC_TRY_COMPILE2([ -#include -#include -#include ],[ -(void)getsockopt (1, 1, 1, NULL, (size_t *)NULL)],[ - AC_MSG_RESULT(size_t *) - XML_SOCKLEN_T=size_t],[ + dnl Determine what socket length (socklen_t) data type is + AC_MSG_CHECKING([for type of socket length (socklen_t)]) AC_TRY_COMPILE2([ -#include -#include -#include ],[ -(void)getsockopt (1, 1, 1, NULL, (int *)NULL)],[ - AC_MSG_RESULT(int *) - XML_SOCKLEN_T=int],[ - AC_MSG_WARN(could not determine) - XML_SOCKLEN_T="int"])])]) -AC_DEFINE_UNQUOTED(XML_SOCKLEN_T, $XML_SOCKLEN_T, [Determine what socket length (socklen_t) data type is]) - -dnl Checking if gethostbyname() argument is const. -AC_MSG_CHECKING([for const gethostbyname() argument]) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[(void)gethostbyname((const char *)"");]])], -have_gethostbyname_const_arg=yes, -have_gethostbyname_const_arg=no) -AC_MSG_RESULT($have_gethostbyname_const_arg) -if test x"$have_gethostbyname_const_arg" = x"yes"; then - AC_DEFINE([GETHOSTBYNAME_ARG_CAST], [], - [Type cast for the gethostbyname() argument]) -else - AC_DEFINE([GETHOSTBYNAME_ARG_CAST], [(char *)], - [Type cast for the gethostbyname() argument]) + #include + #ifdef _WIN32 + #include + #else + #include + #endif],[ + (void)getsockopt (1, 1, 1, NULL, (socklen_t *)NULL)],[ + AC_MSG_RESULT(socklen_t *) + XML_SOCKLEN_T=socklen_t],[ + AC_TRY_COMPILE2([ + #include + #include ],[ + (void)getsockopt (1, 1, 1, NULL, (size_t *)NULL)],[ + AC_MSG_RESULT(size_t *) + XML_SOCKLEN_T=size_t],[ + AC_TRY_COMPILE2([ + #include + #include ],[ + (void)getsockopt (1, 1, 1, NULL, (int *)NULL)],[ + AC_MSG_RESULT(int *) + XML_SOCKLEN_T=int],[ + AC_MSG_WARN(could not determine) + XML_SOCKLEN_T="int"])])]) + AC_DEFINE_UNQUOTED(XML_SOCKLEN_T, $XML_SOCKLEN_T, [Determine what socket length (socklen_t) data type is]) + + dnl + dnl Checking for availability of IPv6 + dnl + AC_ARG_ENABLE(ipv6, [ --enable-ipv6[[=yes/no]] enables compilation of IPv6 code [[default=yes]]],, enable_ipv6=yes) + if test "$with_minimum" = "yes" + then + enable_ipv6=no + fi + if test $enable_ipv6 = yes; then + AC_MSG_CHECKING([whether to enable IPv6]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #ifdef _WIN32 + #include + #else + #include + #ifdef HAVE_NETDB_H + #include + #endif + #endif + ]], [[ + struct sockaddr_storage ss; + socket(AF_INET6, SOCK_STREAM, 0); + getaddrinfo(0, 0, 0, 0); + ]])], [ + AC_DEFINE([SUPPORT_IP6], [], [Support for IPv6]) + AC_MSG_RESULT([yes])], [ + AC_MSG_RESULT([no])] + ) + fi fi -dnl Checking if send() second argument is const. -AC_MSG_CHECKING([for const send() second argument]) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], - [[(void)send(1,(const char *)"",1,1);]])], -have_send_const_arg2=yes, -have_send_const_arg2=no) -AC_MSG_RESULT($have_send_const_arg2) -if test x"$have_send_const_arg2" = x"yes"; then - AC_DEFINE([SEND_ARG2_CAST], [], - [Type cast for the send() function 2nd arg]) -else - AC_DEFINE([SEND_ARG2_CAST], [(char *)], - [Type cast for the send() function 2nd arg]) +dnl +dnl Extra flags +dnl +XML_LIBDIR='-L${libdir}' +XML_INCLUDEDIR='-I${includedir}/libxml2' +XML_CFLAGS="" + +dnl Thread-local storage +if test "$with_tls" = "yes"; then + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([_Thread_local int v;]) ], [ + AC_DEFINE([XML_THREAD_LOCAL], [_Thread_local], [TLS specifier]) ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([__thread int v;]) ], [ + AC_DEFINE([XML_THREAD_LOCAL], [__thread], [TLS specifier]) ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([__declspec(thread) int v;]) ], [ + AC_DEFINE([XML_THREAD_LOCAL], [__declspec(thread)], [TLS specifier]) ], [ + WARN_NO_TLS=1 ])])]) fi dnl Checking whether __attribute__((destructor)) is accepted by the compiler @@ -596,99 +438,29 @@ f(void) {}], [], [ AC_DEFINE([ATTRIBUTE_DESTRUCTOR], [__attribute__((destructor))],[A form that will not confuse apibuild.py])],[ AC_MSG_RESULT(no)]) - -dnl ***********************Checking for availability of IPv6******************* - -AC_MSG_CHECKING([whether to enable IPv6]) -AC_ARG_ENABLE(ipv6, [ --enable-ipv6[[=yes/no]] enables compilation of IPv6 code [[default=yes]]],, enable_ipv6=yes) -if test "$with_minimum" = "yes" -then - enable_ipv6=no -fi -if test $enable_ipv6 = yes; then - have_ipv6=no - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -# include -# include - ]], [[ - struct sockaddr_storage ss; - socket(AF_INET6, SOCK_STREAM, 0) - ]])], - have_ipv6=yes, - have_ipv6=no - ) - AC_MSG_RESULT($have_ipv6) - - if test $have_ipv6 = yes; then - AC_DEFINE([SUPPORT_IP6], [], [Support for IPv6]) - have_broken_ss_family=no - - dnl ********************************************************************* - dnl on some platforms (like AIX 5L), the structure sockaddr doesn't have - dnl a ss_family member, but rather __ss_family. Let's detect that - dnl and define the HAVE_BROKEN_SS_FAMILY when we are on one of these - dnl platforms. However, we should only do this if ss_family is not - dnl present. - dnl ******************************************************************** - AC_MSG_CHECKING([struct sockaddr::ss_family]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -# include -# include - ]], [[ - struct sockaddr_storage ss ; - ss.ss_family = 0 ; - ]])], - have_ss_family=yes, - have_ss_family=no - ) - AC_MSG_RESULT($have_ss_family) - if test x$have_ss_family = xno ; then - AC_MSG_CHECKING([broken struct sockaddr::ss_family]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -# include -# include - ]], [[ - struct sockaddr_storage ss ; - ss.__ss_family = 0 ; - ]])], - have_broken_ss_family=yes, - have_broken_ss_family=no - ) - AC_MSG_RESULT($have_broken_ss_family) - if test x$have_broken_ss_family = xyes ; then - AC_DEFINE(HAVE_BROKEN_SS_FAMILY, [], - [Whether struct sockaddr::__ss_family exists]) - AC_DEFINE(ss_family, __ss_family, - [ss_family is not defined here, use __ss_family instead]) - else - AC_MSG_WARN(ss_family and __ss_family not found) - fi - fi - - have_getaddrinfo=no - AC_CHECK_FUNC(getaddrinfo, have_getaddrinfo=yes) - if test $have_getaddrinfo != yes; then - for lib in bsd socket inet; do - AC_CHECK_LIB($lib, getaddrinfo, [LIBS="$LIBS -l$lib";have_getaddrinfo=yes;break]) - done - fi - - if test $have_getaddrinfo = yes; then - AC_DEFINE([HAVE_GETADDRINFO], [], [Define if getaddrinfo is there]) - fi - fi -fi - -dnl ******************************End IPv6 checks****************************** - -XML_LIBDIR='-L${libdir}' -XML_INCLUDEDIR='-I${includedir}/libxml2' - dnl -dnl Extra flags +dnl Linker version scripts for symbol versioning dnl -XML_CFLAGS="" -RDL_LIBS="" +VERSION_SCRIPT_FLAGS= +# lt_cv_prog_gnu_ld is from libtool 2.+ +if test "$lt_cv_prog_gnu_ld" = yes; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-msys* ) + ;; + *) + dnl lld 16 defaults to --no-undefined-version but the version script + dnl can contain symbols disabled by configuration options. + AX_APPEND_LINK_FLAGS([-Wl,--undefined-version], [VERSION_SCRIPT_FLAGS]) + AX_APPEND_FLAG([-Wl,--version-script=], [VERSION_SCRIPT_FLAGS]) + ;; + esac +else + case $host in + *-*-sunos*) VERSION_SCRIPT_FLAGS="-Wl,-M -Wl,";; + esac +fi +AC_SUBST(VERSION_SCRIPT_FLAGS) +AM_CONDITIONAL([USE_VERSION_SCRIPT], [test -n "$VERSION_SCRIPT_FLAGS"]) dnl dnl Workaround for native compilers @@ -698,35 +470,26 @@ dnl if test "${GCC}" != "yes" ; then case "${host}" in hppa*-*-hpux* ) - EXTRA_CFLAGS="${EXTRA_CFLAGS} -Wp,-H30000" + AM_CFLAGS="${AM_CFLAGS} -Wp,-H30000" ;; *-dec-osf* ) - EXTRA_CFLAGS="${EXTRA_CFLAGS} -ieee" + AM_CFLAGS="${AM_CFLAGS} -ieee" ;; alpha*-*-linux* ) - EXTRA_CFLAGS="${EXTRA_CFLAGS} -ieee" + AM_CFLAGS="${AM_CFLAGS} -ieee" ;; esac else - if test "$with_fexceptions" = "yes" - then - # - # Not activated by default because this inflates the code size - # Used to allow propagation of C++ exceptions through the library - # - EXTRA_CFLAGS="${EXTRA_CFLAGS} -fexceptions" - fi - # warnings we'd like to see - EXTRA_CFLAGS="${EXTRA_CFLAGS} -pedantic -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wredundant-decls" + AM_CFLAGS="${AM_CFLAGS} -pedantic -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" # warnings we'd like to suppress - EXTRA_CFLAGS="${EXTRA_CFLAGS} -Wno-long-long -Wno-format-extra-args" + AM_CFLAGS="${AM_CFLAGS} -Wno-long-long -Wno-format-extra-args" case "${host}" in alpha*-*-linux* ) - EXTRA_CFLAGS="${EXTRA_CFLAGS} -mieee" + AM_CFLAGS="${AM_CFLAGS} -mieee" ;; alpha*-*-osf* ) - EXTRA_CFLAGS="${EXTRA_CFLAGS} -mieee" + AM_CFLAGS="${AM_CFLAGS} -mieee" ;; esac fi @@ -734,305 +497,99 @@ case ${host} in *-*-solaris*) XML_LIBDIR="${XML_LIBDIR} -R${libdir}" ;; - hppa*-hp-mpeix) - NEED_TRIO=1 - ;; - *-*-mingw* | *-*-cygwin* | *-*-msvc* ) + *-*-cygwin* | *-*-mingw* | *-*-msys* ) # If the host is Windows, and shared libraries are disabled, we - # need to add -DLIBXML_STATIC to EXTRA_CFLAGS in order for linking to + # need to add -DLIBXML_STATIC to AM_CFLAGS in order for linking to # work properly (without it, xmlexports.h would force the use of # DLL imports, which obviously aren't present in a static # library). if test "x$enable_shared" = "xno"; then XML_CFLAGS="$XML_CFLAGS -DLIBXML_STATIC" - EXTRA_CFLAGS="$EXTRA_CFLAGS -DLIBXML_STATIC" + AM_CFLAGS="$AM_CFLAGS -DLIBXML_STATIC" fi ;; esac dnl -dnl check for python +dnl Simple API modules dnl -PYTHON_TESTS= -AS_IF([test "x$with_python" != "xno"], [ - AM_PATH_PYTHON - PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}]) -]) -AM_CONDITIONAL([WITH_PYTHON], [test "x$with_python" != "xno"]) - -dnl check for dso support -WITH_MODULES=0 - -if test "$with_modules" != "no" ; then - case "$host" in - *-*-cygwin*) - MODULE_EXTENSION=".dll" - AC_CHECK_LIB(cygwin, dlopen, [ - WITH_MODULES=1 - MODULE_PLATFORM_LIBS= - AC_DEFINE([HAVE_DLOPEN], [], [Have dlopen based dso]) - ]) - ;; - *-*-mingw*) - MODULE_EXTENSION=".dll" - WITH_MODULES=1 - ;; - *) - AC_CHECK_FUNC(shl_load, libxml_have_shl_load=yes, [ - AC_CHECK_LIB(dld, shl_load, [ - MODULE_PLATFORM_LIBS="-ldld" - libxml_have_shl_load=yes], [ - AC_CHECK_FUNC(dlopen, libxml_have_dlopen=yes, [ - AC_CHECK_LIB(dl, dlopen, [ - MODULE_PLATFORM_LIBS="-ldl" - libxml_have_dlopen=yes])])])]) - - if test "${libxml_have_shl_load}" = "yes"; then - MODULE_EXTENSION=".sl" - WITH_MODULES=1 - AC_DEFINE([HAVE_SHLLOAD], [], [Have shl_load based dso]) - fi - - if test "${libxml_have_dlopen}" = "yes"; then - case "${host}" in - *-*-hpux* ) - MODULE_EXTENSION=".sl" - ;; - * ) - MODULE_EXTENSION=".so" - ;; - esac - - WITH_MODULES=1 - AC_DEFINE([HAVE_DLOPEN], [], [Have dlopen based dso]) - fi - ;; - esac -fi - -AC_SUBST(WITH_MODULES) -AC_SUBST(MODULE_PLATFORM_LIBS) -AC_SUBST(MODULE_EXTENSION) - -dnl -dnl Check for trio string functions -dnl - -if test "${NEED_TRIO}" = "1" ; then - echo Adding trio library for string functions - WITH_TRIO=1 -else - WITH_TRIO=0 -fi -AM_CONDITIONAL(WITH_TRIO_SOURCES, test "${NEED_TRIO}" = "1") -AC_SUBST(WITH_TRIO) - -dnl -dnl Allow to enable/disable various pieces -dnl -echo Checking configuration requirements - -dnl -dnl Thread-related stuff -dnl -THREAD_LIBS="" -BASE_THREAD_LIBS="" -WITH_THREADS=0 -THREAD_CFLAGS="" -THREADS_W32="" -WITH_THREAD_ALLOC=0 - -if test "$with_threads" = "no" ; then - echo Disabling multithreaded support -else - echo Enabling multithreaded support - - dnl Default to native threads on Windows - case $host_os in - *mingw*) if test "$with_threads" != "pthread" && test "$with_threads" != "no"; then - WITH_THREADS="1" - THREADS_W32="1" - THREAD_CFLAGS="$THREAD_CFLAGS -DHAVE_WIN32_THREADS" - fi - ;; - esac - - dnl Use pthread by default in other cases - if test -z "$THREADS_W32"; then - if test "$with_threads" = "pthread" || test "$with_threads" = "" || test "$with_threads" = "yes" ; then - AC_CHECK_HEADER(pthread.h, - AC_CHECK_LIB(pthread, pthread_join,[ - THREAD_LIBS="-lpthread" - AC_DEFINE([HAVE_PTHREAD_H], [], [Define if is there]) - WITH_THREADS="1"])) - fi - fi - - case $host_os in - *cygwin*) THREAD_LIBS="" - ;; - *beos*) WITH_THREADS="1" - THREAD_CFLAGS="$THREAD_CFLAGS -DHAVE_BEOS_THREADS" - ;; - *linux*) - if test "${GCC}" = "yes" ; then - GCC_VERSION=`${CC} --version | head -1 | awk '{print $3}'` - GCC_MAJOR=`echo ${GCC_VERSION} | sed 's+\..*++'` - GCC_MEDIUM=`echo ${GCC_VERSION} | sed 's+[[0-9]]*\.++' | sed 's+\..*++'` - if test "${THREAD_LIBS}" = "-lpthread" ; then - if expr ${GCC_MEDIUM} \> 2 \& ${GCC_MAJOR} = 3 > /dev/null - then - THREAD_LIBS="" - BASE_THREAD_LIBS="-lpthread" - else - if expr ${GCC_MAJOR} \> 3 > /dev/null - then - THREAD_LIBS="" - BASE_THREAD_LIBS="-lpthread" - else - echo old GCC disabling weak symbols for pthread - fi - fi - fi - fi - ;; - esac - if test "$WITH_THREADS" = "1" ; then - THREAD_CFLAGS="$THREAD_CFLAGS -D_REENTRANT" - fi -fi -if test "$with_thread_alloc" = "yes" && test "$WITH_THREADS" = "1" ; then - WITH_THREAD_ALLOC=1 -fi - -AC_SUBST(THREAD_LIBS) -AC_SUBST(BASE_THREAD_LIBS) -AC_SUBST(WITH_THREADS) -AC_SUBST(THREAD_CFLAGS) -AC_SUBST(WITH_THREAD_ALLOC) -AM_CONDITIONAL([THREADS_W32],[test -n "$THREADS_W32"]) - -dnl -dnl xmllint shell history -dnl -if test "$with_history" = "yes" ; then - echo Enabling xmllint shell history - dnl check for terminal library. this is a very cool solution - dnl from octave's configure.in - unset tcap - for termlib in ncurses curses termcap terminfo termlib; do - AC_CHECK_LIB(${termlib}, tputs, [tcap="-l$termlib"]) - test -n "$tcap" && break - done - - AC_CHECK_HEADER(readline/history.h, - AC_CHECK_LIB(history, append_history,[ - RDL_LIBS="-lhistory" - AC_DEFINE([HAVE_LIBHISTORY], [], [Define if history library is there (-lhistory)])])) - AC_CHECK_HEADER(readline/readline.h, - AC_CHECK_LIB(readline, readline,[ - RDL_LIBS="-lreadline $RDL_LIBS $tcap" - AC_DEFINE([HAVE_LIBREADLINE], [], [Define if readline library is there (-lreadline)])], , $tcap)) - if test -n "$RDL_DIR" && test -n "$RDL_LIBS"; then - CPPFLAGS="$CPPFLAGS -I${RDL_DIR}/include" - RDL_LIBS="-L${RDL_DIR}/lib $RDL_LIBS" - fi -fi - -dnl -dnl Tree functions -dnl if test "$with_tree" = "no" ; then echo Disabling DOM like tree manipulation APIs WITH_TREE=0 -else +else WITH_TREE=1 fi AC_SUBST(WITH_TREE) if test "$with_ftp" != "yes" ; then - echo Disabling FTP support WITH_FTP=0 - FTP_OBJ= -else +else + echo Enabling FTP support WITH_FTP=1 - FTP_OBJ=nanoftp.o fi AC_SUBST(WITH_FTP) -AC_SUBST(FTP_OBJ) +AM_CONDITIONAL(WITH_FTP_SOURCES, test "$WITH_FTP" = "1") -if test "$with_http" = "no" ; then - echo Disabling HTTP support +if test "$with_http" != "yes" ; then WITH_HTTP=0 - HTTP_OBJ= -else +else + echo Enabling HTTP support WITH_HTTP=1 - HTTP_OBJ=nanohttp.o fi AC_SUBST(WITH_HTTP) -AC_SUBST(HTTP_OBJ) +AM_CONDITIONAL(WITH_HTTP_SOURCES, test "$WITH_HTTP" = "1") if test "$with_legacy" != "yes" ; then - echo Disabling deprecated APIs WITH_LEGACY=0 -else +else + echo Enabling deprecated APIs WITH_LEGACY=1 fi AC_SUBST(WITH_LEGACY) +AM_CONDITIONAL(WITH_LEGACY_SOURCES, test "$WITH_LEGACY" = "1") if test "$with_reader" = "no" ; then echo Disabling the xmlReader parsing interface WITH_READER=0 -else +else WITH_READER=1 - if test "$with_push" = "no" ; then - echo xmlReader requires Push interface - enabling it - with_push=yes - fi fi AC_SUBST(WITH_READER) +AM_CONDITIONAL(WITH_READER_SOURCES, test "$WITH_READER" = "1") if test "$with_writer" = "no" ; then echo Disabling the xmlWriter saving interface WITH_WRITER=0 -# WRITER_TEST= -else +else WITH_WRITER=1 -# WRITER_TEST=Writertests - if test "$with_push" = "no" ; then - echo xmlWriter requires Push interface - enabling it - with_push=yes - fi - if test "$with_output" = "no" ; then - echo xmlWriter requires Output interface - enabling it - with_output=yes - fi fi AC_SUBST(WITH_WRITER) -#AC_SUBST(WRITER_TEST) +AM_CONDITIONAL(WITH_WRITER_SOURCES, test "$WITH_WRITER" = "1") if test "$with_pattern" = "no" ; then echo Disabling the xmlPattern parsing interface WITH_PATTERN=0 -else +else WITH_PATTERN=1 fi AC_SUBST(WITH_PATTERN) +AM_CONDITIONAL(WITH_PATTERN_SOURCES, test "$WITH_PATTERN" = "1") if test "$with_sax1" = "no" ; then echo Disabling the older SAX1 interface WITH_SAX1=0 -else +else WITH_SAX1=1 fi AC_SUBST(WITH_SAX1) +AM_CONDITIONAL(WITH_SAX1_SOURCES, test "$WITH_SAX1" = "1") if test "$with_push" = "no" ; then echo Disabling the PUSH parser interfaces WITH_PUSH=0 -else +else WITH_PUSH=1 fi AC_SUBST(WITH_PUSH) @@ -1040,406 +597,558 @@ AC_SUBST(WITH_PUSH) if test "$with_html" = "no" ; then echo Disabling HTML support WITH_HTML=0 - HTML_OBJ= -else +else WITH_HTML=1 - HTML_OBJ="HTMLparser.o HTMLtree.o" fi AC_SUBST(WITH_HTML) -AC_SUBST(HTML_OBJ) +AM_CONDITIONAL(WITH_HTML_SOURCES, test "$WITH_HTML" = "1") if test "$with_valid" = "no" ; then echo Disabling DTD validation support WITH_VALID=0 - TEST_VTIME= -else +else WITH_VALID=1 - TEST_VTIME=VTimingtests fi AC_SUBST(WITH_VALID) -AC_SUBST(TEST_VALID) -AC_SUBST(TEST_VTIME) +AM_CONDITIONAL(WITH_VALID_SOURCES, test "$WITH_VALID" = "1") if test "$with_catalog" = "no" ; then echo Disabling Catalog support WITH_CATALOG=0 - CATALOG_OBJ= - TEST_CATALOG= -else +else WITH_CATALOG=1 - CATALOG_OBJ="catalog.o" - TEST_CATALOG=Catatests fi AC_SUBST(WITH_CATALOG) -AC_SUBST(CATALOG_OBJ) -AC_SUBST(TEST_CATALOG) +AM_CONDITIONAL(WITH_CATALOG_SOURCES, test "$WITH_CATALOG" = "1") if test "$with_xptr" = "no" ; then echo Disabling XPointer support WITH_XPTR=0 WITH_XPTR_LOCS=0 - XPTR_OBJ= -else +else WITH_XPTR=1 - XPTR_OBJ=xpointer.o - if test "$with_xpath" = "no" ; then - echo XPointer requires XPath support - enabling it - with_xpath=yes - fi - if test "$with_xptr_locs" = "yes" ; then - WITH_XPTR_LOCS=1 - else - WITH_XPTR_LOCS=0 - fi fi AC_SUBST(WITH_XPTR) +AM_CONDITIONAL(WITH_XPTR_SOURCES, test "$WITH_XPTR" = "1") + +if test "$with_xptr_locs" != "yes" ; then + WITH_XPTR_LOCS=0 +else + echo Enabling Xpointer locations support + WITH_XPTR_LOCS=1 +fi AC_SUBST(WITH_XPTR_LOCS) -AC_SUBST(XPTR_OBJ) if test "$with_c14n" = "no" ; then echo Disabling C14N support WITH_C14N=0 - C14N_OBJ= -else +else WITH_C14N=1 - C14N_OBJ="c14n.c" - if test "$with_xpath" = "no" ; then - echo C14N requires XPath support - enabling it - with_xpath=yes - fi fi AC_SUBST(WITH_C14N) -AC_SUBST(C14N_OBJ) +AM_CONDITIONAL(WITH_C14N_SOURCES, test "$WITH_C14N" = "1") if test "$with_xinclude" = "no" ; then echo Disabling XInclude support WITH_XINCLUDE=0 - XINCLUDE_OBJ= - with_xinclude="no" -else +else WITH_XINCLUDE=1 - XINCLUDE_OBJ=xinclude.o - if test "$with_xpath" = "no" ; then - echo XInclude requires XPath support - enabling it - with_xpath=yes - fi fi AC_SUBST(WITH_XINCLUDE) -AC_SUBST(XINCLUDE_OBJ) - -if test "$with_xptr" = "" && test "$with_xpath" = "no" ; then - with_xptr=no -fi - -if test "$with_schematron" = "" && test "$with_xpath" = "no" ; then - with_schematron=no -fi +AM_CONDITIONAL(WITH_XINCLUDE_SOURCES, test "$WITH_XINCLUDE" = "1") if test "$with_schematron" = "no" ; then echo "Disabling Schematron support" WITH_SCHEMATRON=0 - TEST_SCHEMATRON= -else - echo "Enabled Schematron support" +else WITH_SCHEMATRON=1 - TEST_SCHEMATRON="Schematrontests" - with_xpath=yes - with_pattern=yes - with_schematron=yes fi AC_SUBST(WITH_SCHEMATRON) -AC_SUBST(TEST_SCHEMATRON) +AM_CONDITIONAL(WITH_SCHEMATRON_SOURCES, test "$WITH_SCHEMATRON" = "1") if test "$with_xpath" = "no" ; then echo Disabling XPATH support WITH_XPATH=0 - XPATH_OBJ= -else +else WITH_XPATH=1 - XPATH_OBJ=xpath.o fi AC_SUBST(WITH_XPATH) -AC_SUBST(XPATH_OBJ) +AM_CONDITIONAL(WITH_XPATH_SOURCES, test "$WITH_XPATH" = "1") -dnl -dnl output functions -dnl if test "$with_output" = "no" ; then echo Disabling serialization/saving support WITH_OUTPUT=0 -else +else WITH_OUTPUT=1 fi AC_SUBST(WITH_OUTPUT) +AM_CONDITIONAL(WITH_OUTPUT_SOURCES, test "$WITH_OUTPUT" = "1") -WITH_ICONV=0 -if test "$with_iconv" = "no" ; then - echo Disabling ICONV support -else - if test "$with_iconv" != "yes" && test "$with_iconv" != "" ; then - CPPFLAGS="${CPPFLAGS} -I$with_iconv/include" - # Export this since our headers include iconv.h - XML_INCLUDEDIR="${XML_INCLUDEDIR} -I$with_iconv/include" - ICONV_LIBS="-L$with_iconv/lib" - fi - - AC_CHECK_HEADER(iconv.h, - AC_MSG_CHECKING(for iconv) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -#include ]],[[ -iconv_t cd = iconv_open ("",""); -iconv (cd, NULL, NULL, NULL, NULL);]])],[ - AC_MSG_RESULT(yes) - WITH_ICONV=1],[ - AC_MSG_RESULT(no) - AC_MSG_CHECKING(for iconv in -liconv) - - _ldflags="${LDFLAGS}" - _libs="${LIBS}" - LDFLAGS="${LDFLAGS} ${ICONV_LIBS}" - LIBS="${LIBS} -liconv" - - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -#include ]],[[ -iconv_t cd = iconv_open ("",""); -iconv (cd, NULL, NULL, NULL, NULL);]])],[ - AC_MSG_RESULT(yes) - WITH_ICONV=1 - ICONV_LIBS="${ICONV_LIBS} -liconv" - LIBS="${_libs}" - LDFLAGS="${_ldflags}"],[ - AC_MSG_RESULT(no) - LIBS="${_libs}" - LDFLAGS="${_ldflags}"])])) -fi -AC_SUBST(WITH_ICONV) - -WITH_ICU=0 -ICU_LIBS="" -if test "$with_icu" != "yes" ; then - echo Disabling ICU support -else - # Try pkg-config first so that static linking works. - # If this succeeeds, we ignore the WITH_ICU directory. - PKG_CHECK_MODULES([ICU],[icu-i18n], - [have_libicu=yes], - [have_libicu=no]) - - if test "x$have_libicu" = "xyes"; then - m4_ifdef([PKG_CHECK_VAR], - [PKG_CHECK_VAR([ICU_DEFS], [icu-i18n], [DEFS])]) - if test "x$ICU_DEFS" != "x"; then - CPPFLAGS="$CPPFLAGS $ICU_DEFS" - fi - fi - - # If pkg-config failed, fall back to AC_CHECK_LIB. This - # will not pick up the necessary LIBS flags for liblzma's - # private dependencies, though, so static linking may fail. - if test "x$have_libicu" = "xno"; then - ICU_CONFIG=icu-config - if ${ICU_CONFIG} --cflags >/dev/null 2>&1 - then - ICU_LIBS=`${ICU_CONFIG} --ldflags` - have_libicu=yes - echo Enabling ICU support - else - if test "$with_icu" != "yes" && test "$with_iconv" != "" ; then - CPPFLAGS="${CPPFLAGS} -I$with_icu" - fi - - AC_CHECK_HEADER(unicode/ucnv.h, - AC_MSG_CHECKING(for icu) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ - UConverter *utf = ucnv_open("UTF-8", NULL);]])],[ - AC_MSG_RESULT(yes) - have_libicu=yes],[ - AC_MSG_RESULT(no) - AC_MSG_CHECKING(for icu in -licucore) - - _ldflags="${LDFLAGS}" - _libs="${LIBS}" - LDFLAGS="${LDFLAGS} ${ICU_LIBS}" - LIBS="${LIBS} -licucore" - - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ - UConverter *utf = ucnv_open("UTF-8", NULL);]])],[ - AC_MSG_RESULT(yes) - have_libicu=yes - ICU_LIBS="${ICU_LIBS} -licucore" - LIBS="${_libs}" - LDFLAGS="${_ldflags}"],[ - AC_MSG_RESULT(no) - LIBS="${_libs}" - LDFLAGS="${_ldflags}"])])) - fi - fi - - # Found the library via either method? - if test "x$have_libicu" = "xyes"; then - WITH_ICU=1 - fi -fi -XML_LIBS="-lxml2" -XML_LIBTOOLLIBS="libxml2.la" -AC_SUBST(WITH_ICU) - -WITH_ISO8859X=1 -if test "$WITH_ICONV" != "1" ; then -if test "$with_iso8859x" = "no" ; then +if test "$WITH_ICONV" != "1" && test "$with_iso8859x" = "no" ; then echo Disabling ISO8859X support WITH_ISO8859X=0 -fi +else + WITH_ISO8859X=1 fi AC_SUBST(WITH_ISO8859X) if test "$with_schemas" = "no" ; then echo "Disabling Schemas/Relax-NG support" WITH_SCHEMAS=0 -else - echo "Enabled Schemas/Relax-NG support" +else WITH_SCHEMAS=1 - AS_IF([test "x$with_python" != "xno"], [ - PYTHON_TESTS="$PYTHON_TESTS RelaxNGPythonTests SchemasPythonTests" - ]) - with_regexps=yes fi AC_SUBST(WITH_SCHEMAS) +AM_CONDITIONAL(WITH_SCHEMAS_SOURCES, test "$WITH_SCHEMAS" = "1") if test "$with_regexps" = "no" ; then echo Disabling Regexps support WITH_REGEXPS=0 - TEST_REGEXPS= -else +else WITH_REGEXPS=1 - TEST_REGEXPS="Automatatests" fi AC_SUBST(WITH_REGEXPS) -AC_SUBST(TEST_REGEXPS) +AM_CONDITIONAL(WITH_REGEXPS_SOURCES, test "$WITH_REGEXPS" = "1") if test "$with_debug" = "no" ; then echo Disabling DEBUG support WITH_DEBUG=0 - DEBUG_OBJ= - TEST_DEBUG= -else +else WITH_DEBUG=1 - DEBUG_OBJ=debugXML.o - TEST_DEBUG=Scripttests fi AC_SUBST(WITH_DEBUG) -AC_SUBST(DEBUG_OBJ) -AC_SUBST(TEST_DEBUG) - -if test "$with_mem_debug" = "yes" ; then - if test "$with_thread_alloc" = "yes" ; then - echo Disabling memory debug - cannot use mem-debug with thread-alloc! - WITH_MEM_DEBUG=0 - else - echo Enabling memory debug support - WITH_MEM_DEBUG=1 +AM_CONDITIONAL(WITH_DEBUG_SOURCES, test "$WITH_DEBUG" = "1") + +dnl +dnl Check for Python +dnl + +AS_IF([test "x$with_python" != "xno"], [ + AM_PATH_PYTHON + PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}]) +]) +AM_CONDITIONAL([WITH_PYTHON], [test "x$with_python" != "xno"]) + +dnl +dnl Extra Python flags for Windows +dnl +PYTHON_LDFLAGS= +if test "${PYTHON}" != ""; then + case "$host" in + *-*-mingw* ) + PYTHON_LDFLAGS="-no-undefined -shrext .pyd" + ;; + *-*-cygwin* |*-*-msys* ) + PYTHON_LDFLAGS="-no-undefined" + ;; + esac +fi +AC_SUBST(PYTHON_LDFLAGS) + +dnl +dnl Check for DSO support +dnl +WITH_MODULES=0 + +if test "$with_modules" != "no" ; then + case "$host" in + *-*-cygwin* | *-*-msys* ) + MODULE_EXTENSION=".dll" + ;; + *-*-mingw*) + MODULE_EXTENSION=".dll" + WITH_MODULES=1 + ;; + *-*-hpux*) + MODULE_EXTENSION=".sl" + ;; + *) + MODULE_EXTENSION=".so" + ;; + esac + + if test "$WITH_MODULES" = "0"; then + _libs=$LIBS + AC_SEARCH_LIBS([dlopen], [dl], [ + WITH_MODULES=1 + if test "$ac_cv_search_dlopen" != "none required"; then + MODULE_PLATFORM_LIBS=$ac_cv_search_dlopen + fi + AC_DEFINE([HAVE_DLOPEN], [], [Have dlopen based dso])], [ + AC_SEARCH_LIBS([shl_load], [dld], [ + WITH_MODULES=1 + if test "$ac_cv_search_shl_load" != "none required"; then + MODULE_PLATFORM_LIBS=$ac_cv_search_shl_load + fi + AC_DEFINE([HAVE_SHLLOAD], [], [Have shl_load based dso])])]) + LIBS=$_libs fi -else - WITH_MEM_DEBUG=0 fi -AC_SUBST(WITH_MEM_DEBUG) -if test "$with_run_debug" = "yes" ; then - echo Enabling runtime debug support - WITH_RUN_DEBUG=1 -else - WITH_RUN_DEBUG=0 +AC_SUBST(WITH_MODULES) +AC_SUBST(MODULE_PLATFORM_LIBS) +AC_SUBST(MODULE_EXTENSION) +AM_CONDITIONAL(WITH_MODULES_SOURCES, test "$WITH_MODULES" = "1") + +dnl +dnl Thread-related stuff +dnl +THREAD_LIBS="" +BASE_THREAD_LIBS="" +WITH_THREADS=0 +WITH_THREAD_ALLOC=0 + +if test "$with_threads" = "no" ; then + echo Disabling multithreaded support +else + case $host_os in + *mingw*) + dnl Default to native threads on Windows + WITH_THREADS="1" + ;; + *) + dnl Use pthread by default in other cases + _libs=$LIBS + AC_CHECK_HEADERS(pthread.h, + AC_SEARCH_LIBS([pthread_create], [pthread], [ + WITH_THREADS="1" + if test "$ac_cv_search_pthread_create" != "none required"; then + THREAD_LIBS=$ac_cv_search_pthread_create + fi + AC_DEFINE([HAVE_PTHREAD_H], [], + [Define if is there])])) + LIBS=$_libs + ;; + esac + + case $host_os in + *linux*) + if test "${GCC}" = "yes" ; then + BASE_THREAD_LIBS="$THREAD_LIBS" + THREAD_LIBS="" + fi + ;; + esac +fi +if test "$with_thread_alloc" = "yes" && test "$WITH_THREADS" = "1" ; then + WITH_THREAD_ALLOC=1 fi -AC_SUBST(WITH_RUN_DEBUG) -WIN32_EXTRA_LIBADD= -WIN32_EXTRA_LDFLAGS= -CYGWIN_EXTRA_LDFLAGS= -CYGWIN_EXTRA_PYTHON_LIBADD= -WIN32_EXTRA_PYTHON_LIBADD= -case "$host" in - *-*-mingw*) - CPPFLAGS="$CPPFLAGS -DWIN32" - WIN32_EXTRA_LIBADD="-lws2_32" - WIN32_EXTRA_LDFLAGS="-no-undefined" - if test "${PYTHON}" != "" - then - case "$host" in - *-w64-mingw*) - WIN32_EXTRA_PYTHON_LIBADD="-shrext .pyd -L${pythondir}/../../lib -lpython${PYTHON_VERSION}" - ;; - *) - WIN32_EXTRA_PYTHON_LIBADD="-L${pythondir}/../../libs -lpython$(echo ${PYTHON_VERSION} | tr -d .)" - ;; - esac - fi - ;; - *-*-cygwin*) - CYGWIN_EXTRA_LDFLAGS="-no-undefined" - if test "${PYTHON}" != "" - then - CYGWIN_EXTRA_PYTHON_LIBADD="-L/usr/lib/python${PYTHON_VERSION}/config -lpython${PYTHON_VERSION}" - fi - ;; -esac +AC_SUBST(THREAD_LIBS) +AC_SUBST(BASE_THREAD_LIBS) +AC_SUBST(WITH_THREADS) +AC_SUBST(WITH_THREAD_ALLOC) + +dnl +dnl xmllint shell history +dnl +if test "$with_history" = "yes" && test "$with_readline" != "no"; then + echo Enabling xmllint shell history + dnl check for terminal library. this is a very cool solution + dnl from octave's configure.in + unset tcap + for termlib in ncurses curses termcap terminfo termlib; do + AC_CHECK_LIB(${termlib}, tputs, [tcap="-l$termlib"]) + test -n "$tcap" && break + done + + _cppflags=$CPPFLAGS + _libs=$LIBS + if test "$with_readline" != "" && test "$with_readline" != "yes"; then + RDL_DIR=$with_readline + CPPFLAGS="${CPPFLAGS} -I$RDL_DIR/include" + LIBS="${LIBS} -L$RDL_DIR/lib" + fi + AC_CHECK_HEADER(readline/history.h, + AC_CHECK_LIB(history, append_history,[ + RDL_LIBS="-lhistory" + if test "x${RDL_DIR}" != "x"; then + RDL_CFLAGS="-I$RDL_DIR/include" + RDL_LIBS="-L$RDL_DIR/lib $RDL_LIBS" + fi + AC_DEFINE([HAVE_LIBHISTORY], [], [Define if history library is there (-lhistory)])])) + AC_CHECK_HEADER(readline/readline.h, + AC_CHECK_LIB(readline, readline,[ + RDL_LIBS="-lreadline $RDL_LIBS $tcap" + if test "x$RDL_DIR" != "x"; then + RDL_CFLAGS="-I$RDL_DIR/include" + RDL_LIBS="-L$RDL_DIR/lib $RDL_LIBS" + fi + AC_DEFINE([HAVE_LIBREADLINE], [], [Define if readline library is there (-lreadline)])], , $tcap)) + CPPFLAGS=$_cppflags + LIBS=$_libs +fi +AC_SUBST(RDL_CFLAGS) +AC_SUBST(RDL_LIBS) + +dnl +dnl Checks for zlib library. +dnl +WITH_ZLIB=0 + +if test "$with_zlib" != "no" && test "$with_zlib" != ""; then + echo "Enabling zlib compression support" + + if test "$with_zlib" != "yes"; then + Z_DIR=$with_zlib + fi -XML_PRIVATE_LIBS="$Z_LIBS $LZMA_LIBS $THREAD_LIBS $ICONV_LIBS $ICU_LIBS $LIBM $WIN32_EXTRA_LIBADD" + # Don't run pkg-config if with_zlib contains a path. + if test "x$Z_DIR" = "x"; then + # Try pkg-config first so that static linking works. + PKG_CHECK_MODULES([Z],[zlib], + [WITH_ZLIB=1; XML_PC_REQUIRES="${XML_PC_REQUIRES} zlib"], + [:]) + fi + + if test "$WITH_ZLIB" = "0"; then + _cppflags=$CPPFLAGS + _libs=$LIBS + if test "x$Z_DIR" != "x"; then + CPPFLAGS="${CPPFLAGS} -I$Z_DIR/include" + LIBS="${LIBS} -L$Z_DIR/lib" + fi + AC_CHECK_HEADERS(zlib.h, + AC_CHECK_LIB(z, gzread,[ + WITH_ZLIB=1 + if test "x${Z_DIR}" != "x"; then + Z_CFLAGS="-I${Z_DIR}/include" + Z_LIBS="-L${Z_DIR}/lib -lz" + [case ${host} in + *-*-solaris*) + Z_LIBS="-L${Z_DIR}/lib -R${Z_DIR}/lib -lz" + ;; + esac] + else + Z_LIBS="-lz" + fi]) + XML_PC_LIBS="${XML_PC_LIBS} ${Z_LIBS}" + ) + CPPFLAGS=$_cppflags + LIBS=$_libs + fi -AC_SUBST(WIN32_EXTRA_LIBADD) -AC_SUBST(WIN32_EXTRA_LDFLAGS) -AC_SUBST(WIN32_EXTRA_PYTHON_LIBADD) -AC_SUBST(CYGWIN_EXTRA_LDFLAGS) -AC_SUBST(CYGWIN_EXTRA_PYTHON_LIBADD) + XML_PRIVATE_CFLAGS="${XML_PRIVATE_CFLAGS} ${Z_CFLAGS}" + XML_PRIVATE_LIBS="${XML_PRIVATE_LIBS} ${Z_LIBS}" +fi +AC_SUBST(WITH_ZLIB) -dnl Checking the standard string functions availability dnl -dnl Note mingw* has C99 implementation that produce expected xml numbers -dnl if code use {v}snprintf functions. -dnl If you like to activate at run-time C99 compatible number output -dnl see release note for mingw runtime 3.15: -dnl http://sourceforge.net/project/shownotes.php?release_id=24832 +dnl Checks for lzma library. dnl -dnl Also *win32*config.h files redefine them for various MSC compilers. +WITH_LZMA=0 + +if test "$with_lzma" != "no" && test "$with_lzma" != ""; then + echo "Enabling lzma compression support" + + if test "$with_lzma" != "yes"; then + LZMA_DIR=$with_lzma + fi + + # Don't run pkg-config if with_lzma contains a path. + if test "x$LZMA_DIR" = "x"; then + # Try pkg-config first so that static linking works. + PKG_CHECK_MODULES([LZMA],[liblzma], + [WITH_LZMA=1; XML_PC_REQUIRES="${XML_PC_REQUIRES} liblzma"], + [:]) + fi + + # If pkg-config failed, fall back to AC_CHECK_LIB. This + # will not pick up the necessary LIBS flags for liblzma's + # private dependencies, though, so static linking may fail. + if test "$WITH_LZMA" = "0"; then + _cppflags=$CPPFLAGS + _libs=$LIBS + if test "x$LZMA_DIR" != "x"; then + CPPFLAGS="${CPPFLAGS} -I$LZMA_DIR/include" + LIBS="${LIBS} -L$LZMA_DIR/lib" + fi + AC_CHECK_HEADERS(lzma.h, + AC_CHECK_LIB(lzma, lzma_code,[ + WITH_LZMA=1 + if test "x${LZMA_DIR}" != "x"; then + LZMA_CFLAGS="-I${LZMA_DIR}/include" + LZMA_LIBS="-L${LZMA_DIR}/lib -llzma" + else + LZMA_LIBS="-llzma" + fi]) + XML_PC_LIBS="${XML_PC_LIBS} ${LZMA_LIBS}" + ) + CPPFLAGS=$_cppflags + LIBS=$_libs + fi + + XML_PRIVATE_CFLAGS="${XML_PRIVATE_CFLAGS} ${LZMA_CFLAGS}" + XML_PRIVATE_LIBS="${XML_PRIVATE_LIBS} ${LZMA_LIBS}" +fi +AC_SUBST(WITH_LZMA) +AM_CONDITIONAL(WITH_LZMA_SOURCES, test "$WITH_LZMA" = "1") + dnl -dnl So do not redefine {v}snprintf to _{v}snprintf like following: -dnl AC_DEFINE([snprintf],[_snprintf],[Win32 Std C name mangling work-around]) -dnl AC_DEFINE([vsnprintf],[_vsnprintf],[Win32 Std C name mangling work-around]) -dnl and do not redefine those functions is C-source files. +dnl Checks for iconv library. dnl -AC_CHECK_FUNCS(snprintf vsnprintf,, - NEED_TRIO=1) - -if test "$with_coverage" = "yes" && test "${GCC}" = "yes" -then - echo Enabling code coverage for GCC - EXTRA_CFLAGS="$EXTRA_CFLAGS -fprofile-arcs -ftest-coverage" - LDFLAGS="$LDFLAGS -fprofile-arcs -ftest-coverage" +WITH_ICONV=0 + +if test "$with_iconv" = "no" ; then + echo Disabling ICONV support else - echo Disabling code coverage for GCC + _cppflags=$CPPFLAGS + _libs=$LIBS + if test "$with_iconv" != "yes" && test "$with_iconv" != "" ; then + ICONV_DIR=$with_iconv + CPPFLAGS="$CPPFLAGS -I$ICONV_DIR/include" + LIBS="$LIBS -L$ICONV_DIR/lib" + fi + AC_MSG_CHECKING([for libiconv]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([#include ], [iconv_open(0,0);]) + ], [ + WITH_ICONV=1 + AC_MSG_RESULT([none required]) + ], [ + LIBS="$LIBS -liconv" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([#include ], [iconv_open(0,0);]) + ], [ + WITH_ICONV=1 + ICONV_LIBS="-liconv" + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) + ]) + if test "$WITH_ICONV" = "1" && test "$ICONV_DIR" != ""; then + ICONV_CFLAGS="-I$ICONV_DIR/include" + ICONV_LIBS="-L$ICONV_DIR/lib $ICONV_LIBS" + # Export this since our headers include iconv.h + XML_INCLUDEDIR="$XML_INCLUDEDIR -I$ICONV_DIR/include" + fi + CPPFLAGS=$_cppflags + LIBS=$_libs fi +AC_SUBST(WITH_ICONV) +AC_SUBST(ICONV_CFLAGS) + +dnl +dnl Checks for ICU library. +dnl +WITH_ICU=0 + +if test "$with_icu" != "no" && test "$with_icu" != "" ; then + echo Enabling ICU support -AC_SUBST(EXTRA_CFLAGS) + # Try pkg-config first so that static linking works. + # If this succeeeds, we ignore the WITH_ICU directory. + PKG_CHECK_MODULES([ICU], [icu-i18n], [ + WITH_ICU=1; XML_PC_REQUIRES="${XML_PC_REQUIRES} icu-i18n" + m4_ifdef([PKG_CHECK_VAR], + [PKG_CHECK_VAR([ICU_DEFS], [icu-i18n], [DEFS])]) + if test "x$ICU_DEFS" != "x"; then + ICU_CFLAGS="$ICU_CFLAGS $ICU_DEFS" + fi],[:]) + + if test "$WITH_ICU" = "0"; then + ICU_CONFIG=icu-config + if ${ICU_CONFIG} --cflags >/dev/null 2>&1 + then + WITH_ICU=1 + ICU_CFLAGS=`${ICU_CONFIG} --cflags` + ICU_LIBS=`${ICU_CONFIG} --ldflags` + XML_PC_LIBS="${XML_PC_LIBS} ${ICU_LIBS}" + else + _cppflags="${CPPFLAGS}" + _libs="${LIBS}" + if test "$with_icu" != "yes" ; then + ICU_DIR=$with_icu + CPPFLAGS="${CPPFLAGS} -I$ICU_DIR/include" + LIBS="${LIBS} -L$ICU_DIR/lib" + fi + + AC_CHECK_HEADER(unicode/ucnv.h, [ + AC_CHECK_LIB([icucore], [ucnv_open], [ + WITH_ICU=1 + ICU_LIBS=-licucore + if test "$ICU_DIR" != ""; then + ICU_CFLAGS="-I$ICU_DIR/include" + ICU_LIBS="-L$ICU_DIR/lib $ICU_LIBS" + fi])]) + XML_PC_LIBS="${XML_PC_LIBS} ${ICU_LIBS}" + CPPFLAGS=$_cppflags + LIBS=$_libs + fi + fi + + XML_PRIVATE_CFLAGS="${XML_PRIVATE_CFLAGS} ${ICU_CFLAGS}" + XML_PRIVATE_LIBS="${XML_PRIVATE_LIBS} ${ICU_LIBS}" +fi +AC_SUBST(WITH_ICU) + +dnl +dnl Crypto libraries +dnl +case "$host" in + *-*-mingw*) + CRYPTO_LIBS="-lbcrypt" + ;; +esac + +XML_LIBS="-lxml2" +XML_LIBTOOLLIBS="libxml2.la" +NON_PC_LIBS="${THREAD_LIBS} ${ICONV_LIBS} ${LIBM} ${NET_LIBS} ${CRYPTO_LIBS}" +XML_PC_LIBS="${XML_PC_LIBS} ${NON_PC_LIBS}" +XML_PRIVATE_LIBS="${XML_PRIVATE_LIBS} ${NON_PC_LIBS}" +XML_PRIVATE_CFLAGS="${XML_PRIVATE_CFLAGS} ${ICONV_CFLAGS}" + +dnl When static-only: +dnl * Duplicate xml-config static --libs into --dynamic. +dnl * Fold pkg-config private fields into main fields. +if test "x$enable_shared" = "xno"; then + XML_PRIVATE_LIBS_NO_SHARED="${XML_PRIVATE_LIBS}" + XML_PC_PRIVATE= + XML_PC_LIBS_PRIVATE= +else + XML_PRIVATE_LIBS_NO_SHARED= + XML_PC_PRIVATE=".private" + XML_PC_LIBS_PRIVATE=" +Libs.private:" +fi +AC_SUBST(XML_PRIVATE_LIBS_NO_SHARED) +AC_SUBST(XML_PC_PRIVATE) +AC_SUBST(XML_PC_LIBS_PRIVATE) +AM_SUBST_NOTMAKE(XML_PRIVATE_LIBS_NO_SHARED) +AM_SUBST_NOTMAKE(XML_PC_PRIVATE) +AM_SUBST_NOTMAKE(XML_PC_LIBS_PRIVATE) + +AC_SUBST(XML_PC_LIBS) +AC_SUBST(XML_PC_REQUIRES) +AM_SUBST_NOTMAKE(XML_PC_LIBS) +AM_SUBST_NOTMAKE(XML_PC_REQUIRES) + +AC_SUBST(AM_CFLAGS) +AC_SUBST(AM_LDFLAGS) AC_SUBST(XML_CFLAGS) AC_SUBST(XML_LIBDIR) AC_SUBST(XML_LIBS) AC_SUBST(XML_PRIVATE_LIBS) +AC_SUBST(XML_PRIVATE_CFLAGS) AC_SUBST(XML_LIBTOOLLIBS) -AC_SUBST(ICONV_LIBS) -AC_SUBST(ICU_LIBS) AC_SUBST(XML_INCLUDEDIR) -AC_SUBST(RDL_LIBS) - dnl for the spec file RELDATE=`date +'%a %b %e %Y'` AC_SUBST(RELDATE) -AC_SUBST(PYTHON_TESTS) # keep on one line for cygwin c.f. #130896 -AC_CONFIG_FILES([libxml2.spec:libxml.spec.in Makefile include/Makefile include/libxml/Makefile doc/Makefile doc/examples/Makefile doc/devhelp/Makefile example/Makefile fuzz/Makefile python/Makefile python/tests/Makefile xstc/Makefile include/libxml/xmlversion.h libxml-2.0.pc libxml-2.0-uninstalled.pc libxml2-config.cmake]) +AC_CONFIG_FILES([Makefile include/Makefile include/libxml/Makefile include/private/Makefile doc/Makefile doc/devhelp/Makefile example/Makefile fuzz/Makefile python/Makefile python/tests/Makefile xstc/Makefile include/libxml/xmlversion.h libxml-2.0.pc libxml-2.0-uninstalled.pc libxml2-config.cmake]) AC_CONFIG_FILES([python/setup.py], [chmod +x python/setup.py]) AC_CONFIG_FILES([xml2-config], [chmod +x xml2-config]) AC_OUTPUT -echo Done configuring +if test "$WARN_NO_TLS" != ""; then + echo "================================================================" + echo "WARNING: Your C compiler appears to not support thread-local" + echo "storage. Future versions of libxml2 will require this feature" + echo "for multi-threading." + echo "================================================================" +fi diff --git a/debugXML.c b/debugXML.c index f451c9d5c41..ed56b0f882a 100644 --- a/debugXML.c +++ b/debugXML.c @@ -18,18 +18,18 @@ #include #include #include -#include #include #include #include #include -#include #include #include #ifdef LIBXML_SCHEMAS_ENABLED #include #endif +#include "private/error.h" + #define DUMP_TEXT_TYPE 1 typedef struct _xmlDebugCtxt xmlDebugCtxt; @@ -154,31 +154,21 @@ static void xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - "%s", msg); + fprintf(ctxt->output, "ERROR %d: %s", error, msg); } static void LIBXML_ATTR_FORMAT(3,0) xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - msg, extra); + fprintf(ctxt->output, "ERROR %d: ", error); + fprintf(ctxt->output, msg, extra); } static void LIBXML_ATTR_FORMAT(3,0) xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - msg, extra); + fprintf(ctxt->output, "ERROR %d: ", error); + fprintf(ctxt->output, msg, extra); } /** @@ -1824,47 +1814,47 @@ xmlShellPrintXPathError(int errorType, const char *arg) switch (errorType) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s: no such node\n", arg); break; case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is an XSLT value tree\n", arg); break; } #if 0 - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Try casting the result string function (xpath builtin)\n", arg); #endif @@ -1940,26 +1930,26 @@ xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list) list->nodesetval->nodeTab[indx]); } } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Empty node set\n"); } break; #else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Node set\n"); #endif /* LIBXML_OUTPUT_ENABLED */ } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a Boolean:%s\n", xmlBoolToText(list->boolval)); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a number:%0g\n", list->floatval); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a string:%s\n", list->stringval); break; @@ -2331,6 +2321,16 @@ xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, return (0); } +static void +xmlShellPrintf(void *ctx, const char *msg, ...) { + xmlShellCtxtPtr sctxt = ctx; + va_list ap; + + va_start(ap, msg); + vfprintf(sctxt->output, msg, ap); + va_end(ap); +} + #ifdef LIBXML_SCHEMAS_ENABLED /** * xmlShellRNGValidate: @@ -2355,23 +2355,23 @@ xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas, int ret; ctxt = xmlRelaxNGNewParserCtxt(schemas); - xmlRelaxNGSetParserErrors(ctxt, xmlGenericError, xmlGenericError, NULL); + xmlRelaxNGSetParserErrors(ctxt, xmlShellPrintf, xmlShellPrintf, sctxt); relaxngschemas = xmlRelaxNGParse(ctxt); xmlRelaxNGFreeParserCtxt(ctxt); if (relaxngschemas == NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(sctxt->output, "Relax-NG schema %s failed to compile\n", schemas); return(-1); } vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); - xmlRelaxNGSetValidErrors(vctxt, xmlGenericError, xmlGenericError, NULL); + xmlRelaxNGSetValidErrors(vctxt, xmlShellPrintf, xmlShellPrintf, sctxt); ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc); if (ret == 0) { - fprintf(stderr, "%s validates\n", sctxt->filename); + fprintf(sctxt->output, "%s validates\n", sctxt->filename); } else if (ret > 0) { - fprintf(stderr, "%s fails to validate\n", sctxt->filename); + fprintf(sctxt->output, "%s fails to validate\n", sctxt->filename); } else { - fprintf(stderr, "%s validation generated an internal error\n", + fprintf(sctxt->output, "%s validation generated an internal error\n", sctxt->filename); } xmlRelaxNGFreeValidCtxt(vctxt); @@ -2506,7 +2506,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, } #ifdef W_OK if (access((char *) filename, W_OK)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Cannot write to %s\n", filename); return (-1); } @@ -2514,7 +2514,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, switch (node->type) { case XML_DOCUMENT_NODE: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2522,13 +2522,13 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_HTML_ENABLED if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } #else if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2539,7 +2539,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, f = fopen((char *) filename, "w"); if (f == NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2575,7 +2575,7 @@ xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, return (-1); #ifdef W_OK if (access((char *) filename, W_OK)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Cannot save to %s\n", filename); return (-1); } @@ -2583,25 +2583,25 @@ xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, switch (ctxt->doc->type) { case XML_DOCUMENT_NODE: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } break; case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_HTML_ENABLED if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } #else if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } #endif /* LIBXML_HTML_ENABLED */ break; default: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "To save to subparts of a document use the 'write' command\n"); return (-1); @@ -2633,9 +2633,10 @@ xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, int res = -1; if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1); - vctxt.userData = NULL; - vctxt.error = xmlGenericError; - vctxt.warning = xmlGenericError; + memset(&vctxt, 0, sizeof(vctxt)); + vctxt.error = xmlShellPrintf; + vctxt.warning = xmlShellPrintf; + vctxt.userData = ctxt; if ((dtd == NULL) || (dtd[0] == 0)) { res = xmlValidateDocument(&vctxt, ctxt->doc); @@ -2791,7 +2792,7 @@ xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, * using a environment similar to a UNIX commandline. */ void -xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, +xmlShell(xmlDocPtr doc, const char *filename, xmlShellReadlineFunc input, FILE * output) { char prompt[500] = "/ > "; @@ -2936,22 +2937,13 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlShellSave(ctxt, arg, NULL, NULL); } else if (!strcmp(command, "write")) { if (arg[0] == 0) - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Write command requires a filename argument\n"); else xmlShellWrite(ctxt, arg, ctxt->node, NULL); #endif /* LIBXML_OUTPUT_ENABLED */ } else if (!strcmp(command, "grep")) { xmlShellGrep(ctxt, arg, ctxt->node, NULL); - } else if (!strcmp(command, "free")) { - if (arg[0] == 0) { - xmlMemShow(ctxt->output, 0); - } else { - int len = 0; - - sscanf(arg, "%d", &len); - xmlMemShow(ctxt->output, len); - } } else if (!strcmp(command, "pwd")) { char dir[500]; @@ -2971,7 +2963,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -2989,37 +2981,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3028,7 +3020,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3040,7 +3032,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, #ifdef LIBXML_XPATH_ENABLED } else if (!strcmp(command, "setns")) { if (arg[0] == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "setns: prefix=[nsuri] required\n"); } else { xmlShellRegisterNamespace(ctxt, arg, NULL, NULL); @@ -3052,7 +3044,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL); } else if (!strcmp(command, "xpath")) { if (arg[0] == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "xpath: expression required\n"); } else { ctxt->pctxt->node = ctxt->node; @@ -3084,7 +3076,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3108,37 +3100,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3147,7 +3139,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3168,7 +3160,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3187,37 +3179,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3226,7 +3218,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3249,7 +3241,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET: @@ -3259,52 +3251,52 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if ((ctxt->node != NULL) && (ctxt->node->type == XML_NAMESPACE_DECL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "cannot cd to namespace\n"); ctxt->node = NULL; } } else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a %d Node Set\n", arg, list->nodesetval->nodeNr); } else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an empty Node Set\n", arg); break; case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3313,7 +3305,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3333,7 +3325,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3354,37 +3346,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3393,14 +3385,14 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; } #endif /* LIBXML_OUTPUT_ENABLED */ } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Unknown command %s\n", command); } free(cmdline); /* not xmlFree here ! */ diff --git a/dict.c b/dict.c index c29d2af77a7..49e1c6bf760 100644 --- a/dict.c +++ b/dict.c @@ -19,81 +19,28 @@ #define IN_LIBXML #include "libxml.h" +#include #include #include -#include +#include -/* - * 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(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) -#define DICT_RANDOMIZATION -#endif +#include "private/dict.h" +#include "private/globals.h" +#include "private/threads.h" -#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 -#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 */ +#include -/* - * An entry in the dictionary - */ -typedef struct _xmlDictEntry xmlDictEntry; -typedef xmlDictEntry *xmlDictEntryPtr; -struct _xmlDictEntry { - struct _xmlDictEntry *next; - const xmlChar *name; - unsigned int len; - int valid; - unsigned long okey; -}; +#ifndef SIZE_MAX + #define SIZE_MAX ((size_t) -1) +#endif + +#define MAX_FILL_NUM 7 +#define MAX_FILL_DENOM 8 +#define MIN_HASH_SIZE 8 +#define MAX_HASH_SIZE (1u << 31) typedef struct _xmlDictStrings xmlDictStrings; typedef xmlDictStrings *xmlDictStringsPtr; @@ -105,20 +52,23 @@ struct _xmlDictStrings { size_t nbStrings; xmlChar array[1]; }; + +typedef xmlHashedString xmlDictEntry; + /* * The entire dictionary */ struct _xmlDict { int ref_counter; - struct _xmlDictEntry *dict; + xmlDictEntry *table; size_t size; unsigned int nbElems; xmlDictStringsPtr strings; struct _xmlDict *subdict; /* used for randomization */ - int seed; + unsigned seed; /* used to impose a limit on size */ size_t limit; }; @@ -127,107 +77,51 @@ struct _xmlDict { * A mutex for modifying the reference counter for shared * dictionaries. */ -static xmlMutexPtr xmlDictMutex = NULL; - -/* - * Whether the dictionary mutex was initialized. - */ -static int xmlDictInitialized = 0; - -#ifdef DICT_RANDOMIZATION -#ifdef HAVE_RAND_R -/* - * Internal data for random function, protected by xmlDictMutex - */ -static unsigned int rand_seed = 0; -#endif -#endif +static xmlMutex xmlDictMutex; /** * xmlInitializeDict: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * Do the dictionary mutex initialization. + * DEPRECATED: Alias for xmlInitParser. * - * Returns 0 if initialization was already done, and 1 if that - * call led to the initialization + * Returns 0. */ -int xmlInitializeDict(void) { +int +xmlInitializeDict(void) { + xmlInitParser(); return(0); } /** - * __xmlInitializeDict: - * - * This function is not public - * Do the dictionary mutex initialization. - * this function is not thread safe, initialization should - * normally be done once at setup when called from xmlOnceInit() - * we may also land in this code if thread support is not compiled in + * xmlInitDictInternal: * - * Returns 0 if initialization was already done, and 1 if that - * call led to the initialization + * Initialize mutex. */ -int __xmlInitializeDict(void) { - if (xmlDictInitialized) - return(1); - - if ((xmlDictMutex = xmlNewMutex()) == NULL) - return(0); - xmlMutexLock(xmlDictMutex); - -#ifdef DICT_RANDOMIZATION -#ifdef HAVE_RAND_R - rand_seed = time(NULL); - rand_r(& rand_seed); -#else - srand(time(NULL)); -#endif -#endif - xmlDictInitialized = 1; - xmlMutexUnlock(xmlDictMutex); - return(1); -} - -#ifdef DICT_RANDOMIZATION -int __xmlRandom(void) { - int ret; - - if (xmlDictInitialized == 0) - __xmlInitializeDict(); - - xmlMutexLock(xmlDictMutex); -#ifdef HAVE_RAND_R - ret = rand_r(& rand_seed); -#else - ret = rand(); -#endif - xmlMutexUnlock(xmlDictMutex); - return(ret); +void +xmlInitDictInternal(void) { + xmlInitMutex(&xmlDictMutex); } -#endif /** * xmlDictCleanup: * - * DEPRECATED: This function will be made private. Call xmlCleanupParser + * DEPRECATED: This function is a no-op. Call xmlCleanupParser * to free global state but see the warnings there. xmlCleanupParser * should be only called once at program exit. In most cases, you don't * have call cleanup functions at all. - * - * Free the dictionary mutex. Do not call unless sure the library - * is not in use anymore ! */ void xmlDictCleanup(void) { - if (!xmlDictInitialized) - return; - - xmlFreeMutex(xmlDictMutex); +} - xmlDictInitialized = 0; +/** + * xmlCleanupDictInternal: + * + * Free the dictionary mutex. + */ +void +xmlCleanupDictInternal(void) { + xmlCleanupMutex(&xmlDictMutex); } /* @@ -247,9 +141,6 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) { size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ size_t limit = 0; -#ifdef DICT_DEBUG_PATTERNS - fprintf(stderr, "-"); -#endif pool = dict->strings; while (pool != NULL) { if ((size_t)(pool->end - pool->free) > namelen) @@ -266,10 +157,20 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) { return(NULL); } - if (size == 0) size = 1000; - else size *= 4; /* exponential growth */ - if (size < 4 * namelen) - size = 4 * namelen; /* just in case ! */ + if (size == 0) { + size = 1000; + } else { + if (size < (SIZE_MAX - sizeof(xmlDictStrings)) / 4) + size *= 4; /* exponential growth */ + else + size = SIZE_MAX - sizeof(xmlDictStrings); + } + if (size / 4 < namelen) { + if ((size_t) namelen + 0 < (SIZE_MAX - sizeof(xmlDictStrings)) / 4) + size = 4 * (size_t) namelen; /* just in case ! */ + else + return(NULL); + } pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); if (pool == NULL) return(NULL); @@ -279,9 +180,6 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) { pool->end = &pool->array[size]; pool->next = dict->strings; dict->strings = pool; -#ifdef DICT_DEBUG_PATTERNS - fprintf(stderr, "+"); -#endif } found_pool: ret = pool->free; @@ -313,11 +211,6 @@ xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen, size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ size_t limit = 0; - if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); - -#ifdef DICT_DEBUG_PATTERNS - fprintf(stderr, "="); -#endif pool = dict->strings; while (pool != NULL) { if ((size_t)(pool->end - pool->free) > namelen + plen + 1) @@ -347,9 +240,6 @@ xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen, pool->end = &pool->array[size]; pool->next = dict->strings; dict->strings = pool; -#ifdef DICT_DEBUG_PATTERNS - fprintf(stderr, "+"); -#endif } found_pool: ret = pool->free; @@ -363,209 +253,6 @@ found_pool: 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 - */ - -#ifdef __clang__ -ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") -#endif -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. - */ -#ifdef __clang__ -ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") -#endif -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]; - /* Falls through. */ - case 9: value += name[8]; - /* Falls through. */ - case 8: value += name[7]; - /* Falls through. */ - case 7: value += name[6]; - /* Falls through. */ - case 6: value += name[5]; - /* Falls through. */ - case 5: value += name[4]; - /* Falls through. */ - case 4: value += name[3]; - /* Falls through. */ - case 3: value += name[2]; - /* Falls through. */ - case 2: value += name[1]; - /* Falls through. */ - 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) { - int offset = len - (plen + 1 + 1); - if (offset < 0) - offset = len - (10 + 1); - value += name[offset]; - len = 10; - if (plen > 10) - plen = 10; - } - switch (plen) { - case 10: value += prefix[9]; - /* Falls through. */ - case 9: value += prefix[8]; - /* Falls through. */ - case 8: value += prefix[7]; - /* Falls through. */ - case 7: value += prefix[6]; - /* Falls through. */ - case 6: value += prefix[5]; - /* Falls through. */ - case 5: value += prefix[4]; - /* Falls through. */ - case 4: value += prefix[3]; - /* Falls through. */ - case 3: value += prefix[2]; - /* Falls through. */ - case 2: value += prefix[1]; - /* Falls through. */ - case 1: value += prefix[0]; - /* Falls through. */ - default: break; - } - len -= plen; - if (len > 0) { - value += (unsigned long) ':'; - len--; - } - switch (len) { - case 10: value += name[9]; - /* Falls through. */ - case 9: value += name[8]; - /* Falls through. */ - case 8: value += name[7]; - /* Falls through. */ - case 7: value += name[6]; - /* Falls through. */ - case 6: value += name[5]; - /* Falls through. */ - case 5: value += name[4]; - /* Falls through. */ - case 4: value += name[3]; - /* Falls through. */ - case 3: value += name[2]; - /* Falls through. */ - case 2: value += name[1]; - /* Falls through. */ - case 1: value += name[0]; - /* Falls through. */ - default: break; - } - return(value); -} - /** * xmlDictCreate: * @@ -577,36 +264,24 @@ xmlDictPtr xmlDictCreate(void) { xmlDictPtr dict; - if (!xmlDictInitialized) - if (!__xmlInitializeDict()) - return(NULL); - -#ifdef DICT_DEBUG_PATTERNS - fprintf(stderr, "C"); -#endif + xmlInitParser(); dict = xmlMalloc(sizeof(xmlDict)); - if (dict) { - dict->ref_counter = 1; - dict->limit = 0; - - 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 = __xmlRandom(); -#else - dict->seed = 0; + if (dict == NULL) + return(NULL); + dict->ref_counter = 1; + dict->limit = 0; + + dict->size = 0; + dict->nbElems = 0; + dict->table = NULL; + dict->strings = NULL; + dict->subdict = NULL; + dict->seed = xmlRandom(); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dict->seed = 0; #endif - return(dict); - } - xmlFree(dict); - } - return(NULL); + return(dict); } /** @@ -625,9 +300,6 @@ 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); @@ -645,152 +317,13 @@ xmlDictCreateSub(xmlDictPtr sub) { */ int xmlDictReference(xmlDictPtr dict) { - if (!xmlDictInitialized) - if (!__xmlInitializeDict()) - return(-1); - if (dict == NULL) return -1; - xmlMutexLock(xmlDictMutex); + xmlMutexLock(&xmlDictMutex); dict->ref_counter++; - xmlMutexUnlock(xmlDictMutex); + xmlMutexUnlock(&xmlDictMutex); return(0); } -/** - * xmlDictGrow: - * @dict: the dictionary - * @size: the new size of the dictionary - * - * resize the dictionary - * - * Returns 0 in case of success, -1 in case of failure - */ -static int -xmlDictGrow(xmlDictPtr dict, size_t size) { - unsigned long key, okey; - size_t 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 here - * result is losing an entry and unicity guarantee - */ - 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 %lu to %lu, %u elems\n", oldsize, size, nbElem); -#endif - - return(ret); -} - /** * xmlDictFree: * @dict: the dictionary @@ -800,49 +333,27 @@ xmlDictGrow(xmlDictPtr dict, size_t size) { */ void xmlDictFree(xmlDictPtr dict) { - size_t 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 */ - xmlMutexLock(xmlDictMutex); + xmlMutexLock(&xmlDictMutex); dict->ref_counter--; if (dict->ref_counter > 0) { - xmlMutexUnlock(xmlDictMutex); + xmlMutexUnlock(&xmlDictMutex); return; } - xmlMutexUnlock(xmlDictMutex); + xmlMutexUnlock(&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); + if (dict->table) { + xmlFree(dict->table); } pool = dict->strings; while (pool != NULL) { @@ -854,445 +365,685 @@ xmlDictFree(xmlDictPtr dict) { } /** - * xmlDictLookup: + * xmlDictOwns: * @dict: the dictionary - * @name: the name of the userdata - * @len: the length of the name, if -1 it is recomputed + * @str: the string * - * Add the @name to the dictionary @dict if not present. + * check if a string is owned by the dictionary * - * Returns the internal copy of the name or NULL in case of internal error + * Returns 1 if true, 0 if false and -1 in case of error + * -1 in case of error */ -const xmlChar * -xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { - unsigned long key, okey, nbi = 0; - xmlDictEntryPtr entry; - xmlDictEntryPtr insert; - const xmlChar *ret; - unsigned int l; +int +xmlDictOwns(xmlDictPtr dict, const xmlChar *str) { + xmlDictStringsPtr pool; - if ((dict == NULL) || (name == NULL)) - return(NULL); + 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); +} - if (len < 0) - l = strlen((const char *) name); - else - l = len; +/** + * xmlDictSize: + * @dict: the dictionary + * + * Query the number of elements installed in the hash @dict. + * + * Returns the number of elements in the dictionary 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); +} - if (((dict->limit > 0) && (l >= dict->limit)) || - (l > INT_MAX / 2)) - return(NULL); +/** + * xmlDictSetLimit: + * @dict: the dictionary + * @limit: the limit in bytes + * + * Set a size limit for the dictionary + * Added in 2.9.0 + * + * Returns the previous limit of the dictionary or 0 + */ +size_t +xmlDictSetLimit(xmlDictPtr dict, size_t limit) { + size_t ret; - /* - * Check for duplicate and insertion location. - */ - okey = xmlDictComputeKey(dict, 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) { -#ifdef __GNUC__ - if ((insert->okey == okey) && (insert->len == l)) { - if (!memcmp(insert->name, name, l)) - return(insert->name); - } -#else - if ((insert->okey == okey) && (insert->len == l) && - (!xmlStrncmp(insert->name, name, l))) - return(insert->name); -#endif - nbi++; - } -#ifdef __GNUC__ - if ((insert->okey == okey) && (insert->len == l)) { - if (!memcmp(insert->name, name, l)) - return(insert->name); - } -#else - if ((insert->okey == okey) && (insert->len == l) && - (!xmlStrncmp(insert->name, name, l))) - return(insert->name); -#endif + if (dict == NULL) + return(0); + ret = dict->limit; + dict->limit = limit; + return(ret); +} + +/** + * xmlDictGetUsage: + * @dict: the dictionary + * + * Get how much memory is used by a dictionary for strings + * Added in 2.9.0 + * + * Returns the amount of strings allocated + */ +size_t +xmlDictGetUsage(xmlDictPtr dict) { + xmlDictStringsPtr pool; + size_t limit = 0; + + if (dict == NULL) + return(0); + pool = dict->strings; + while (pool != NULL) { + limit += pool->size; + pool = pool->next; } + return(limit); +} - 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, 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) { -#ifdef __GNUC__ - if ((tmp->okey == skey) && (tmp->len == l)) { - if (!memcmp(tmp->name, name, l)) - return(tmp->name); - } -#else - if ((tmp->okey == skey) && (tmp->len == l) && - (!xmlStrncmp(tmp->name, name, l))) - return(tmp->name); -#endif - nbi++; - } -#ifdef __GNUC__ - if ((tmp->okey == skey) && (tmp->len == l)) { - if (!memcmp(tmp->name, name, l)) - return(tmp->name); - } -#else - if ((tmp->okey == skey) && (tmp->len == l) && - (!xmlStrncmp(tmp->name, name, l))) - return(tmp->name); -#endif - } - key = okey % dict->size; +/***************************************************************** + * + * The code below was rewritten and is additionally licensed under + * the main license in file 'Copyright'. + * + *****************************************************************/ + +ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xmlDictHashName(unsigned seed, const xmlChar* data, size_t maxLen, + size_t *plen) { + unsigned h1, h2; + size_t i; + + HASH_INIT(h1, h2, seed); + + for (i = 0; i < maxLen && data[i]; i++) { + HASH_UPDATE(h1, h2, data[i]); } - ret = xmlDictAddString(dict, name, l); - if (ret == NULL) - return(NULL); - if (insert == NULL) { - entry = &(dict->dict[key]); - } else { - entry = xmlMalloc(sizeof(xmlDictEntry)); - if (entry == NULL) - return(NULL); + HASH_FINISH(h1, h2); + + *plen = i; + return(h2 | MAX_HASH_SIZE); +} + +ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xmlDictHashQName(unsigned seed, const xmlChar *prefix, const xmlChar *name, + size_t *pplen, size_t *plen) { + unsigned h1, h2; + size_t i; + + HASH_INIT(h1, h2, seed); + + for (i = 0; prefix[i] != 0; i++) { + HASH_UPDATE(h1, h2, prefix[i]); } - entry->name = ret; - entry->len = l; - entry->next = NULL; - entry->valid = 1; - entry->okey = okey; + *pplen = i; + HASH_UPDATE(h1, h2, ':'); - if (insert != NULL) - insert->next = entry; + for (i = 0; name[i] != 0; i++) { + HASH_UPDATE(h1, h2, name[i]); + } + *plen = i; - dict->nbElems++; + HASH_FINISH(h1, h2); - 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); + /* + * Always set the upper bit of hash values since 0 means an unoccupied + * bucket. + */ + return(h2 | MAX_HASH_SIZE); +} + +/** + * xmlDictComputeHash: + * @dict: dictionary + * @string: C string + * + * Compute the hash value of a C string. + * + * Returns the hash value. + */ +unsigned +xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) { + size_t len; + return(xmlDictHashName(dict->seed, string, SIZE_MAX, &len)); +} + +#define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n))) + +/** + * xmlDictCombineHash: + * @v1: first hash value + * @v2: second hash value + * + * Combine two hash values. + * + * Returns the combined hash value. + */ +ATTRIBUTE_NO_SANITIZE_INTEGER +unsigned +xmlDictCombineHash(unsigned v1, unsigned v2) { + /* + * The upper bit of hash values is always set, so we have to operate on + * 31-bit hashes here. + */ + v1 ^= v2; + v1 += HASH_ROL31(v2, 5); + + return((v1 & 0xFFFFFFFF) | 0x80000000); +} + +/** + * xmlDictFindEntry: + * @dict: dict + * @prefix: optional QName prefix + * @name: string + * @len: length of string + * @hashValue: valid hash value of string + * @pfound: result of search + * + * Try to find a matching hash table entry. If an entry was found, set + * @found to 1 and return the entry. Otherwise, set @found to 0 and return + * the location where a new entry should be inserted. + */ +ATTRIBUTE_NO_SANITIZE_INTEGER +static xmlDictEntry * +xmlDictFindEntry(const xmlDict *dict, const xmlChar *prefix, + const xmlChar *name, int len, unsigned hashValue, + int *pfound) { + xmlDictEntry *entry; + unsigned mask, pos, displ; + int found = 0; + + mask = dict->size - 1; + pos = hashValue & mask; + entry = &dict->table[pos]; + + if (entry->hashValue != 0) { + /* + * Robin hood hashing: abort if the displacement of the entry + * is smaller than the displacement of the key we look for. + * This also stops at the correct position when inserting. + */ + displ = 0; + + do { + if (entry->hashValue == hashValue) { + if (prefix == NULL) { + /* + * name is not necessarily null-terminated. + */ + if ((strncmp((const char *) entry->name, + (const char *) name, len) == 0) && + (entry->name[len] == 0)) { + found = 1; + break; + } + } else { + if (xmlStrQEqual(prefix, name, entry->name)) { + found = 1; + break; + } + } + } + + displ++; + pos++; + entry++; + if ((pos & mask) == 0) + entry = dict->table; + } while ((entry->hashValue != 0) && + (((pos - entry->hashValue) & mask) >= displ)); } - /* Note that entry may have been freed at this point by xmlDictGrow */ - return(ret); + *pfound = found; + return(entry); } /** - * xmlDictExists: - * @dict: the dictionary - * @name: the name of the userdata - * @len: the length of the name, if -1 it is recomputed + * xmlDictGrow: + * @dict: dictionary + * @size: new size of the dictionary * - * Check if the @name exists in the dictionary @dict. + * Resize the dictionary hash table. * - * Returns the internal copy of the name or NULL if not found. + * Returns 0 in case of success, -1 if a memory allocation failed. */ -const xmlChar * -xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { - unsigned long key, okey, nbi = 0; - xmlDictEntryPtr insert; - unsigned int l; +static int +xmlDictGrow(xmlDictPtr dict, unsigned size) { + const xmlDictEntry *oldentry, *oldend, *end; + xmlDictEntry *table; + unsigned oldsize, i; - if ((dict == NULL) || (name == NULL)) - return(NULL); + /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */ + if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0])) + return(-1); + table = xmlMalloc(size * sizeof(table[0])); + if (table == NULL) + return(-1); + memset(table, 0, size * sizeof(table[0])); - if (len < 0) - l = strlen((const char *) name); - else - l = len; - if (((dict->limit > 0) && (l >= dict->limit)) || - (l > INT_MAX / 2)) - return(NULL); + oldsize = dict->size; + if (oldsize == 0) + goto done; + + oldend = &dict->table[oldsize]; + end = &table[size]; /* - * Check for duplicate and insertion location. + * Robin Hood sorting order is maintained if we + * + * - compute dict indices with modulo + * - resize by an integer factor + * - start to copy from the beginning of a probe sequence */ - okey = xmlDictComputeKey(dict, 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) { -#ifdef __GNUC__ - if ((insert->okey == okey) && (insert->len == l)) { - if (!memcmp(insert->name, name, l)) - return(insert->name); - } -#else - if ((insert->okey == okey) && (insert->len == l) && - (!xmlStrncmp(insert->name, name, l))) - return(insert->name); -#endif - nbi++; - } -#ifdef __GNUC__ - if ((insert->okey == okey) && (insert->len == l)) { - if (!memcmp(insert->name, name, l)) - return(insert->name); - } -#else - if ((insert->okey == okey) && (insert->len == l) && - (!xmlStrncmp(insert->name, name, l))) - return(insert->name); -#endif + oldentry = dict->table; + while (oldentry->hashValue != 0) { + if (++oldentry >= oldend) + oldentry = dict->table; } - 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, 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) { -#ifdef __GNUC__ - if ((tmp->okey == skey) && (tmp->len == l)) { - if (!memcmp(tmp->name, name, l)) - return(tmp->name); - } -#else - if ((tmp->okey == skey) && (tmp->len == l) && - (!xmlStrncmp(tmp->name, name, l))) - return(tmp->name); -#endif - nbi++; - } -#ifdef __GNUC__ - if ((tmp->okey == skey) && (tmp->len == l)) { - if (!memcmp(tmp->name, name, l)) - return(tmp->name); - } -#else - if ((tmp->okey == skey) && (tmp->len == l) && - (!xmlStrncmp(tmp->name, name, l))) - return(tmp->name); -#endif - } + for (i = 0; i < oldsize; i++) { + if (oldentry->hashValue != 0) { + xmlDictEntry *entry = &table[oldentry->hashValue & (size - 1)]; + + while (entry->hashValue != 0) { + if (++entry >= end) + entry = table; + } + *entry = *oldentry; + } + + if (++oldentry >= oldend) + oldentry = dict->table; } - /* not found */ - return(NULL); + xmlFree(dict->table); + +done: + dict->table = table; + dict->size = size; + + return(0); } /** - * xmlDictQLookup: - * @dict: the dictionary - * @prefix: the prefix - * @name: the name - * - * Add the QName @prefix:@name to the hash @dict if not present. + * xmlDictLookupInternal: + * @dict: dict + * @prefix: optional QName prefix + * @name: string + * @maybeLen: length of string or -1 if unknown + * @update: whether the string should be added * - * Returns the internal copy of the QName or NULL in case of internal error + * Internal lookup and update function. */ -const xmlChar * -xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { - unsigned long okey, key, nbi = 0; - xmlDictEntryPtr entry; - xmlDictEntryPtr insert; +ATTRIBUTE_NO_SANITIZE_INTEGER +static const xmlDictEntry * +xmlDictLookupInternal(xmlDictPtr dict, const xmlChar *prefix, + const xmlChar *name, int maybeLen, int update) { + xmlDictEntry *entry = NULL; const xmlChar *ret; - unsigned int len, plen, l; + unsigned hashValue; + size_t maxLen, len, plen, klen; + int found = 0; 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; + maxLen = (maybeLen < 0) ? SIZE_MAX : (size_t) maybeLen; + + if (prefix == NULL) { + hashValue = xmlDictHashName(dict->seed, name, maxLen, &len); + if (len > INT_MAX / 2) + return(NULL); + klen = len; + } else { + hashValue = xmlDictHashQName(dict->seed, prefix, name, &plen, &len); + if ((len > INT_MAX / 2) || (plen >= INT_MAX / 2 - len)) + return(NULL); + klen = plen + 1 + len; + } + + if ((dict->limit > 0) && (klen >= dict->limit)) + return(NULL); /* - * Check for duplicate and insertion location. + * Check for an existing entry */ - 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->size > 0) + entry = xmlDictFindEntry(dict, prefix, name, klen, hashValue, &found); + if (found) + return(entry); + + if ((dict->subdict != NULL) && (dict->subdict->size > 0)) { + xmlDictEntry *subEntry; + unsigned subHashValue; + + if (prefix == NULL) + subHashValue = xmlDictHashName(dict->subdict->seed, name, len, + &len); + else + subHashValue = xmlDictHashQName(dict->subdict->seed, prefix, name, + &plen, &len); + subEntry = xmlDictFindEntry(dict->subdict, prefix, name, klen, + subHashValue, &found); + if (found) + return(subEntry); } - 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; + if (!update) + return(NULL); + + /* + * Grow the hash table if needed + */ + if (dict->nbElems + 1 > dict->size / MAX_FILL_DENOM * MAX_FILL_NUM) { + unsigned newSize, mask, displ, pos; + + if (dict->size == 0) { + newSize = MIN_HASH_SIZE; + } else { + if (dict->size >= MAX_HASH_SIZE) + return(NULL); + newSize = dict->size * 2; + } + if (xmlDictGrow(dict, newSize) != 0) + return(NULL); + + /* + * Find new entry + */ + mask = dict->size - 1; + displ = 0; + pos = hashValue & mask; + entry = &dict->table[pos]; + + while ((entry->hashValue != 0) && + ((pos - entry->hashValue) & mask) >= displ) { + displ++; + pos++; + entry++; + if ((pos & mask) == 0) + entry = dict->table; + } } - ret = xmlDictAddQString(dict, prefix, plen, name, l); + if (prefix == NULL) + ret = xmlDictAddString(dict, name, len); + else + ret = xmlDictAddQString(dict, prefix, plen, name, len); if (ret == NULL) return(NULL); - if (insert == NULL) { - entry = &(dict->dict[key]); - } else { - entry = xmlMalloc(sizeof(xmlDictEntry)); - if (entry == NULL) - return(NULL); + + /* + * Shift the remainder of the probe sequence to the right + */ + if (entry->hashValue != 0) { + const xmlDictEntry *end = &dict->table[dict->size]; + const xmlDictEntry *cur = entry; + + do { + cur++; + if (cur >= end) + cur = dict->table; + } while (cur->hashValue != 0); + + if (cur < entry) { + /* + * If we traversed the end of the buffer, handle the part + * at the start of the buffer. + */ + memmove(&dict->table[1], dict->table, + (char *) cur - (char *) dict->table); + cur = end - 1; + dict->table[0] = *cur; + } + + memmove(&entry[1], entry, (char *) cur - (char *) entry); } - entry->name = ret; - entry->len = len; - entry->next = NULL; - entry->valid = 1; - entry->okey = okey; - if (insert != NULL) - insert->next = entry; + /* + * Populate entry + */ + entry->hashValue = hashValue; + entry->name = ret; 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); + return(entry); } /** - * xmlDictOwns: - * @dict: the dictionary - * @str: the string + * xmlDictLookup: + * @dict: dictionary + * @name: string key + * @len: length of the key, if -1 it is recomputed * - * check if a string is owned by the dictionary + * Lookup a string and add it to the dictionary if it wasn't found. * - * Returns 1 if true, 0 if false and -1 in case of error - * -1 in case of error + * Returns the interned copy of the string or NULL if a memory allocation + * failed. */ -int -xmlDictOwns(xmlDictPtr dict, const xmlChar *str) { - xmlDictStringsPtr pool; +const xmlChar * +xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { + const xmlDictEntry *entry; - 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); + entry = xmlDictLookupInternal(dict, NULL, name, len, 1); + if (entry == NULL) + return(NULL); + return(entry->name); } /** - * xmlDictSize: - * @dict: the dictionary + * xmlDictLookupHashed: + * @dict: dictionary + * @name: string key + * @len: length of the key, if -1 it is recomputed * - * Query the number of elements installed in the hash @dict. + * Lookup a dictionary entry and add the string to the dictionary if + * it wasn't found. * - * Returns the number of elements in the dictionary or - * -1 in case of error + * Returns the dictionary entry. */ -int -xmlDictSize(xmlDictPtr dict) { - if (dict == NULL) - return(-1); - if (dict->subdict) - return(dict->nbElems + dict->subdict->nbElems); - return(dict->nbElems); +xmlHashedString +xmlDictLookupHashed(xmlDictPtr dict, const xmlChar *name, int len) { + const xmlDictEntry *entry; + xmlHashedString ret; + + entry = xmlDictLookupInternal(dict, NULL, name, len, 1); + + if (entry == NULL) { + ret.name = NULL; + ret.hashValue = 0; + } else { + ret = *entry; + } + + return(ret); } /** - * xmlDictSetLimit: + * xmlDictExists: * @dict: the dictionary - * @limit: the limit in bytes + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed * - * Set a size limit for the dictionary - * Added in 2.9.0 + * Check if a string exists in the dictionary. * - * Returns the previous limit of the dictionary or 0 + * Returns the internal copy of the name or NULL if not found. */ -size_t -xmlDictSetLimit(xmlDictPtr dict, size_t limit) { - size_t ret; +const xmlChar * +xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { + const xmlDictEntry *entry; - if (dict == NULL) - return(0); - ret = dict->limit; - dict->limit = limit; - return(ret); + entry = xmlDictLookupInternal(dict, NULL, name, len, 0); + if (entry == NULL) + return(NULL); + return(entry->name); } /** - * xmlDictGetUsage: + * xmlDictQLookup: * @dict: the dictionary + * @prefix: the prefix + * @name: the name * - * Get how much memory is used by a dictionary for strings - * Added in 2.9.0 + * Lookup the QName @prefix:@name and add it to the dictionary if + * it wasn't found. * - * Returns the amount of strings allocated + * Returns the interned copy of the string or NULL if a memory allocation + * failed. */ -size_t -xmlDictGetUsage(xmlDictPtr dict) { - xmlDictStringsPtr pool; - size_t limit = 0; +const xmlChar * +xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { + const xmlDictEntry *entry; - if (dict == NULL) - return(0); - pool = dict->strings; - while (pool != NULL) { - limit += pool->size; - pool = pool->next; + entry = xmlDictLookupInternal(dict, prefix, name, -1, 1); + if (entry == NULL) + return(NULL); + return(entry->name); +} + +/* + * Pseudo-random generator + */ + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include + #include +#elif defined(HAVE_GETENTROPY) + #ifdef HAVE_UNISTD_H + #include + #endif + #ifdef HAVE_SYS_RANDOM_H + #include + #endif +#else + #include +#endif + +static xmlMutex xmlRngMutex; + +static unsigned globalRngState[2]; + +/* + * xmlInitRandom: + * + * Initialize the PRNG. + */ +ATTRIBUTE_NO_SANITIZE_INTEGER +void +xmlInitRandom(void) { + xmlInitMutex(&xmlRngMutex); + + { +#ifdef _WIN32 + NTSTATUS status; + + status = BCryptGenRandom(NULL, (unsigned char *) globalRngState, + sizeof(globalRngState), + BCRYPT_USE_SYSTEM_PREFERRED_RNG); + if (!BCRYPT_SUCCESS(status)) { + fprintf(stderr, "libxml2: BCryptGenRandom failed with " + "error code %lu\n", GetLastError()); + abort(); + } +#elif defined(HAVE_GETENTROPY) + while (1) { + if (getentropy(globalRngState, sizeof(globalRngState)) == 0) + break; + + if (errno != EINTR) { + fprintf(stderr, "libxml2: getentropy failed with " + "error code %d\n", errno); + abort(); + } + } +#else + int var; + + globalRngState[0] = + (unsigned) time(NULL) ^ + HASH_ROL((unsigned) ((size_t) &xmlInitRandom & 0xFFFFFFFF), 8); + globalRngState[1] = + HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^ + HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24); +#endif } - return(limit); +} + +/* + * xmlCleanupRandom: + * + * Clean up PRNG globals. + */ +void +xmlCleanupRandom(void) { + xmlCleanupMutex(&xmlRngMutex); +} + +ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xoroshiro64ss(unsigned *s) { + unsigned s0 = s[0]; + unsigned s1 = s[1]; + unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5; + + s1 ^= s0; + s[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9); + s[1] = HASH_ROL(s1, 13); + + return(result & 0xFFFFFFFF); +} + +/* + * xmlGlobalRandom: + * + * Generate a pseudo-random value using the global PRNG. + * + * Returns a random value. + */ +unsigned +xmlGlobalRandom(void) { + unsigned ret; + + xmlMutexLock(&xmlRngMutex); + ret = xoroshiro64ss(globalRngState); + xmlMutexUnlock(&xmlRngMutex); + + return(ret); +} + +/* + * xmlRandom: + * + * Generate a pseudo-random value using the thread-local PRNG. + * + * Returns a random value. + */ +unsigned +xmlRandom(void) { +#ifdef LIBXML_THREAD_ENABLED + return(xoroshiro64ss(xmlGetLocalRngState())); +#else + return(xmlGlobalRandom()); +#endif } diff --git a/enc.h b/enc.h deleted file mode 100644 index a69a5d03c85..00000000000 --- a/enc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Summary: Internal Interfaces for encoding in libxml2 - * Description: this module describes a few interfaces which were - * added along with the API changes in 2.9.0 - * those are private routines at this point - * - * Copy: See Copyright for the status of this software. - * - * Author: Daniel Veillard - */ - -#ifndef __XML_ENC_H__ -#define __XML_ENC_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int xmlCharEncFirstLineInt(xmlCharEncodingHandler *handler, xmlBufferPtr out, - xmlBufferPtr in, int len); -int xmlCharEncFirstLineInput(xmlParserInputBufferPtr input, int len); -int xmlCharEncInput(xmlParserInputBufferPtr input, int flush); -int xmlCharEncOutput(xmlOutputBufferPtr output, int init); - -#ifdef __cplusplus -} -#endif -#endif /* __XML_ENC_H__ */ - - diff --git a/encoding.c b/encoding.c index 5465359f244..14ffafddbc0 100644 --- a/encoding.c +++ b/encoding.c @@ -34,14 +34,15 @@ #include #include +#include #ifdef LIBXML_HTML_ENABLED #include #endif -#include #include -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" #ifdef LIBXML_ICU_ENABLED #include @@ -57,9 +58,6 @@ struct _uconv_t { }; #endif -static xmlCharEncodingHandlerPtr xmlUTF16LEHandler = NULL; -static xmlCharEncodingHandlerPtr xmlUTF16BEHandler = NULL; - typedef struct _xmlCharEncodingAlias xmlCharEncodingAlias; typedef xmlCharEncodingAlias *xmlCharEncodingAliasPtr; struct _xmlCharEncodingAlias { @@ -71,96 +69,8 @@ static xmlCharEncodingAliasPtr xmlCharEncodingAliases = NULL; static int xmlCharEncodingAliasesNb = 0; static int xmlCharEncodingAliasesMax = 0; -#if defined(LIBXML_ICONV_ENABLED) || defined(LIBXML_ICU_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 information - * - * 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 LIBXML_ATTR_FORMAT(2,0) -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); -} - -#ifdef LIBXML_ICU_ENABLED -static uconv_t* -openIcuConverter(const char* name, int toUnicode) -{ - UErrorCode status = U_ZERO_ERROR; - uconv_t *conv = (uconv_t *) xmlMalloc(sizeof(uconv_t)); - if (conv == NULL) - return NULL; - - conv->pivot_source = conv->pivot_buf; - conv->pivot_target = conv->pivot_buf; - - conv->uconv = ucnv_open(name, &status); - if (U_FAILURE(status)) - goto error; - - status = U_ZERO_ERROR; - if (toUnicode) { - ucnv_setToUCallBack(conv->uconv, UCNV_TO_U_CALLBACK_STOP, - NULL, NULL, NULL, &status); - } - else { - ucnv_setFromUCallBack(conv->uconv, UCNV_FROM_U_CALLBACK_STOP, - NULL, NULL, NULL, &status); - } - if (U_FAILURE(status)) - goto error; - - status = U_ZERO_ERROR; - conv->utf8 = ucnv_open("UTF-8", &status); - if (U_SUCCESS(status)) - return conv; - -error: - if (conv->uconv) - ucnv_close(conv->uconv); - xmlFree(conv); - return NULL; -} - -static void -closeIcuConverter(uconv_t *conv) -{ - if (conv != NULL) { - ucnv_close(conv->uconv); - ucnv_close(conv->utf8); - xmlFree(conv); - } -} -#endif /* LIBXML_ICU_ENABLED */ - /************************************************************************ * * * Conversions To/From UTF8 encoding * @@ -176,7 +86,9 @@ closeIcuConverter(uconv_t *conv) * * 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 + * + * Returns the number of bytes written or an XML_ENC_ERR code. + * * 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 produced. @@ -202,7 +114,7 @@ asciiToUTF8(unsigned char* out, int *outlen, } else { *outlen = out - outstart; *inlen = processed - base; - return(-1); + return(XML_ENC_ERR_INPUT); } processed = (const unsigned char*) in; @@ -223,7 +135,8 @@ asciiToUTF8(unsigned char* out, int *outlen, * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. + * * 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 produced. @@ -239,7 +152,8 @@ UTF8Toascii(unsigned char* out, int *outlen, unsigned int c, d; int trailing; - if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) + return(XML_ENC_ERR_INTERNAL); if (in == NULL) { /* * initialization nothing to do @@ -257,7 +171,7 @@ UTF8Toascii(unsigned char* out, int *outlen, /* trailing byte in leading position */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } 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; } @@ -265,7 +179,7 @@ UTF8Toascii(unsigned char* out, int *outlen, /* no chance for this in Ascii */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } if (inend - in < trailing) { @@ -288,7 +202,7 @@ UTF8Toascii(unsigned char* out, int *outlen, /* no chance for this in Ascii */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } processed = in; } @@ -307,7 +221,9 @@ UTF8Toascii(unsigned char* out, int *outlen, * * 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 + * + * Returns the number of bytes written or an XML_ENC_ERR code. + * * 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 produced. @@ -322,7 +238,7 @@ isolat1ToUTF8(unsigned char* out, int *outlen, const unsigned char* instop; if ((out == NULL) || (in == NULL) || (outlen == NULL) || (inlen == NULL)) - return(-1); + return(XML_ENC_ERR_INTERNAL); outend = out + *outlen; inend = in + (*inlen); @@ -356,7 +272,8 @@ isolat1ToUTF8(unsigned char* out, int *outlen, * * No op copy operation for UTF8 handling. * - * Returns the number of bytes written, or -1 if lack of space. + * Returns the number of bytes written or an XML_ENC_ERR code. + * * The value of *inlen after return is the number of octets consumed * if the return value is positive, else unpredictable. */ @@ -367,7 +284,7 @@ UTF8ToUTF8(unsigned char* out, int *outlen, int len; if ((out == NULL) || (outlen == NULL) || (inlenb == NULL)) - return(-1); + return(XML_ENC_ERR_INTERNAL); if (inb == NULL) { /* inb == NULL means output is initialized. */ *outlen = 0; @@ -380,7 +297,7 @@ UTF8ToUTF8(unsigned char* out, int *outlen, len = *outlen; } if (len < 0) - return(-1); + return(XML_ENC_ERR_INTERNAL); /* * FIXME: Conversion functions must assure valid UTF-8, so we have @@ -406,8 +323,8 @@ UTF8ToUTF8(unsigned char* out, int *outlen, * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. + * * 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 produced. @@ -423,7 +340,8 @@ UTF8Toisolat1(unsigned char* out, int *outlen, unsigned int c, d; int trailing; - if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) + return(XML_ENC_ERR_INTERNAL); if (in == NULL) { /* * initialization nothing to do @@ -441,7 +359,7 @@ UTF8Toisolat1(unsigned char* out, int *outlen, /* trailing byte in leading position */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } 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; } @@ -449,7 +367,7 @@ UTF8Toisolat1(unsigned char* out, int *outlen, /* no chance for this in IsoLat1 */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } if (inend - in < trailing) { @@ -462,7 +380,7 @@ UTF8Toisolat1(unsigned char* out, int *outlen, if (((d= *in++) & 0xC0) != 0x80) { *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } c <<= 6; c |= d & 0x3F; @@ -477,7 +395,7 @@ UTF8Toisolat1(unsigned char* out, int *outlen, /* no chance for this in IsoLat1 */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } processed = in; } @@ -499,10 +417,10 @@ UTF8Toisolat1(unsigned char* out, int *outlen, * 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. + * Returns the number of bytes written or an XML_ENC_ERR code. + * + * 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, @@ -511,7 +429,7 @@ UTF16LEToUTF8(unsigned char* out, int *outlen, unsigned char* outstart = out; const unsigned char* processed = inb; unsigned char* outend; - unsigned short* in = (unsigned short*) inb; + unsigned short* in = (unsigned short *) (void *) inb; unsigned short* inend; unsigned int c, d, inlen; unsigned char *tmp; @@ -532,7 +450,7 @@ UTF16LEToUTF8(unsigned char* out, int *outlen, } else { tmp = (unsigned char *) in; c = *tmp++; - c = c | (((unsigned int)*tmp) << 8); + c = c | (*tmp << 8); in++; } if ((c & 0xFC00) == 0xD800) { /* surrogates */ @@ -544,7 +462,7 @@ UTF16LEToUTF8(unsigned char* out, int *outlen, } else { tmp = (unsigned char *) in; d = *tmp++; - d = d | (((unsigned int)*tmp) << 8); + d = d | (*tmp << 8); in++; } if ((d & 0xFC00) == 0xDC00) { @@ -556,7 +474,7 @@ UTF16LEToUTF8(unsigned char* out, int *outlen, else { *outlen = out - outstart; *inlenb = processed - inb; - return(-2); + return(XML_ENC_ERR_INPUT); } } @@ -591,14 +509,13 @@ UTF16LEToUTF8(unsigned char* out, int *outlen, * 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. + * Returns the number of bytes written or an XML_ENC_ERR code. */ static int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen) { - unsigned short* out = (unsigned short*) outb; + unsigned short* out = (unsigned short *) (void *) outb; const unsigned char* processed = in; const unsigned char *const instart = in; unsigned short* outstart= out; @@ -610,7 +527,8 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, unsigned short tmp1, tmp2; /* UTF16LE encoding has no BOM */ - if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) + return(XML_ENC_ERR_INTERNAL); if (in == NULL) { *outlen = 0; *inlen = 0; @@ -625,7 +543,7 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, /* trailing byte in leading position */ *outlen = (out - outstart) * 2; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } 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; } @@ -633,7 +551,7 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, /* no chance for this in UTF-16 */ *outlen = (out - outstart) * 2; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } if (inend - in < trailing) { @@ -655,7 +573,7 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, *out++ = c; } else { tmp = (unsigned char *) out; - *tmp = c ; + *tmp = (unsigned char) c; /* Explicit truncation */ *(tmp + 1) = c >> 8 ; out++; } @@ -670,13 +588,13 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, } else { tmp1 = 0xD800 | (c >> 10); tmp = (unsigned char *) out; - *tmp = (unsigned char) tmp1; + *tmp = (unsigned char) tmp1; /* Explicit truncation */ *(tmp + 1) = tmp1 >> 8; out++; tmp2 = 0xDC00 | (c & 0x03FF); tmp = (unsigned char *) out; - *tmp = (unsigned char) tmp2; + *tmp = (unsigned char) tmp2; /* Explicit truncation */ *(tmp + 1) = tmp2 >> 8; out++; } @@ -700,8 +618,7 @@ UTF8ToUTF16LE(unsigned char* outb, int *outlen, * 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. + * Returns the number of bytes written or an XML_ENC_ERR code. */ static int UTF8ToUTF16(unsigned char* outb, int *outlen, @@ -716,10 +633,6 @@ UTF8ToUTF16(unsigned char* outb, int *outlen, outb[1] = 0xFE; *outlen = 2; *inlen = 0; -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "Added FFFE Byte Order Mark\n"); -#endif return(2); } *outlen = 0; @@ -742,10 +655,10 @@ UTF8ToUTF16(unsigned char* outb, int *outlen, * 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) + * Returns the number of bytes written or an XML_ENC_ERR code. + * * The value of *inlen after return is the number of octets consumed - * if the return value is positive, else unpredictable. + * if the return value is positive, else unpredictable. */ static int UTF16BEToUTF8(unsigned char* out, int *outlen, @@ -754,7 +667,7 @@ UTF16BEToUTF8(unsigned char* out, int *outlen, unsigned char* outstart = out; const unsigned char* processed = inb; unsigned char* outend; - unsigned short* in = (unsigned short*) inb; + unsigned short* in = (unsigned short *) (void *) inb; unsigned short* inend; unsigned int c, d, inlen; unsigned char *tmp; @@ -773,7 +686,7 @@ UTF16BEToUTF8(unsigned char* out, int *outlen, if (xmlLittleEndian) { tmp = (unsigned char *) in; c = *tmp++; - c = (c << 8) | (unsigned int) *tmp; + c = (c << 8) | *tmp; in++; } else { c= *in++; @@ -785,7 +698,7 @@ UTF16BEToUTF8(unsigned char* out, int *outlen, if (xmlLittleEndian) { tmp = (unsigned char *) in; d = *tmp++; - d = (d << 8) | (unsigned int) *tmp; + d = (d << 8) | *tmp; in++; } else { d= *in++; @@ -799,7 +712,7 @@ UTF16BEToUTF8(unsigned char* out, int *outlen, else { *outlen = out - outstart; *inlenb = processed - inb; - return(-2); + return(XML_ENC_ERR_INPUT); } } @@ -834,14 +747,13 @@ UTF16BEToUTF8(unsigned char* out, int *outlen, * 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. + * Returns the number of bytes written or an XML_ENC_ERR code. */ static int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen) { - unsigned short* out = (unsigned short*) outb; + unsigned short* out = (unsigned short *) (void *) outb; const unsigned char* processed = in; const unsigned char *const instart = in; unsigned short* outstart= out; @@ -853,7 +765,8 @@ UTF8ToUTF16BE(unsigned char* outb, int *outlen, unsigned short tmp1, tmp2; /* UTF-16BE has no BOM */ - if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) + return(XML_ENC_ERR_INTERNAL); if (in == NULL) { *outlen = 0; *inlen = 0; @@ -868,7 +781,7 @@ UTF8ToUTF16BE(unsigned char* outb, int *outlen, /* trailing byte in leading position */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } 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; } @@ -876,7 +789,7 @@ UTF8ToUTF16BE(unsigned char* outb, int *outlen, /* no chance for this in UTF-16 */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } if (inend - in < trailing) { @@ -895,7 +808,7 @@ UTF8ToUTF16BE(unsigned char* outb, int *outlen, if (xmlLittleEndian) { tmp = (unsigned char *) out; *tmp = c >> 8; - *(tmp + 1) = c; + *(tmp + 1) = (unsigned char) c; /* Explicit truncation */ out++; } else { *out++ = c; @@ -908,13 +821,13 @@ UTF8ToUTF16BE(unsigned char* outb, int *outlen, tmp1 = 0xD800 | (c >> 10); tmp = (unsigned char *) out; *tmp = tmp1 >> 8; - *(tmp + 1) = (unsigned char) tmp1; + *(tmp + 1) = (unsigned char) tmp1; /* Explicit truncation */ out++; tmp2 = 0xDC00 | (c & 0x03FF); tmp = (unsigned char *) out; *tmp = tmp2 >> 8; - *(tmp + 1) = (unsigned char) tmp2; + *(tmp + 1) = (unsigned char) tmp2; /* Explicit truncation */ out++; } else { *out++ = 0xD800 | (c >> 10); @@ -1047,7 +960,7 @@ xmlGetEncodingAlias(const char *alias) { return(NULL); for (i = 0;i < 99;i++) { - upper[i] = toupper(alias[i]); + upper[i] = (char) toupper((unsigned char) alias[i]); if (upper[i] == 0) break; } upper[i] = 0; @@ -1077,29 +990,32 @@ int xmlAddEncodingAlias(const char *name, const char *alias) { int i; char upper[100]; + char *nameCopy, *aliasCopy; if ((name == NULL) || (alias == NULL)) return(-1); for (i = 0;i < 99;i++) { - upper[i] = toupper(alias[i]); + upper[i] = (char) toupper((unsigned char) 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)); + if (xmlCharEncodingAliasesNb >= xmlCharEncodingAliasesMax) { + xmlCharEncodingAliasPtr tmp; + size_t newSize = xmlCharEncodingAliasesMax ? + xmlCharEncodingAliasesMax * 2 : + 20; + + tmp = (xmlCharEncodingAliasPtr) + xmlRealloc(xmlCharEncodingAliases, + newSize * sizeof(xmlCharEncodingAlias)); + if (tmp == NULL) + return(-1); + xmlCharEncodingAliases = tmp; + xmlCharEncodingAliasesMax = newSize; } + /* * Walk down the list looking for a definition of the alias */ @@ -1108,16 +1024,27 @@ xmlAddEncodingAlias(const char *name, const char *alias) { /* * Replace the definition. */ + nameCopy = xmlMemStrdup(name); + if (nameCopy == NULL) + return(-1); xmlFree((char *) xmlCharEncodingAliases[i].name); - xmlCharEncodingAliases[i].name = xmlMemStrdup(name); + xmlCharEncodingAliases[i].name = nameCopy; return(0); } } /* * Add the definition */ - xmlCharEncodingAliases[xmlCharEncodingAliasesNb].name = xmlMemStrdup(name); - xmlCharEncodingAliases[xmlCharEncodingAliasesNb].alias = xmlMemStrdup(upper); + nameCopy = xmlMemStrdup(name); + if (nameCopy == NULL) + return(-1); + aliasCopy = xmlMemStrdup(upper); + if (aliasCopy == NULL) { + xmlFree(nameCopy); + return(-1); + } + xmlCharEncodingAliases[xmlCharEncodingAliasesNb].name = nameCopy; + xmlCharEncodingAliases[xmlCharEncodingAliasesNb].alias = aliasCopy; xmlCharEncodingAliasesNb++; return(0); } @@ -1184,7 +1111,7 @@ xmlParseCharEncoding(const char* name) name = alias; for (i = 0;i < 499;i++) { - upper[i] = toupper(name[i]); + upper[i] = (char) toupper((unsigned char) name[i]); if (upper[i] == 0) break; } upper[i] = 0; @@ -1233,9 +1160,6 @@ xmlParseCharEncoding(const char* name) 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); } @@ -1311,19 +1235,104 @@ xmlGetCharEncodingName(xmlCharEncoding enc) { * * ************************************************************************/ +#if !defined(LIBXML_ICONV_ENABLED) && !defined(LIBXML_ICU_ENABLED) && \ + defined(LIBXML_ISO8859X_ENABLED) + +#define DECLARE_ISO_FUNCS(n) \ + static int ISO8859_##n##ToUTF8(unsigned char* out, int *outlen, \ + const unsigned char* in, int *inlen); \ + static int UTF8ToISO8859_##n(unsigned char* out, int *outlen, \ + const unsigned char* in, int *inlen); + +/** DOC_DISABLE */ +DECLARE_ISO_FUNCS(2) +DECLARE_ISO_FUNCS(3) +DECLARE_ISO_FUNCS(4) +DECLARE_ISO_FUNCS(5) +DECLARE_ISO_FUNCS(6) +DECLARE_ISO_FUNCS(7) +DECLARE_ISO_FUNCS(8) +DECLARE_ISO_FUNCS(9) +DECLARE_ISO_FUNCS(10) +DECLARE_ISO_FUNCS(11) +DECLARE_ISO_FUNCS(13) +DECLARE_ISO_FUNCS(14) +DECLARE_ISO_FUNCS(15) +DECLARE_ISO_FUNCS(16) +/** DOC_ENABLE */ + +#endif /* LIBXML_ISO8859X_ENABLED */ + +#ifdef LIBXML_ICONV_ENABLED + #define EMPTY_ICONV , (iconv_t) 0, (iconv_t) 0 +#else + #define EMPTY_ICONV +#endif + +#ifdef LIBXML_ICU_ENABLED + #define EMPTY_UCONV , NULL, NULL +#else + #define EMPTY_UCONV +#endif + +#define MAKE_HANDLER(name, in, out) \ + { (char *) name, in, out EMPTY_ICONV EMPTY_UCONV } + +static const xmlCharEncodingHandler defaultHandlers[] = { +#ifdef LIBXML_OUTPUT_ENABLED + MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, UTF8ToUTF16LE) + ,MAKE_HANDLER("UTF-16BE", UTF16BEToUTF8, UTF8ToUTF16BE) + ,MAKE_HANDLER("UTF-16", UTF16LEToUTF8, UTF8ToUTF16) + ,MAKE_HANDLER("ISO-8859-1", isolat1ToUTF8, UTF8Toisolat1) + ,MAKE_HANDLER("ASCII", asciiToUTF8, UTF8Toascii) + ,MAKE_HANDLER("US-ASCII", asciiToUTF8, UTF8Toascii) +#ifdef LIBXML_HTML_ENABLED + ,MAKE_HANDLER("HTML", NULL, UTF8ToHtml) +#endif +#else + MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, NULL) + ,MAKE_HANDLER("UTF-16BE", UTF16BEToUTF8, NULL) + ,MAKE_HANDLER("UTF-16", UTF16LEToUTF8, NULL) + ,MAKE_HANDLER("ISO-8859-1", isolat1ToUTF8, NULL) + ,MAKE_HANDLER("ASCII", asciiToUTF8, NULL) + ,MAKE_HANDLER("US-ASCII", asciiToUTF8, NULL) +#endif /* LIBXML_OUTPUT_ENABLED */ + +#if !defined(LIBXML_ICONV_ENABLED) && !defined(LIBXML_ICU_ENABLED) && \ + defined(LIBXML_ISO8859X_ENABLED) + ,MAKE_HANDLER("ISO-8859-2", ISO8859_2ToUTF8, UTF8ToISO8859_2) + ,MAKE_HANDLER("ISO-8859-3", ISO8859_3ToUTF8, UTF8ToISO8859_3) + ,MAKE_HANDLER("ISO-8859-4", ISO8859_4ToUTF8, UTF8ToISO8859_4) + ,MAKE_HANDLER("ISO-8859-5", ISO8859_5ToUTF8, UTF8ToISO8859_5) + ,MAKE_HANDLER("ISO-8859-6", ISO8859_6ToUTF8, UTF8ToISO8859_6) + ,MAKE_HANDLER("ISO-8859-7", ISO8859_7ToUTF8, UTF8ToISO8859_7) + ,MAKE_HANDLER("ISO-8859-8", ISO8859_8ToUTF8, UTF8ToISO8859_8) + ,MAKE_HANDLER("ISO-8859-9", ISO8859_9ToUTF8, UTF8ToISO8859_9) + ,MAKE_HANDLER("ISO-8859-10", ISO8859_10ToUTF8, UTF8ToISO8859_10) + ,MAKE_HANDLER("ISO-8859-11", ISO8859_11ToUTF8, UTF8ToISO8859_11) + ,MAKE_HANDLER("ISO-8859-13", ISO8859_13ToUTF8, UTF8ToISO8859_13) + ,MAKE_HANDLER("ISO-8859-14", ISO8859_14ToUTF8, UTF8ToISO8859_14) + ,MAKE_HANDLER("ISO-8859-15", ISO8859_15ToUTF8, UTF8ToISO8859_15) + ,MAKE_HANDLER("ISO-8859-16", ISO8859_16ToUTF8, UTF8ToISO8859_16) +#endif +}; + +#define NUM_DEFAULT_HANDLERS \ + (sizeof(defaultHandlers) / sizeof(defaultHandlers[0])) + +static const xmlCharEncodingHandler xmlUTF8Handler = + MAKE_HANDLER("UTF-8", UTF8ToUTF8, UTF8ToUTF8); + +static const xmlCharEncodingHandler *xmlUTF16LEHandler = &defaultHandlers[0]; +static const xmlCharEncodingHandler *xmlUTF16BEHandler = &defaultHandlers[1]; +static const xmlCharEncodingHandler *xmlLatin1Handler = &defaultHandlers[3]; +static const xmlCharEncodingHandler *xmlAsciiHandler = &defaultHandlers[4]; /* the size should be growable, but it's not a big deal ... */ #define MAX_ENCODING_HANDLERS 50 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) @@ -1354,21 +1363,16 @@ xmlNewCharEncodingHandler(const char *name, /* * Keep only the uppercase version of the encoding. */ - if (name == NULL) { - xmlEncodingErr(XML_I18N_NO_NAME, - "xmlNewCharEncodingHandler : no name !\n", NULL); + if (name == NULL) return(NULL); - } for (i = 0;i < 499;i++) { - upper[i] = toupper(name[i]); + upper[i] = (char) toupper((unsigned char) name[i]); if (upper[i] == 0) break; } upper[i] = 0; up = xmlMemStrdup(upper); - if (up == NULL) { - xmlEncodingErrMemory("xmlNewCharEncodingHandler : out of memory !\n"); + if (up == NULL) return(NULL); - } /* * allocate and fill-up an handler block. @@ -1377,7 +1381,6 @@ xmlNewCharEncodingHandler(const char *name, xmlMalloc(sizeof(xmlCharEncodingHandler)); if (handler == NULL) { xmlFree(up); - xmlEncodingErrMemory("xmlNewCharEncodingHandler : out of memory !\n"); return(NULL); } memset(handler, 0, sizeof(xmlCharEncodingHandler)); @@ -1398,74 +1401,31 @@ xmlNewCharEncodingHandler(const char *name, * registers and returns the handler. */ xmlRegisterCharEncodingHandler(handler); -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "Registered encoding handler for %s\n", name); -#endif return(handler); } /** * xmlInitCharEncodingHandlers: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * 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. + * DEPRECATED: Alias for xmlInitParser. */ void xmlInitCharEncodingHandlers(void) { + xmlInitParser(); +} + +/** + * xmlInitEncodingInternal: + * + * Initialize the char encoding support. + */ +void +xmlInitEncodingInternal(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); -#ifdef LIBXML_HTML_ENABLED - xmlNewCharEncodingHandler("HTML", NULL, UTF8ToHtml); -#endif -#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) && !defined(LIBXML_ICU_ENABLED) -#ifdef LIBXML_ISO8859X_ENABLED - xmlRegisterCharEncodingHandlersISO8859x (); -#endif -#endif - + else xmlLittleEndian = 1; } /** @@ -1496,7 +1456,6 @@ xmlCleanupCharEncodingHandlers(void) { xmlFree(handlers); handlers = NULL; nbCharEncodingHandler = 0; - xmlDefaultCharEncodingHandler = NULL; } /** @@ -1507,19 +1466,16 @@ xmlCleanupCharEncodingHandlers(void) { */ void xmlRegisterCharEncodingHandler(xmlCharEncodingHandlerPtr handler) { - if (handlers == NULL) xmlInitCharEncodingHandlers(); - if ((handler == NULL) || (handlers == NULL)) { - xmlEncodingErr(XML_I18N_NO_HANDLER, - "xmlRegisterCharEncodingHandler: NULL handler !\n", NULL); - goto free_handler; + if (handler == NULL) + return; + if (handlers == NULL) { + handlers = xmlMalloc(MAX_ENCODING_HANDLERS * sizeof(handlers[0])); + if (handlers == NULL) + goto free_handler; } - if (nbCharEncodingHandler >= MAX_ENCODING_HANDLERS) { - xmlEncodingErr(XML_I18N_EXCESS_HANDLER, - "xmlRegisterCharEncodingHandler: Too many handler registered, see %s\n", - "MAX_ENCODING_HANDLERS"); + if (nbCharEncodingHandler >= MAX_ENCODING_HANDLERS) goto free_handler; - } handlers[nbCharEncodingHandler++] = handler; return; @@ -1532,285 +1488,516 @@ free_handler: } } +#ifdef LIBXML_ICONV_ENABLED +static int +xmlCreateIconvHandler(const char *name, xmlCharEncodingHandler **out) { + xmlCharEncodingHandlerPtr enc = NULL; + iconv_t icv_in = (iconv_t) -1; + iconv_t icv_out = (iconv_t) -1; + int ret; + + *out = NULL; + + icv_in = iconv_open("UTF-8", name); + if (icv_in == (iconv_t) -1) { + if (errno == EINVAL) + ret = XML_ERR_UNSUPPORTED_ENCODING; + else if (errno == ENOMEM) + ret = XML_ERR_NO_MEMORY; + else + ret = XML_ERR_SYSTEM; + goto error; + } + + icv_out = iconv_open(name, "UTF-8"); + if (icv_out == (iconv_t) -1) { + if (errno == EINVAL) + ret = XML_ERR_UNSUPPORTED_ENCODING; + else if (errno == ENOMEM) + ret = XML_ERR_NO_MEMORY; + else + ret = XML_ERR_SYSTEM; + goto error; + } + + enc = xmlMalloc(sizeof(*enc)); + if (enc == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + memset(enc, 0, sizeof(*enc)); + + enc->name = xmlMemStrdup(name); + if (enc->name == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + enc->iconv_in = icv_in; + enc->iconv_out = icv_out; + + *out = enc; + return(0); + +error: + if (enc != NULL) + xmlFree(enc); + if (icv_in != (iconv_t) -1) + iconv_close(icv_in); + if (icv_out != (iconv_t) -1) + iconv_close(icv_out); + return(ret); +} +#endif /* LIBXML_ICONV_ENABLED */ + +#ifdef LIBXML_ICU_ENABLED +static int +openIcuConverter(const char* name, int toUnicode, uconv_t **out) +{ + UErrorCode status; + uconv_t *conv; + + *out = NULL; + + conv = (uconv_t *) xmlMalloc(sizeof(uconv_t)); + if (conv == NULL) + return(XML_ERR_NO_MEMORY); + + conv->pivot_source = conv->pivot_buf; + conv->pivot_target = conv->pivot_buf; + + status = U_ZERO_ERROR; + conv->uconv = ucnv_open(name, &status); + if (U_FAILURE(status)) + goto error; + + status = U_ZERO_ERROR; + if (toUnicode) { + ucnv_setToUCallBack(conv->uconv, UCNV_TO_U_CALLBACK_STOP, + NULL, NULL, NULL, &status); + } + else { + ucnv_setFromUCallBack(conv->uconv, UCNV_FROM_U_CALLBACK_STOP, + NULL, NULL, NULL, &status); + } + if (U_FAILURE(status)) + goto error; + + status = U_ZERO_ERROR; + conv->utf8 = ucnv_open("UTF-8", &status); + if (U_FAILURE(status)) + goto error; + + *out = conv; + return(0); + +error: + if (conv->uconv) + ucnv_close(conv->uconv); + xmlFree(conv); + + if (status == U_FILE_ACCESS_ERROR) + return(XML_ERR_UNSUPPORTED_ENCODING); + if (status == U_MEMORY_ALLOCATION_ERROR) + return(XML_ERR_NO_MEMORY); + return(XML_ERR_SYSTEM); +} + +static void +closeIcuConverter(uconv_t *conv) +{ + if (conv == NULL) + return; + ucnv_close(conv->uconv); + ucnv_close(conv->utf8); + xmlFree(conv); +} + +static int +xmlCreateUconvHandler(const char *name, xmlCharEncodingHandler **out) { + xmlCharEncodingHandlerPtr enc = NULL; + uconv_t *ucv_in = NULL; + uconv_t *ucv_out = NULL; + int ret; + + ret = openIcuConverter(name, 1, &ucv_in); + if (ret != 0) + goto error; + ret = openIcuConverter(name, 0, &ucv_out); + if (ret != 0) + goto error; + + enc = (xmlCharEncodingHandlerPtr) + xmlMalloc(sizeof(xmlCharEncodingHandler)); + if (enc == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + memset(enc, 0, sizeof(xmlCharEncodingHandler)); + + enc->name = xmlMemStrdup(name); + if (enc->name == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + enc->input = NULL; + enc->output = NULL; + enc->uconv_in = ucv_in; + enc->uconv_out = ucv_out; + + *out = enc; + return(0); + +error: + if (enc != NULL) + xmlFree(enc); + if (ucv_in != NULL) + closeIcuConverter(ucv_in); + if (ucv_out != NULL) + closeIcuConverter(ucv_out); + return(ret); +} +#endif /* LIBXML_ICU_ENABLED */ + /** - * xmlGetCharEncodingHandler: + * xmlFindExtraHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to resulting handler + * + * Search the non-default handlers for an exact match. + * + * Returns 0 on success, 1 if no handler was found, -1 if a memory + * allocation failed. + */ +static int +xmlFindExtraHandler(const char *name, int output, + xmlCharEncodingHandler **out) { + int ret; + int i; + + (void) ret; + + if (handlers != NULL) { + for (i = 0; i < nbCharEncodingHandler; i++) { + xmlCharEncodingHandler *handler = handlers[i]; + + if (!xmlStrcasecmp((const xmlChar *) name, + (const xmlChar *) handler->name)) { + if (output) { + if (handler->output != NULL) { + *out = handler; + return(0); + } + } else { + if (handler->input != NULL) { + *out = handler; + return(0); + } + } + } + } + } + +#ifdef LIBXML_ICONV_ENABLED + ret = xmlCreateIconvHandler(name, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); +#endif /* LIBXML_ICONV_ENABLED */ + +#ifdef LIBXML_ICU_ENABLED + ret = xmlCreateUconvHandler(name, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); +#endif /* LIBXML_ICU_ENABLED */ + + return(XML_ERR_UNSUPPORTED_ENCODING); +} + +/** + * xmlFindHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to resulting handler + * + * Search all handlers for an exact match. + * + * Returns 0 on success, 1 if no handler was found, -1 if a memory + * allocation failed. + */ +static int +xmlFindHandler(const char *name, int output, xmlCharEncodingHandler **out) { + int i; + + /* + * Check for default handlers + */ + for (i = 0; i < (int) NUM_DEFAULT_HANDLERS; i++) { + xmlCharEncodingHandler *handler; + + handler = (xmlCharEncodingHandler *) &defaultHandlers[i]; + + if (xmlStrcasecmp((const xmlChar *) name, + (const xmlChar *) handler->name) == 0) { + if (output) { + if (handler->output != NULL) { + *out = handler; + return(0); + } + } else { + if (handler->input != NULL) { + *out = handler; + return(0); + } + } + } + } + + /* + * Check for other handlers + */ + return(xmlFindExtraHandler(name, output, out)); +} + +/** + * xmlLookupCharEncodingHandler: * @enc: an xmlCharEncoding value. + * @out: pointer to result + * + * Find or create a handler matching the encoding. If no default or + * registered handler could be found, try to create a handler using + * iconv or ICU if supported. + * + * The handler must be closed with xmlCharEncCloseFunc. * - * Search in the registered set the handler able to read/write that encoding. + * Available since 2.13.0. * - * Returns the handler or NULL if not found + * Returns an xmlParserErrors error code. */ -xmlCharEncodingHandlerPtr -xmlGetCharEncodingHandler(xmlCharEncoding enc) { - xmlCharEncodingHandlerPtr handler; +int +xmlLookupCharEncodingHandler(xmlCharEncoding enc, + xmlCharEncodingHandler **out) { + const char *name = NULL; + static const char *const ebcdicNames[] = { + "EBCDIC", "ebcdic", "EBCDIC-US", "IBM-037" + }; + static const char *const ucs4Names[] = { + "ISO-10646-UCS-4", "UCS-4", "UCS4" + }; + static const char *const ucs2Names[] = { + "ISO-10646-UCS-2", "UCS-2", "UCS2" + }; + static const char *const shiftJisNames[] = { + "SHIFT-JIS", "SHIFT_JIS", "Shift_JIS", + }; + const char *const *names = NULL; + int numNames = 0; + int ret; + int i; + + if (out == NULL) + return(XML_ERR_ARGUMENT); + *out = NULL; - if (handlers == NULL) xmlInitCharEncodingHandlers(); switch (enc) { case XML_CHAR_ENCODING_ERROR: - return(NULL); + return(XML_ERR_UNSUPPORTED_ENCODING); case XML_CHAR_ENCODING_NONE: - return(NULL); + return(0); case XML_CHAR_ENCODING_UTF8: - return(NULL); + return(0); case XML_CHAR_ENCODING_UTF16LE: - return(xmlUTF16LEHandler); + *out = (xmlCharEncodingHandler *) xmlUTF16LEHandler; + return(0); case XML_CHAR_ENCODING_UTF16BE: - return(xmlUTF16BEHandler); + *out = (xmlCharEncodingHandler *) xmlUTF16BEHandler; + return(0); case XML_CHAR_ENCODING_EBCDIC: - handler = xmlFindCharEncodingHandler("EBCDIC"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("ebcdic"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("EBCDIC-US"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("IBM-037"); - if (handler != NULL) return(handler); + names = ebcdicNames; + numNames = sizeof(ebcdicNames) / sizeof(ebcdicNames[0]); break; case XML_CHAR_ENCODING_UCS4BE: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS4"); - if (handler != NULL) return(handler); - break; case XML_CHAR_ENCODING_UCS4LE: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS4"); - if (handler != NULL) return(handler); + names = ucs4Names; + numNames = sizeof(ucs4Names) / sizeof(ucs4Names[0]); break; case XML_CHAR_ENCODING_UCS4_2143: break; case XML_CHAR_ENCODING_UCS4_3412: break; case XML_CHAR_ENCODING_UCS2: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-2"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-2"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS2"); - if (handler != NULL) return(handler); + names = ucs2Names; + numNames = sizeof(ucs2Names) / sizeof(ucs2Names[0]); break; - /* - * We used to keep ISO Latin encodings native in the - * generated data. This led to so many problems that - * this has been removed. One can still change this - * back by registering no-ops encoders for those - */ + case XML_CHAR_ENCODING_ASCII: + *out = (xmlCharEncodingHandler *) xmlAsciiHandler; + return(0); case XML_CHAR_ENCODING_8859_1: - handler = xmlFindCharEncodingHandler("ISO-8859-1"); - if (handler != NULL) return(handler); - break; + *out = (xmlCharEncodingHandler *) xmlLatin1Handler; + return(0); case XML_CHAR_ENCODING_8859_2: - handler = xmlFindCharEncodingHandler("ISO-8859-2"); - if (handler != NULL) return(handler); + name = "ISO-8859-2"; break; case XML_CHAR_ENCODING_8859_3: - handler = xmlFindCharEncodingHandler("ISO-8859-3"); - if (handler != NULL) return(handler); + name = "ISO-8859-3"; break; case XML_CHAR_ENCODING_8859_4: - handler = xmlFindCharEncodingHandler("ISO-8859-4"); - if (handler != NULL) return(handler); + name = "ISO-8859-4"; break; case XML_CHAR_ENCODING_8859_5: - handler = xmlFindCharEncodingHandler("ISO-8859-5"); - if (handler != NULL) return(handler); + name = "ISO-8859-5"; break; case XML_CHAR_ENCODING_8859_6: - handler = xmlFindCharEncodingHandler("ISO-8859-6"); - if (handler != NULL) return(handler); + name = "ISO-8859-6"; break; case XML_CHAR_ENCODING_8859_7: - handler = xmlFindCharEncodingHandler("ISO-8859-7"); - if (handler != NULL) return(handler); + name = "ISO-8859-7"; break; case XML_CHAR_ENCODING_8859_8: - handler = xmlFindCharEncodingHandler("ISO-8859-8"); - if (handler != NULL) return(handler); + name = "ISO-8859-8"; break; case XML_CHAR_ENCODING_8859_9: - handler = xmlFindCharEncodingHandler("ISO-8859-9"); - if (handler != NULL) return(handler); + name = "ISO-8859-9"; break; - case XML_CHAR_ENCODING_2022_JP: - handler = xmlFindCharEncodingHandler("ISO-2022-JP"); - if (handler != NULL) return(handler); + name = "ISO-2022-JP"; break; case XML_CHAR_ENCODING_SHIFT_JIS: - handler = xmlFindCharEncodingHandler("SHIFT-JIS"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("SHIFT_JIS"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("Shift_JIS"); - if (handler != NULL) return(handler); + names = shiftJisNames; + numNames = sizeof(shiftJisNames) / sizeof(shiftJisNames[0]); break; case XML_CHAR_ENCODING_EUC_JP: - handler = xmlFindCharEncodingHandler("EUC-JP"); - if (handler != NULL) return(handler); + name = "EUC-JP"; break; default: break; } -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "No handler found for encoding %d\n", enc); -#endif - return(NULL); + if (name != NULL) + return(xmlFindExtraHandler(name, 0, out)); + + if (names != NULL) { + for (i = 0; i < numNames; i++) { + ret = xmlFindExtraHandler(names[i], 0, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); + } + } + + return(XML_ERR_UNSUPPORTED_ENCODING); } /** - * xmlFindCharEncodingHandler: - * @name: a string describing the char encoding. + * xmlGetCharEncodingHandler: + * @enc: an xmlCharEncoding value. * - * Search in the registered set the handler able to read/write that encoding. + * DEPRECATED: Use xmlLookupCharEncodingHandler which has better error + * reporting. * - * Returns the handler or NULL if not found + * Returns the handler or NULL if no handler was found or an error + * occurred. */ xmlCharEncodingHandlerPtr -xmlFindCharEncodingHandler(const char *name) { +xmlGetCharEncodingHandler(xmlCharEncoding enc) { + xmlCharEncodingHandler *ret; + + xmlLookupCharEncodingHandler(enc, &ret); + return(ret); +} + +/** + * xmlOpenCharEncodingHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to result + * + * Find or create a handler matching the encoding. If no default or + * registered handler could be found, try to create a handler using + * iconv or ICU if supported. + * + * The handler must be closed with xmlCharEncCloseFunc. + * + * If the encoding is UTF-8, a NULL handler and no error code will + * be returned. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors error code. + */ +int +xmlOpenCharEncodingHandler(const char *name, int output, + xmlCharEncodingHandler **out) { const char *nalias; const char *norig; - xmlCharEncoding alias; -#ifdef LIBXML_ICONV_ENABLED - xmlCharEncodingHandlerPtr enc; - iconv_t icv_in, icv_out; -#endif /* LIBXML_ICONV_ENABLED */ -#ifdef LIBXML_ICU_ENABLED - xmlCharEncodingHandlerPtr encu; - uconv_t *ucv_in, *ucv_out; -#endif /* LIBXML_ICU_ENABLED */ - char upper[100]; - int i; + xmlCharEncoding enc; + int ret; + + if (out == NULL) + return(XML_ERR_ARGUMENT); + *out = NULL; + + if (name == NULL) + return(XML_ERR_ARGUMENT); - if (handlers == NULL) xmlInitCharEncodingHandlers(); - if (name == NULL) return(xmlDefaultCharEncodingHandler); - if (name[0] == 0) return(xmlDefaultCharEncodingHandler); + if ((xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF-8") == 0) || + (xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF8") == 0)) + return(XML_ERR_OK); /* * Do the alias resolution */ 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); - if (icv_in != (iconv_t) -1) - iconv_close(icv_in); - else - iconv_close(icv_out); - } -#endif /* LIBXML_ICONV_ENABLED */ -#ifdef LIBXML_ICU_ENABLED - /* check whether icu can handle this */ - ucv_in = openIcuConverter(name, 1); - ucv_out = openIcuConverter(name, 0); - if (ucv_in != NULL && ucv_out != NULL) { - encu = (xmlCharEncodingHandlerPtr) - xmlMalloc(sizeof(xmlCharEncodingHandler)); - if (encu == NULL) { - closeIcuConverter(ucv_in); - closeIcuConverter(ucv_out); - return(NULL); - } - memset(encu, 0, sizeof(xmlCharEncodingHandler)); - encu->name = xmlMemStrdup(name); - encu->input = NULL; - encu->output = NULL; - encu->uconv_in = ucv_in; - encu->uconv_out = ucv_out; -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "Found ICU converter handler for encoding %s\n", name); -#endif - return encu; - } else if (ucv_in != NULL || ucv_out != NULL) { - closeIcuConverter(ucv_in); - closeIcuConverter(ucv_out); - xmlEncodingErr(XML_ERR_INTERNAL_ERROR, - "ICU converter : problems with filters for '%s'\n", name); - } -#endif /* LIBXML_ICU_ENABLED */ + if (nalias != NULL) + name = nalias; -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "No handler found for encoding %s\n", name); -#endif + ret = xmlFindHandler(name, output, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); /* * Fallback using the canonical names + * + * TODO: We should make sure that the name of the returned + * handler equals norig. */ - alias = xmlParseCharEncoding(norig); - if (alias != XML_CHAR_ENCODING_ERROR) { - const char* canon; - canon = xmlGetCharEncodingName(alias); - if ((canon != NULL) && (strcmp(name, canon))) { - return(xmlFindCharEncodingHandler(canon)); - } - } + enc = xmlParseCharEncoding(norig); + return(xmlLookupCharEncodingHandler(enc, out)); +} - /* If "none of the above", give up */ - return(NULL); +/** + * xmlFindCharEncodingHandler: + * @name: a string describing the char encoding. + * + * DEPRECATED: Use xmlOpenCharEncodingHandler which has better error + * reporting. + * + * Returns the handler or NULL if no handler was found or an error + * occurred. + */ +xmlCharEncodingHandlerPtr +xmlFindCharEncodingHandler(const char *name) { + xmlCharEncodingHandler *ret; + + /* + * This handler shouldn't be used, but we must return a non-NULL + * handler. + */ + if ((xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF-8") == 0) || + (xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF8") == 0)) + return((xmlCharEncodingHandlerPtr) &xmlUTF8Handler); + + xmlOpenCharEncodingHandler(name, 0, &ret); + return(ret); } /************************************************************************ @@ -1828,11 +2015,7 @@ xmlFindCharEncodingHandler(const char *name) { * @in: a pointer to an array of input bytes * @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. + * Returns an XML_ENC_ERR code. * * The value of @inlen after return is the number of octets consumed * as the return value is positive, else unpredictable. @@ -1848,7 +2031,7 @@ xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen, if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL)) { if (outlen != NULL) *outlen = 0; - return(-1); + return(XML_ENC_ERR_INTERNAL); } icv_inlen = *inlen; icv_outlen = *outlen; @@ -1858,27 +2041,16 @@ xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen, ret = iconv(cd, (void *) &icv_in, &icv_inlen, &icv_out, &icv_outlen); *inlen -= icv_inlen; *outlen -= icv_outlen; - if ((icv_inlen != 0) || (ret == (size_t) -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; - } + if (ret == (size_t) -1) { + if (errno == EILSEQ) + return(XML_ENC_ERR_INPUT); + if (errno == E2BIG) + return(XML_ENC_ERR_SPACE); + if (errno == EINVAL) + return(XML_ENC_ERR_PARTIAL); + return(XML_ENC_ERR_INTERNAL); } - return 0; + return(XML_ENC_ERR_SUCCESS); } #endif /* LIBXML_ICONV_ENABLED */ @@ -1897,13 +2069,8 @@ xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen, * @outlen: the length of @out * @in: a pointer to an array of input bytes * @inlen: the length of @in - * @flush: if true, indicates end of input * - * 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. + * Returns an XML_ENC_ERR code. * * The value of @inlen after return is the number of octets consumed * as the return value is positive, else unpredictable. @@ -1911,42 +2078,53 @@ xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen, */ static int xmlUconvWrapper(uconv_t *cd, int toUnicode, unsigned char *out, int *outlen, - const unsigned char *in, int *inlen, int flush) { + const unsigned char *in, int *inlen) { const char *ucv_in = (const char *) in; char *ucv_out = (char *) out; UErrorCode err = U_ZERO_ERROR; if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL)) { if (outlen != NULL) *outlen = 0; - return(-1); + return(XML_ENC_ERR_INTERNAL); } + /* + * Note that the ICU API is stateful. It can always consume a certain + * amount of input even if the output buffer would overflow. The + * remaining input must be processed by calling ucnv_convertEx with a + * possibly empty input buffer. + * + * ucnv_convertEx is always called with reset and flush set to 0, + * so we don't mess up the state. This should never generate + * U_TRUNCATED_CHAR_FOUND errors. + * + * This also means that ICU xmlCharEncodingHandlers should never be + * reused. It would be a lot nicer if there was a way to emulate the + * stateless iconv API. + */ if (toUnicode) { /* encoding => UTF-16 => UTF-8 */ ucnv_convertEx(cd->utf8, cd->uconv, &ucv_out, ucv_out + *outlen, &ucv_in, ucv_in + *inlen, cd->pivot_buf, &cd->pivot_source, &cd->pivot_target, - cd->pivot_buf + ICU_PIVOT_BUF_SIZE, 0, flush, &err); + cd->pivot_buf + ICU_PIVOT_BUF_SIZE, 0, 0, &err); } else { /* UTF-8 => UTF-16 => encoding */ ucnv_convertEx(cd->uconv, cd->utf8, &ucv_out, ucv_out + *outlen, &ucv_in, ucv_in + *inlen, cd->pivot_buf, &cd->pivot_source, &cd->pivot_target, - cd->pivot_buf + ICU_PIVOT_BUF_SIZE, 0, flush, &err); + cd->pivot_buf + ICU_PIVOT_BUF_SIZE, 0, 0, &err); } *inlen = ucv_in - (const char*) in; *outlen = ucv_out - (char *) out; if (U_SUCCESS(err)) { - /* reset pivot buf if this is the last call for input (flush==TRUE) */ - if (flush) - cd->pivot_source = cd->pivot_target = cd->pivot_buf; - return 0; + return(XML_ENC_ERR_SUCCESS); } if (err == U_BUFFER_OVERFLOW_ERROR) - return -1; + return(XML_ENC_ERR_SPACE); if (err == U_INVALID_CHAR_FOUND || err == U_ILLEGAL_CHAR_FOUND) - return -2; - return -3; + return(XML_ENC_ERR_INPUT); + return(XML_ENC_ERR_PARTIAL); } #endif /* LIBXML_ICU_ENABLED */ @@ -1956,6 +2134,34 @@ xmlUconvWrapper(uconv_t *cd, int toUnicode, unsigned char *out, int *outlen, * * ************************************************************************/ +/** + * xmlEncConvertError: + * @code: XML_ENC_ERR code + * + * Convert XML_ENC_ERR to libxml2 error codes. + */ +static int +xmlEncConvertError(int code) { + int ret; + + switch (code) { + case XML_ENC_ERR_SUCCESS: + ret = XML_ERR_OK; + break; + case XML_ENC_ERR_INPUT: + ret = XML_ERR_INVALID_ENCODING; + break; + case XML_ENC_ERR_MEMORY: + ret = XML_ERR_NO_MEMORY; + break; + default: + ret = XML_ERR_INTERNAL_ERROR; + break; + } + + return(ret); +} + /** * xmlEncInputChunk: * @handler: encoding handler @@ -1963,28 +2169,35 @@ xmlUconvWrapper(uconv_t *cd, int toUnicode, unsigned char *out, int *outlen, * @outlen: the length of @out * @in: a pointer to an array of input bytes * @inlen: the length of @in - * @flush: flush (ICU-related) - * - * 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 0, else unpredictable. * The value of @outlen after return is the number of octets produced. + * + * Returns an XML_ENC_ERR code. */ -static int +int xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out, - int *outlen, const unsigned char *in, int *inlen, int flush) { + int *outlen, const unsigned char *in, int *inlen) { int ret; - (void)flush; if (handler->input != NULL) { + int oldinlen = *inlen; + ret = handler->input(out, outlen, in, inlen); - if (ret > 0) - ret = 0; + if (ret >= 0) { + /* + * The built-in converters don't signal XML_ENC_ERR_SPACE. + */ + if (*inlen < oldinlen) { + if (*outlen > 0) + ret = XML_ENC_ERR_SPACE; + else + ret = XML_ENC_ERR_PARTIAL; + } else { + ret = XML_ENC_ERR_SUCCESS; + } + } } #ifdef LIBXML_ICONV_ENABLED else if (handler->iconv_in != NULL) { @@ -1993,16 +2206,19 @@ xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out, #endif /* LIBXML_ICONV_ENABLED */ #ifdef LIBXML_ICU_ENABLED else if (handler->uconv_in != NULL) { - ret = xmlUconvWrapper(handler->uconv_in, 1, out, outlen, in, inlen, - flush); + ret = xmlUconvWrapper(handler->uconv_in, 1, out, outlen, in, inlen); } #endif /* LIBXML_ICU_ENABLED */ else { *outlen = 0; *inlen = 0; - ret = -2; + ret = XML_ENC_ERR_INTERNAL; } + /* Ignore partial errors when reading. */ + if (ret == XML_ENC_ERR_PARTIAL) + ret = XML_ENC_ERR_SUCCESS; + return(ret); } @@ -2014,12 +2230,7 @@ xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out, * @in: a pointer to an array of input bytes * @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. - * -4 if no output function was found. + * Returns an XML_ENC_ERR code. * * The value of @inlen after return is the number of octets consumed * as the return value is 0, else unpredictable. @@ -2031,9 +2242,22 @@ xmlEncOutputChunk(xmlCharEncodingHandler *handler, unsigned char *out, int ret; if (handler->output != NULL) { + int oldinlen = *inlen; + ret = handler->output(out, outlen, in, inlen); - if (ret > 0) - ret = 0; + if (ret >= 0) { + /* + * The built-in converters don't signal XML_ENC_ERR_SPACE. + */ + if (*inlen < oldinlen) { + if (*outlen > 0) + ret = XML_ENC_ERR_SPACE; + else + ret = XML_ENC_ERR_PARTIAL; + } else { + ret = XML_ENC_ERR_SUCCESS; + } + } } #ifdef LIBXML_ICONV_ENABLED else if (handler->iconv_out != NULL) { @@ -2042,328 +2266,110 @@ xmlEncOutputChunk(xmlCharEncodingHandler *handler, unsigned char *out, #endif /* LIBXML_ICONV_ENABLED */ #ifdef LIBXML_ICU_ENABLED else if (handler->uconv_out != NULL) { - ret = xmlUconvWrapper(handler->uconv_out, 0, out, outlen, in, inlen, - 1); + ret = xmlUconvWrapper(handler->uconv_out, 0, out, outlen, in, inlen); } #endif /* LIBXML_ICU_ENABLED */ else { *outlen = 0; *inlen = 0; - ret = -4; + ret = XML_ENC_ERR_INTERNAL; } - return(ret); -} - -/** - * xmlCharEncFirstLineInt: - * @handler: char encoding 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; - 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 * 2); - written = out->size - out->use - 1; - } + /* We shouldn't generate partial sequences when writing. */ + if (ret == XML_ENC_ERR_PARTIAL) + ret = XML_ENC_ERR_INTERNAL; - ret = xmlEncInputChunk(handler, &out->content[out->use], &written, - in->content, &toconv, 0); - xmlBufferShrink(in, toconv); - out->use += written; - out->content[out->use] = 0; - if (ret == -1) ret = -3; - -#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(written ? written : ret); + return(ret); } /** * xmlCharEncFirstLine: - * @handler: char encoding transformation data structure + * @handler: char encoding 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. + * DEPERECATED: Don't use. * - * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. */ int xmlCharEncFirstLine(xmlCharEncodingHandler *handler, xmlBufferPtr out, - xmlBufferPtr in) { - return(xmlCharEncFirstLineInt(handler, out, in, -1)); + xmlBufferPtr in) { + return(xmlCharEncInFunc(handler, out, in)); } /** - * xmlCharEncFirstLineInput: + * xmlCharEncInput: * @input: a parser input buffer - * @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. Point is that this is based on autodetection - * of the encoding and once that first line is converted we may find - * out that a different decoder is needed to process the input. + * Generic front-end for the encoding handler on parser input * - * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. */ int -xmlCharEncFirstLineInput(xmlParserInputBufferPtr input, int len) +xmlCharEncInput(xmlParserInputBufferPtr input) { int ret; - size_t written; + size_t avail; size_t toconv; int c_in; int c_out; xmlBufPtr in; xmlBufPtr out; + const xmlChar *inData; + size_t inTotal = 0; if ((input == NULL) || (input->encoder == NULL) || (input->buffer == NULL) || (input->raw == NULL)) - return (-1); + return(XML_ENC_ERR_INTERNAL); out = input->buffer; in = input->raw; toconv = xmlBufUse(in); if (toconv == 0) return (0); - written = xmlBufAvail(out); - /* - * 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 > (unsigned int) len) - toconv = len; - } else { - if (toconv > 180) - toconv = 180; - } - if (toconv * 2 >= written) { - xmlBufGrow(out, toconv * 2); - written = xmlBufAvail(out); - } - if (written > 360) - written = 360; - - c_in = toconv; - c_out = written; - ret = xmlEncInputChunk(input->encoder, xmlBufEnd(out), &c_out, - xmlBufContent(in), &c_in, 0); - xmlBufShrink(in, c_in); - xmlBufAddLen(out, c_out); - if (ret == -1) - ret = -3; - - switch (ret) { - case 0: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input\n", - c_in, c_out); -#endif - break; - case -1: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input, %d left\n", - c_in, c_out, (int)xmlBufUse(in)); -#endif - break; - case -3: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input, %d left\n", - c_in, c_out, (int)xmlBufUse(in)); -#endif - break; - case -2: { - char buf[50]; - const xmlChar *content = xmlBufContent(in); - - snprintf(&buf[0], 49, "0x%02X 0x%02X 0x%02X 0x%02X", - content[0], content[1], - content[2], content[3]); - buf[49] = 0; - xmlEncodingErr(XML_I18N_CONV_FAILED, - "input conversion failed due to input error, bytes %s\n", - buf); + inData = xmlBufContent(in); + inTotal = 0; + + do { + c_in = toconv > INT_MAX / 2 ? INT_MAX / 2 : toconv; + + avail = xmlBufAvail(out); + if (avail > INT_MAX) + avail = INT_MAX; + if (avail < 4096) { + if (xmlBufGrow(out, 4096) < 0) { + input->error = XML_ERR_NO_MEMORY; + return(XML_ENC_ERR_MEMORY); + } + avail = xmlBufAvail(out); } - } - /* - * Ignore when input buffer is not on a boundary - */ - if (ret == -3) ret = 0; - if (ret == -1) ret = 0; - return(c_out ? c_out : ret); -} -/** - * xmlCharEncInput: - * @input: a parser input buffer - * @flush: try to flush all the raw buffer - * - * Generic front-end for the encoding handler on parser input - * - * 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 -xmlCharEncInput(xmlParserInputBufferPtr input, int flush) -{ - int ret; - size_t written; - size_t toconv; - int c_in; - int c_out; - xmlBufPtr in; - xmlBufPtr out; + c_in = toconv; + c_out = avail; + ret = xmlEncInputChunk(input->encoder, xmlBufEnd(out), &c_out, + inData, &c_in); + inTotal += c_in; + inData += c_in; + toconv -= c_in; + xmlBufAddLen(out, c_out); + } while (ret == XML_ENC_ERR_SPACE); - if ((input == NULL) || (input->encoder == NULL) || - (input->buffer == NULL) || (input->raw == NULL)) - return (-1); - out = input->buffer; - in = input->raw; + xmlBufShrink(in, inTotal); - toconv = xmlBufUse(in); - if (toconv == 0) - return (0); - if ((toconv > 64 * 1024) && (flush == 0)) - toconv = 64 * 1024; - written = xmlBufAvail(out); - if (toconv * 2 >= written) { - xmlBufGrow(out, toconv * 2); - written = xmlBufAvail(out); - } - if ((written > 128 * 1024) && (flush == 0)) - written = 128 * 1024; + if (input->rawconsumed > ULONG_MAX - (unsigned long)c_in) + input->rawconsumed = ULONG_MAX; + else + input->rawconsumed += c_in; - c_in = toconv; - c_out = written; - ret = xmlEncInputChunk(input->encoder, xmlBufEnd(out), &c_out, - xmlBufContent(in), &c_in, flush); - xmlBufShrink(in, c_in); - xmlBufAddLen(out, c_out); - if (ret == -1) - ret = -3; - - switch (ret) { - case 0: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input\n", - c_in, c_out); -#endif - break; - case -1: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input, %d left\n", - c_in, c_out, (int)xmlBufUse(in)); -#endif - break; - case -3: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of input, %d left\n", - c_in, c_out, (int)xmlBufUse(in)); -#endif - break; - case -2: { - char buf[50]; - const xmlChar *content = xmlBufContent(in); - - snprintf(&buf[0], 49, "0x%02X 0x%02X 0x%02X 0x%02X", - content[0], content[1], - content[2], content[3]); - buf[49] = 0; - xmlEncodingErr(XML_I18N_CONV_FAILED, - "input conversion failed due to input error, bytes %s\n", - buf); - } + if (((ret != 0) && (c_out == 0)) || + (ret == XML_ENC_ERR_MEMORY)) { + if (input->error == 0) + input->error = xmlEncConvertError(ret); + return(ret); } - /* - * Ignore when input buffer is not on a boundary - */ - if (ret == -3) - ret = 0; - return (c_out? c_out : ret); + + return (c_out); } /** @@ -2374,10 +2380,7 @@ xmlCharEncInput(xmlParserInputBufferPtr input, int flush) * * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. */ int xmlCharEncInFunc(xmlCharEncodingHandler * handler, xmlBufferPtr out, @@ -2388,11 +2391,11 @@ xmlCharEncInFunc(xmlCharEncodingHandler * handler, xmlBufferPtr out, int toconv; if (handler == NULL) - return (-1); + return(XML_ENC_ERR_INTERNAL); if (out == NULL) - return (-1); + return(XML_ENC_ERR_INTERNAL); if (in == NULL) - return (-1); + return(XML_ENC_ERR_INTERNAL); toconv = in->use; if (toconv == 0) @@ -2403,52 +2406,11 @@ xmlCharEncInFunc(xmlCharEncodingHandler * handler, xmlBufferPtr out, written = out->size - out->use - 1; } ret = xmlEncInputChunk(handler, &out->content[out->use], &written, - in->content, &toconv, 1); + in->content, &toconv); xmlBufferShrink(in, toconv); out->use += written; out->content[out->use] = 0; - if (ret == -1) - ret = -3; - - 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); } @@ -2465,10 +2427,7 @@ xmlCharEncInFunc(xmlCharEncodingHandler * handler, xmlBufferPtr out, * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. */ int xmlCharEncOutput(xmlOutputBufferPtr output, int init) @@ -2484,7 +2443,7 @@ xmlCharEncOutput(xmlOutputBufferPtr output, int init) if ((output == NULL) || (output->encoder == NULL) || (output->buffer == NULL) || (output->conv == NULL)) - return (-1); + return(XML_ENC_ERR_INTERNAL); out = output->conv; in = output->buffer; @@ -2502,10 +2461,6 @@ retry: xmlEncOutputChunk(output->encoder, xmlBufEnd(out), &c_out, NULL, &c_in); xmlBufAddLen(out, c_out); -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "initialized encoder\n"); -#endif return(c_out); } @@ -2513,12 +2468,13 @@ retry: * Conversion itself. */ toconv = xmlBufUse(in); - if (toconv == 0) - return (writtentot); if (toconv > 64 * 1024) toconv = 64 * 1024; if (toconv * 4 >= written) { - xmlBufGrow(out, toconv * 4); + if (xmlBufGrow(out, toconv * 4) < 0) { + ret = XML_ENC_ERR_MEMORY; + goto error; + } written = xmlBufAvail(out); } if (written > 256 * 1024) @@ -2531,95 +2487,55 @@ retry: xmlBufShrink(in, c_in); xmlBufAddLen(out, c_out); writtentot += c_out; - if (ret == -1) { - if (c_out > 0) { - /* Can be a limitation of iconv or uconv */ - goto retry; - } - ret = -3; - } + + if (ret == XML_ENC_ERR_SPACE) + goto retry; /* * Attempt to handle error cases */ - switch (ret) { - case 0: -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "converted %d bytes to %d bytes of output\n", - c_in, c_out); -#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", - c_in, c_out, (int) xmlBufUse(in)); -#endif - break; - case -4: - xmlEncodingErr(XML_I18N_NO_OUTPUT, - "xmlCharEncOutFunc: no output function !\n", NULL); - ret = -1; - break; - case -2: { - xmlChar charref[20]; - int len = (int) xmlBufUse(in); - xmlChar *content = xmlBufContent(in); - int cur, charrefLen; - - cur = xmlGetUTF8Char(content, &len); - if (cur <= 0) - break; + if (ret == XML_ENC_ERR_INPUT) { + xmlChar charref[20]; + int len = xmlBufUse(in); + xmlChar *content = xmlBufContent(in); + int cur, charrefLen; -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "handling output conversion error\n"); - xmlGenericError(xmlGenericErrorContext, - "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - content[0], content[1], - content[2], 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. - */ - charrefLen = snprintf((char *) &charref[0], sizeof(charref), - "&#%d;", cur); - xmlBufShrink(in, len); - xmlBufGrow(out, charrefLen * 4); - c_out = xmlBufAvail(out); - c_in = charrefLen; - ret = xmlEncOutputChunk(output->encoder, xmlBufEnd(out), &c_out, - charref, &c_in); - - if ((ret < 0) || (c_in != charrefLen)) { - char buf[50]; - - snprintf(&buf[0], 49, "0x%02X 0x%02X 0x%02X 0x%02X", - content[0], content[1], - content[2], content[3]); - buf[49] = 0; - xmlEncodingErr(XML_I18N_CONV_FAILED, - "output conversion failed due to conv error, bytes %s\n", - buf); - if (xmlBufGetAllocationScheme(in) != XML_BUFFER_ALLOC_IMMUTABLE) - content[0] = ' '; - break; - } + cur = xmlGetUTF8Char(content, &len); + if (cur <= 0) + goto error; - xmlBufAddLen(out, c_out); - writtentot += c_out; - goto retry; - } + /* + * Removes the UTF8 sequence, and replace it by a charref + * and continue the transcoding phase, hoping the error + * did not mangle the encoder state. + */ + charrefLen = snprintf((char *) &charref[0], sizeof(charref), + "&#%d;", cur); + xmlBufGrow(out, charrefLen * 4); + c_out = xmlBufAvail(out); + c_in = charrefLen; + ret = xmlEncOutputChunk(output->encoder, xmlBufEnd(out), &c_out, + charref, &c_in); + if ((ret < 0) || (c_in != charrefLen)) { + ret = XML_ENC_ERR_INTERNAL; + goto error; + } + + xmlBufShrink(in, len); + xmlBufAddLen(out, c_out); + writtentot += c_out; + goto retry; } - return(writtentot ? writtentot : ret); + +error: + if (((writtentot <= 0) && (ret != 0)) || + (ret == XML_ENC_ERR_MEMORY)) { + if (output->error == 0) + output->error = xmlEncConvertError(ret); + return(ret); + } + + return(writtentot); } #endif @@ -2636,10 +2552,7 @@ retry: * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. */ int xmlCharEncOutFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out, @@ -2649,8 +2562,8 @@ xmlCharEncOutFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out, int writtentot = 0; int toconv; - if (handler == NULL) return(-1); - if (out == NULL) return(-1); + if (handler == NULL) return(XML_ENC_ERR_INTERNAL); + if (out == NULL) return(XML_ENC_ERR_INTERNAL); retry: @@ -2669,10 +2582,6 @@ retry: NULL, &toconv); out->use += written; out->content[out->use] = 0; -#ifdef DEBUG_ENCODING - xmlGenericError(xmlGenericErrorContext, - "initialized encoder\n"); -#endif return(0); } @@ -2680,8 +2589,6 @@ retry: * Conversion itself. */ toconv = in->use; - if (toconv == 0) - return(0); if (toconv * 4 >= written) { xmlBufferGrow(out, toconv * 4); written = out->size - out->use - 1; @@ -2692,94 +2599,43 @@ retry: out->use += written; writtentot += written; out->content[out->use] = 0; - if (ret == -1) { - if (written > 0) { - /* Can be a limitation of iconv or uconv */ - goto retry; - } - ret = -3; - } + + if (ret == XML_ENC_ERR_SPACE) + goto retry; /* * 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 -4: - xmlEncodingErr(XML_I18N_NO_OUTPUT, - "xmlCharEncOutFunc: no output function !\n", NULL); - ret = -1; - break; - case -2: { - xmlChar charref[20]; - int len = in->use; - const xmlChar *utf = (const xmlChar *) in->content; - int cur, charrefLen; - - cur = xmlGetUTF8Char(utf, &len); - if (cur <= 0) - break; + if (ret == XML_ENC_ERR_INPUT) { + xmlChar charref[20]; + int len = in->use; + const xmlChar *utf = (const xmlChar *) in->content; + int cur, charrefLen; -#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. - */ - charrefLen = snprintf((char *) &charref[0], sizeof(charref), - "&#%d;", cur); - xmlBufferShrink(in, len); - xmlBufferGrow(out, charrefLen * 4); - written = out->size - out->use - 1; - toconv = charrefLen; - ret = xmlEncOutputChunk(handler, &out->content[out->use], &written, - charref, &toconv); - - if ((ret < 0) || (toconv != charrefLen)) { - 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; - } + cur = xmlGetUTF8Char(utf, &len); + if (cur <= 0) + return(ret); - out->use += written; - writtentot += written; - out->content[out->use] = 0; - goto retry; - } + /* + * Removes the UTF8 sequence, and replace it by a charref + * and continue the transcoding phase, hoping the error + * did not mangle the encoder state. + */ + charrefLen = snprintf((char *) &charref[0], sizeof(charref), + "&#%d;", cur); + xmlBufferShrink(in, len); + xmlBufferGrow(out, charrefLen * 4); + written = out->size - out->use - 1; + toconv = charrefLen; + ret = xmlEncOutputChunk(handler, &out->content[out->use], &written, + charref, &toconv); + if ((ret < 0) || (toconv != charrefLen)) + return(XML_ENC_ERR_INTERNAL); + + out->use += written; + writtentot += written; + out->content[out->use] = 0; + goto retry; } return(writtentot ? writtentot : ret); } @@ -2796,19 +2652,19 @@ int xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { int ret = 0; int tofree = 0; - int i, handler_in_list = 0; - - /* Avoid unused variable warning if features are disabled. */ - (void) handler_in_list; + int i = 0; if (handler == NULL) return(-1); - if (handler->name == NULL) return(-1); + + for (i = 0; i < (int) NUM_DEFAULT_HANDLERS; i++) { + if (handler == &defaultHandlers[i]) + return(0); + } + if (handlers != NULL) { for (i = 0;i < nbCharEncodingHandler; i++) { - if (handler == handlers[i]) { - handler_in_list = 1; - break; - } + if (handler == handlers[i]) + return(0); } } #ifdef LIBXML_ICONV_ENABLED @@ -2816,8 +2672,7 @@ xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { * Iconv handlers can be used only once, free the whole block. * and the associated icon resources. */ - if ((handler_in_list == 0) && - ((handler->iconv_out != NULL) || (handler->iconv_in != NULL))) { + if ((handler->iconv_out != NULL) || (handler->iconv_in != NULL)) { tofree = 1; if (handler->iconv_out != NULL) { if (iconv_close(handler->iconv_out)) @@ -2832,8 +2687,7 @@ xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { } #endif /* LIBXML_ICONV_ENABLED */ #ifdef LIBXML_ICU_ENABLED - if ((handler_in_list == 0) && - ((handler->uconv_out != NULL) || (handler->uconv_in != NULL))) { + if ((handler->uconv_out != NULL) || (handler->uconv_in != NULL)) { tofree = 1; if (handler->uconv_out != NULL) { closeIcuConverter(handler->uconv_out); @@ -2852,14 +2706,6 @@ xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { 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); } @@ -2905,15 +2751,11 @@ xmlByteConsumed(xmlParserCtxtPtr ctxt) { written = 32000; ret = xmlEncOutputChunk(handler, &convbuf[0], &written, cur, &toconv); - if (ret < 0) { - if (written > 0) - ret = -2; - else - return(-1); - } + if ((ret != XML_ENC_ERR_SUCCESS) && (ret != XML_ENC_ERR_SPACE)) + return(-1); unused += written; cur += toconv; - } while (ret == -2); + } while (ret == XML_ENC_ERR_SPACE); } if (in->buf->rawconsumed < unused) return(-1); @@ -2936,9 +2778,10 @@ xmlByteConsumed(xmlParserCtxtPtr ctxt) { * 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 + * Returns the number of bytes written or an XML_ENC_ERR code. + * * The value of @inlen after return is the number of octets consumed - * as the return value is positive, else unpredictable. + * as the return value is positive, else unpredictable. * The value of @outlen after return is the number of octets consumed. */ static int @@ -2952,7 +2795,7 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (xlattable == NULL)) - return(-1); + return(XML_ENC_ERR_INTERNAL); if (in == NULL) { /* * initialization nothing to do @@ -2970,21 +2813,21 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, /* trailing byte in leading position */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } else if (d < 0xE0) { unsigned char c; if (!(in < inend)) { /* trailing byte not in input buffer */ *outlen = out - outstart; *inlen = processed - instart; - return(-3); + return(XML_ENC_ERR_PARTIAL); } c = *in++; if ((c & 0xC0) != 0x80) { /* not a trailing byte */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } c = c & 0x3F; d = d & 0x1F; @@ -2993,7 +2836,7 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, /* not in character set */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } *out++ = d; } else if (d < 0xF0) { @@ -3003,21 +2846,21 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, /* trailing bytes not in input buffer */ *outlen = out - outstart; *inlen = processed - instart; - return(-3); + return(XML_ENC_ERR_PARTIAL); } c1 = *in++; if ((c1 & 0xC0) != 0x80) { /* not a trailing byte (c1) */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } c2 = *in++; if ((c2 & 0xC0) != 0x80) { /* not a trailing byte (c2) */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } c1 = c1 & 0x3F; c2 = c2 & 0x3F; @@ -3028,14 +2871,14 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, /* not in character set */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } *out++ = d; } else { /* cannot transcode >= U+010000 */ *outlen = out - outstart; *inlen = processed - instart; - return(-2); + return(XML_ENC_ERR_INPUT); } processed = in; } @@ -3053,7 +2896,9 @@ UTF8ToISO8859x(unsigned char* out, int *outlen, * * 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 + * + * Returns the number of bytes written or an XML_ENC_ERR code. + * * The value of @inlen after return is the number of octets consumed * The value of @outlen after return is the number of octets produced. */ @@ -3070,7 +2915,7 @@ ISO8859xToUTF8(unsigned char* out, int *outlen, if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL) || (unicodetable == NULL)) - return(-1); + return(XML_ENC_ERR_INTERNAL); outend = out + *outlen; inend = in + *inlen; instop = inend; @@ -3082,7 +2927,7 @@ ISO8859xToUTF8(unsigned char* out, int *outlen, /* undefined code point */ *outlen = out - outstart; *inlen = in - instart; - return (-1); + return(XML_ENC_ERR_INPUT); } if (c < 0x800) { *out++ = ((c >> 6) & 0x1F) | 0xC0; @@ -3115,7 +2960,7 @@ ISO8859xToUTF8(unsigned char* out, int *outlen, * Lookup tables for ISO-8859-2..ISO-8859-16 transcoding * ************************************************************************/ -static unsigned short const xmlunicodetable_ISO8859_2 [128] = { +static const unsigned short xmlunicodetable_ISO8859_2 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3164,7 +3009,7 @@ static const unsigned char xmltranscodetable_ISO8859_2 [48 + 6 * 64] = { "\x00\x00\x00\xf3\xf4\x00\xf6\xf7\x00\x00\xfa\x00\xfc\xfd\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_3 [128] = { +static const unsigned short xmlunicodetable_ISO8859_3 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3217,7 +3062,7 @@ static const unsigned char xmltranscodetable_ISO8859_3 [48 + 7 * 64] = { "\x00\xf1\xf2\xf3\xf4\x00\xf6\xf7\x00\xf9\xfa\xfb\xfc\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_4 [128] = { +static const unsigned short xmlunicodetable_ISO8859_4 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3266,7 +3111,7 @@ static const unsigned char xmltranscodetable_ISO8859_4 [48 + 6 * 64] = { "\x00\x00\x00\x00\xf4\xf5\xf6\xf7\xf8\x00\xfa\xfb\xfc\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_5 [128] = { +static const unsigned short xmlunicodetable_ISO8859_5 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3315,7 +3160,7 @@ static const unsigned char xmltranscodetable_ISO8859_5 [48 + 6 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_6 [128] = { +static const unsigned short xmlunicodetable_ISO8859_6 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3360,7 +3205,7 @@ static const unsigned char xmltranscodetable_ISO8859_6 [48 + 5 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_7 [128] = { +static const unsigned short xmlunicodetable_ISO8859_7 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3413,7 +3258,7 @@ static const unsigned char xmltranscodetable_ISO8859_7 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_8 [128] = { +static const unsigned short xmlunicodetable_ISO8859_8 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3466,7 +3311,7 @@ static const unsigned char xmltranscodetable_ISO8859_8 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_9 [128] = { +static const unsigned short xmlunicodetable_ISO8859_9 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3511,7 +3356,7 @@ static const unsigned char xmltranscodetable_ISO8859_9 [48 + 5 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_10 [128] = { +static const unsigned short xmlunicodetable_ISO8859_10 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3564,7 +3409,7 @@ static const unsigned char xmltranscodetable_ISO8859_10 [48 + 7 * 64] = { "\xf0\x00\x00\xf3\xf4\xf5\xf6\x00\xf8\x00\xfa\xfb\xfc\xfd\xfe\x00" }; -static unsigned short const xmlunicodetable_ISO8859_11 [128] = { +static const unsigned short xmlunicodetable_ISO8859_11 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3613,7 +3458,7 @@ static const unsigned char xmltranscodetable_ISO8859_11 [48 + 6 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_13 [128] = { +static const unsigned short xmlunicodetable_ISO8859_13 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3666,7 +3511,7 @@ static const unsigned char xmltranscodetable_ISO8859_13 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\xcd\xed\x00\x00\x00\xcf\xef\x00\x00\x00" }; -static unsigned short const xmlunicodetable_ISO8859_14 [128] = { +static const unsigned short xmlunicodetable_ISO8859_14 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3731,7 +3576,7 @@ static const unsigned char xmltranscodetable_ISO8859_14 [48 + 10 * 64] = { "\x00\xf1\xf2\xf3\xf4\xf5\xf6\x00\xf8\xf9\xfa\xfb\xfc\xfd\x00\xff" }; -static unsigned short const xmlunicodetable_ISO8859_15 [128] = { +static const unsigned short xmlunicodetable_ISO8859_15 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3780,7 +3625,7 @@ static const unsigned char xmltranscodetable_ISO8859_15 [48 + 6 * 64] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" }; -static unsigned short const xmlunicodetable_ISO8859_16 [128] = { +static const unsigned short xmlunicodetable_ISO8859_16 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3972,24 +3817,6 @@ static int UTF8ToISO8859_16 (unsigned char* out, int *outlen, 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 diff --git a/entities.c b/entities.c index 84435515f73..f7792a8138e 100644 --- a/entities.c +++ b/entities.c @@ -23,10 +23,11 @@ #include #include #include -#include #include +#include -#include "save.h" +#include "private/entities.h" +#include "private/error.h" /* * The XML predefined entities. @@ -37,83 +38,44 @@ static xmlEntity xmlEntityLt = { NULL, NULL, NULL, NULL, NULL, NULL, BAD_CAST "<", BAD_CAST "<", 1, XML_INTERNAL_PREDEFINED_ENTITY, - NULL, NULL, NULL, NULL, 0, 1 + NULL, NULL, NULL, NULL, 0, 0, 0 }; 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 + NULL, NULL, NULL, NULL, 0, 0, 0 }; 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 + NULL, NULL, NULL, NULL, 0, 0, 0 }; 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 + NULL, NULL, NULL, NULL, 0, 0, 0 }; 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 + NULL, NULL, NULL, NULL, 0, 0, 0 }; -/** - * xmlEntitiesErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ -static void -xmlEntitiesErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} - -/** - * xmlEntitiesErr: - * @code: the error code - * @msg: the message - * - * Raise an error. - */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlEntitiesErr(xmlParserErrors code, const char *msg) -{ - __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL); -} - -/** - * xmlEntitiesWarn: - * @code: the error code - * @msg: the message - * - * Raise a warning. - */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlEntitiesWarn(xmlParserErrors code, const char *msg, const xmlChar *str1) -{ - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_TREE, code, - XML_ERR_WARNING, NULL, 0, - (const char *)str1, NULL, NULL, 0, 0, - msg, (const char *)str1, NULL); -} - /* - * xmlFreeEntity : clean-up an entity record. + * xmlFreeEntity: + * @entity: an entity + * + * Frees the entity. */ -static void +void xmlFreeEntity(xmlEntityPtr entity) { xmlDictPtr dict = NULL; @@ -125,39 +87,22 @@ xmlFreeEntity(xmlEntityPtr entity) dict = entity->doc->dict; - if ((entity->children) && (entity->owner == 1) && + if ((entity->children) && (entity == (xmlEntityPtr) entity->children->parent)) xmlFreeNodeList(entity->children); - if (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); - } + if ((entity->name != NULL) && + ((dict == NULL) || (!xmlDictOwns(dict, entity->name)))) + 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); } @@ -167,44 +112,43 @@ xmlFreeEntity(xmlEntityPtr entity) * internal routine doing the entity node structures allocations */ static xmlEntityPtr -xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, +xmlCreateEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); - if (ret == NULL) { - xmlEntitiesErrMemory("xmlCreateEntity: malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlEntity)); + ret->doc = doc; ret->type = XML_ENTITY_DECL; - ret->checked = 0; /* * fill the structure. */ ret->etype = (xmlEntityType) type; - if (dict == NULL) { + if ((doc == NULL) || (doc->dict == NULL)) ret->name = xmlStrdup(name); - if (ExternalID != NULL) - ret->ExternalID = xmlStrdup(ExternalID); - if (SystemID != NULL) - ret->SystemID = xmlStrdup(SystemID); - } else { - ret->name = xmlDictLookup(dict, name, -1); - if (ExternalID != NULL) - ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); - if (SystemID != NULL) - ret->SystemID = xmlDictLookup(dict, SystemID, -1); + else + ret->name = xmlDictLookup(doc->dict, name, -1); + if (ret->name == NULL) + goto error; + if (ExternalID != NULL) { + ret->ExternalID = xmlStrdup(ExternalID); + if (ret->ExternalID == NULL) + goto error; + } + if (SystemID != NULL) { + ret->SystemID = xmlStrdup(SystemID); + if (ret->SystemID == NULL) + goto error; } if (content != NULL) { ret->length = xmlStrlen(content); - if ((dict != NULL) && (ret->length < 5)) - ret->content = (xmlChar *) - xmlDictLookup(dict, content, ret->length); - else - ret->content = xmlStrndup(content, ret->length); + ret->content = xmlStrndup(content, ret->length); + if (ret->content == NULL) + goto error; } else { ret->length = 0; ret->content = NULL; @@ -212,28 +156,53 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, ret->URI = NULL; /* to be computed by the layer knowing the defining entity */ ret->orig = NULL; - ret->owner = 0; return(ret); + +error: + xmlFreeEntity(ret); + return(NULL); } -/* - * xmlAddEntity : register a new entity for an entities table. +/** + * xmlAddEntity: + * @doc: the document + * @extSubset: add to the external or internal subset + * @name: the entity name + * @type: the entity type XML_xxx_yyy_ENTITY + * @ExternalID: the entity external ID if available + * @SystemID: the entity system ID if available + * @content: the entity content + * @out: pointer to resulting entity (optional) + * + * Register a new entity for this document. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors error code. */ -static xmlEntityPtr -xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, +int +xmlAddEntity(xmlDocPtr doc, int extSubset, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, - const xmlChar *content) { + const xmlChar *content, xmlEntityPtr *out) { + xmlDtdPtr dtd; xmlDictPtr dict = NULL; xmlEntitiesTablePtr table = NULL; xmlEntityPtr ret, predef; + int res; - if (name == NULL) - return(NULL); + if (out != NULL) + *out = NULL; + if ((doc == NULL) || (name == NULL)) + return(XML_ERR_ARGUMENT); + dict = doc->dict; + + if (extSubset) + dtd = doc->extSubset; + else + dtd = doc->intSubset; if (dtd == NULL) - return(NULL); - if (dtd->doc != NULL) - dict = dtd->doc->dict; + return(XML_DTD_NO_DTD); switch (type) { case XML_INTERNAL_GENERAL_ENTITY: @@ -270,41 +239,60 @@ xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, } } } - if (!valid) { - xmlEntitiesWarn(XML_ERR_ENTITY_PROCESSING, - "xmlAddEntity: invalid redeclaration of predefined" - " entity '%s'", name); - return(NULL); - } + if (!valid) + return(XML_ERR_REDECL_PREDEF_ENTITY); } - if (dtd->entities == NULL) + if (dtd->entities == NULL) { dtd->entities = xmlHashCreateDict(0, dict); + if (dtd->entities == NULL) + return(XML_ERR_NO_MEMORY); + } table = dtd->entities; break; case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: - if (dtd->pentities == NULL) + if (dtd->pentities == NULL) { dtd->pentities = xmlHashCreateDict(0, dict); + if (dtd->pentities == NULL) + return(XML_ERR_NO_MEMORY); + } table = dtd->pentities; break; - case XML_INTERNAL_PREDEFINED_ENTITY: - return(NULL); + default: + return(XML_ERR_ARGUMENT); } - if (table == NULL) - return(NULL); - ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); + ret = xmlCreateEntity(dtd->doc, name, type, ExternalID, SystemID, content); if (ret == NULL) - return(NULL); - ret->doc = dtd->doc; + return(XML_ERR_NO_MEMORY); - if (xmlHashAddEntry(table, name, ret)) { + res = xmlHashAdd(table, name, ret); + if (res < 0) { + xmlFreeEntity(ret); + return(XML_ERR_NO_MEMORY); + } else if (res == 0) { /* * entity was already defined at another level. */ xmlFreeEntity(ret); - return(NULL); + return(XML_WAR_ENTITY_REDEFINED); } - return(ret); + + /* + * Link it to the DTD + */ + ret->parent = dtd; + ret->doc = dtd->doc; + if (dtd->last == NULL) { + dtd->children = dtd->last = (xmlNodePtr) ret; + } else { + dtd->last->next = (xmlNodePtr) ret; + ret->prev = dtd->last; + dtd->last = (xmlNodePtr) ret; + } + + if (out != NULL) + *out = ret; + return(0); } /** @@ -361,34 +349,8 @@ xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; - xmlDtdPtr dtd; - - if (doc == NULL) { - xmlEntitiesErr(XML_DTD_NO_DOC, - "xmlAddDtdEntity: document is NULL"); - return(NULL); - } - if (doc->extSubset == NULL) { - xmlEntitiesErr(XML_DTD_NO_DTD, - "xmlAddDtdEntity: document without external subset"); - return(NULL); - } - dtd = doc->extSubset; - ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); - if (ret == NULL) return(NULL); - /* - * Link it to the DTD - */ - ret->parent = dtd; - ret->doc = dtd->doc; - if (dtd->last == NULL) { - dtd->children = dtd->last = (xmlNodePtr) ret; - } else { - dtd->last->next = (xmlNodePtr) ret; - ret->prev = dtd->last; - dtd->last = (xmlNodePtr) ret; - } + xmlAddEntity(doc, 1, name, type, ExternalID, SystemID, content, &ret); return(ret); } @@ -410,34 +372,8 @@ xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; - xmlDtdPtr dtd; - - if (doc == NULL) { - xmlEntitiesErr(XML_DTD_NO_DOC, - "xmlAddDocEntity: document is NULL"); - return(NULL); - } - if (doc->intSubset == NULL) { - xmlEntitiesErr(XML_DTD_NO_DTD, - "xmlAddDocEntity: document without internal subset"); - return(NULL); - } - dtd = doc->intSubset; - ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); - if (ret == NULL) return(NULL); - /* - * Link it to the DTD - */ - ret->parent = dtd; - ret->doc = dtd->doc; - if (dtd->last == NULL) { - dtd->children = dtd->last = (xmlNodePtr) ret; - } else { - dtd->last->next = (xmlNodePtr) ret; - ret->prev = dtd->last; - dtd->last = (xmlNodePtr) ret; - } + xmlAddEntity(doc, 0, name, type, ExternalID, SystemID, content, &ret); return(ret); } @@ -462,21 +398,12 @@ xmlEntityPtr xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { - xmlEntityPtr ret; - xmlDictPtr dict; - if ((doc != NULL) && (doc->intSubset != NULL)) { return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content)); } - if (doc != NULL) - dict = doc->dict; - else - dict = NULL; - ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); - if (ret == NULL) + if (name == NULL) return(NULL); - ret->doc = doc; - return(ret); + return(xmlCreateEntity(doc, name, type, ExternalID, SystemID, content)); } /** @@ -627,11 +554,9 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { * allocate an translation buffer. */ buffer_size = 1000; - buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); - if (buffer == NULL) { - xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed"); + buffer = (xmlChar *) xmlMalloc(buffer_size); + if (buffer == NULL) return(NULL); - } out = buffer; while (*cur != '\0') { @@ -731,57 +656,18 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { * cur[3] is 10xxxxxx if cur[0] is 1111xxxx * cur[0] is not 11111xxx */ - char buf[11], *ptr; - int val = 0, l = 1; - - if (((cur[0] & 0xC0) != 0xC0) || - ((cur[1] & 0xC0) != 0x80) || - (((cur[0] & 0xE0) == 0xE0) && ((cur[2] & 0xC0) != 0x80)) || - (((cur[0] & 0xF0) == 0xF0) && ((cur[3] & 0xC0) != 0x80)) || - (((cur[0] & 0xF8) == 0xF8))) { - xmlEntitiesErr(XML_CHECK_NOT_UTF8, - "xmlEncodeEntities: input not UTF-8"); - 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, - "xmlEncodeEntities: 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; + char buf[13], *ptr; + int val, l; + + l = 4; + val = xmlGetUTF8Char(cur, &l); + if (val < 0) { + val = 0xFFFD; + cur++; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + cur += l; } /* * We could do multiple things here. Just save as a char ref @@ -790,7 +676,6 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { buf[sizeof(buf) - 1] = 0; ptr = buf; while (*ptr != 0) *out++ = *ptr++; - cur += l; continue; } } else if (IS_BYTE_CHAR(*cur)) { @@ -807,7 +692,6 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { return(buffer); mem_error: - xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed"); xmlFree(buffer); return(NULL); } @@ -867,11 +751,9 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) * allocate an translation buffer. */ buffer_size = 1000; - buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); - if (buffer == NULL) { - xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed"); + buffer = (xmlChar *) xmlMalloc(buffer_size); + if (buffer == NULL) return(NULL); - } out = buffer; while (*cur != '\0') { @@ -927,7 +809,6 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) return(buffer); mem_error: - xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed"); xmlFree(buffer); return(NULL); } @@ -984,27 +865,47 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlEntityPtr cur; cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); - if (cur == NULL) { - xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlEntity)); cur->type = XML_ENTITY_DECL; cur->etype = ent->etype; - if (ent->name != NULL) + if (ent->name != NULL) { cur->name = xmlStrdup(ent->name); - if (ent->ExternalID != NULL) + if (cur->name == NULL) + goto error; + } + if (ent->ExternalID != NULL) { cur->ExternalID = xmlStrdup(ent->ExternalID); - if (ent->SystemID != NULL) + if (cur->ExternalID == NULL) + goto error; + } + if (ent->SystemID != NULL) { cur->SystemID = xmlStrdup(ent->SystemID); - if (ent->content != NULL) + if (cur->SystemID == NULL) + goto error; + } + if (ent->content != NULL) { cur->content = xmlStrdup(ent->content); - if (ent->orig != NULL) + if (cur->content == NULL) + goto error; + } + if (ent->orig != NULL) { cur->orig = xmlStrdup(ent->orig); - if (ent->URI != NULL) + if (cur->orig == NULL) + goto error; + } + if (ent->URI != NULL) { cur->URI = xmlStrdup(ent->URI); + if (cur->URI == NULL) + goto error; + } return(cur); + +error: + xmlFreeEntity(cur); + return(NULL); } /** @@ -1017,53 +918,12 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table) { - return(xmlHashCopy(table, xmlCopyEntity)); + return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper)); } #endif /* LIBXML_TREE_ENABLED */ #ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlDumpEntityContent: - * @buf: An XML buffer. - * @content: The entity content. - * - * This will dump the quoted string value, taking care of the special - * treatment required by % - */ -static void -xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) { - if (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. @@ -1073,81 +933,15 @@ xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) { */ void xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { - if ((buf == NULL) || (ent == NULL)) return; - switch (ent->etype) { - case XML_INTERNAL_GENERAL_ENTITY: - xmlBufferWriteChar(buf, "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"); - } + xmlSaveCtxtPtr save; + + if ((buf == NULL) || (ent == NULL)) + return; + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) ent); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -1158,9 +952,9 @@ xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { * When using the hash table scan function, arguments need to be reversed */ static void -xmlDumpEntityDeclScan(void *ent, void *buf, +xmlDumpEntityDeclScan(void *ent, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent); + xmlSaveTree(save, ent); } /** @@ -1172,6 +966,14 @@ xmlDumpEntityDeclScan(void *ent, void *buf, */ void xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) { - xmlHashScan(table, xmlDumpEntityDeclScan, buf); + xmlSaveCtxtPtr save; + + if ((buf == NULL) || (table == NULL)) + return; + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpEntityDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */ diff --git a/error.c b/error.c index 5f42eadcc6d..b678a0ee004 100644 --- a/error.c +++ b/error.c @@ -11,46 +11,169 @@ #include #include +#include #include #include #include -#include - -void XMLCDECL xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED, - const char *msg, - ...) LIBXML_ATTR_FORMAT(2,3); - -#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; \ - }} \ + +#include "private/error.h" +#include "private/string.h" + +/************************************************************************ + * * + * Error struct * + * * + ************************************************************************/ + +static int +xmlVSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + char *message = NULL; + char *fileCopy = NULL; + char *str1Copy = NULL; + char *str2Copy = NULL; + char *str3Copy = NULL; + + if (code == XML_ERR_OK) { + xmlResetError(err); + return(0); + } + + /* + * Formatting the message + */ + if (fmt == NULL) { + message = xmlMemStrdup("No error message provided"); + } else { + xmlChar *tmp; + int res; + + res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap); + if (res < 0) + goto err_memory; + message = (char *) tmp; + } + if (message == NULL) + goto err_memory; + + if (file != NULL) { + fileCopy = (char *) xmlStrdup((const xmlChar *) file); + if (fileCopy == NULL) + goto err_memory; + } + if (str1 != NULL) { + str1Copy = (char *) xmlStrdup((const xmlChar *) str1); + if (str1Copy == NULL) + goto err_memory; + } + if (str2 != NULL) { + str2Copy = (char *) xmlStrdup((const xmlChar *) str2); + if (str2Copy == NULL) + goto err_memory; + } + if (str3 != NULL) { + str3Copy = (char *) xmlStrdup((const xmlChar *) str3); + if (str3Copy == NULL) + goto err_memory; + } + + xmlResetError(err); + + err->domain = domain; + err->code = code; + err->message = message; + err->level = level; + err->file = fileCopy; + err->line = line; + err->str1 = str1Copy; + err->str2 = str2Copy; + err->str3 = str3Copy; + err->int1 = int1; + err->int2 = col; + err->node = node; + err->ctxt = ctxt; + + return(0); + +err_memory: + xmlFree(message); + xmlFree(fileCopy); + xmlFree(str1Copy); + xmlFree(str2Copy); + xmlFree(str3Copy); + return(-1); +} + +static int LIBXML_ATTR_FORMAT(14,15) +xmlSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + va_end(ap); + + return(res); +} + +static int +xmlVUpdateError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + int res; + + /* + * Find first element parent. + */ + if (node != NULL) { + int i; + + for (i = 0; i < 10; i++) { + if ((node->type == XML_ELEMENT_NODE) || + (node->parent == NULL)) + break; + node = node->parent; + } + } + + /* + * Get file and line from node. + */ + if (node != NULL) { + if ((file == NULL) && (node->doc != NULL)) + file = (const char *) node->doc->URL; + + if (line == 0) { + if (node->type == XML_ELEMENT_NODE) + line = node->line; + if ((line == 0) || (line == 65535)) + line = xmlGetLineNo(node); + } + } + + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + + return(res); } /************************************************************************ @@ -67,7 +190,7 @@ void XMLCDECL xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED, * * Default handler for out of context error messages. */ -void XMLCDECL +void xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { va_list args; @@ -83,6 +206,8 @@ xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { * initGenericErrorDefaultFunc: * @handler: the handler * + * DEPRECATED: Use xmlSetGenericErrorFunc. + * * Set or reset (if NULL) the default handler for generic errors * to the builtin error function. */ @@ -100,14 +225,21 @@ initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler) * @ctx: the new error handling context * @handler: the new handler function * - * Function to reset the handler and the error context for out of - * context error messages. - * This simply means that @handler will be called for subsequent - * error messages while not parsing nor validating. And @ctx will - * be passed as first argument to @handler - * One can simply force messages to be emitted to another FILE * than - * stderr by setting @ctx to this file handle and @handler to NULL. - * For multi-threaded applications, this must be set separately for each thread. + * DEPRECATED: See xmlSetStructuredErrorFunc for alternatives. + * + * Set the global "generic" handler and context for error messages. + * The generic error handler will only receive fragments of error + * messages which should be concatenated or printed to a stream. + * + * If handler is NULL, use the built-in default handler which prints + * to stderr. + * + * Since this is a global setting, it's a good idea to reset the + * error handler to its default value after collecting the errors + * you're interested in. + * + * For multi-threaded applications, this must be set separately for + * each thread. */ void xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { @@ -123,12 +255,30 @@ xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { * @ctx: the new error handling context * @handler: the new handler function * - * Function to reset the handler and the error context for out of - * context structured error messages. - * This simply means that @handler will be called for subsequent - * error messages while not parsing nor validating. And @ctx will - * be passed as first argument to @handler - * For multi-threaded applications, this must be set separately for each thread. + * DEPRECATED: Use a per-context error handler. + * + * It's recommended to use the per-context error handlers instead: + * + * - xmlCtxtSetErrorHandler (since 2.13.0) + * - xmlTextReaderSetStructuredErrorHandler + * - xmlXPathSetErrorHandler (since 2.13.0) + * - xmlXIncludeSetErrorHandler (since 2.13.0) + * - xmlSchemaSetParserStructuredErrors + * - xmlSchemaSetValidStructuredErrors + * - xmlRelaxNGSetParserStructuredErrors + * - xmlRelaxNGSetValidStructuredErrors + * + * Set the global "structured" handler and context for error messages. + * If handler is NULL, the error handler is deactivated. + * + * The structured error handler takes precedence over "generic" + * handlers, even per-context generic handlers. + * + * Since this is a global setting, it's a good idea to deactivate the + * error handler after collecting the errors you're interested in. + * + * For multi-threaded applications, this must be set separately for + * each thread. */ void xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { @@ -146,6 +296,8 @@ xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { * xmlParserPrintFileInfo: * @input: an xmlParserInputPtr input * + * DEPRECATED: Use xmlFormatError. + * * Displays the associated file and line information for the current input */ @@ -163,7 +315,7 @@ xmlParserPrintFileInfo(xmlParserInputPtr input) { } /** - * xmlParserPrintFileContext: + * xmlParserPrintFileContextInternal: * @input: an xmlParserInputPtr input * * Displays current context within the input content for error tracking @@ -172,7 +324,7 @@ xmlParserPrintFileInfo(xmlParserInputPtr input) { static void xmlParserPrintFileContextInternal(xmlParserInputPtr input , xmlGenericErrorFunc channel, void *data ) { - const xmlChar *cur, *base; + const xmlChar *cur, *base, *start; unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ xmlChar content[81]; /* space for 80 chars + line terminator */ xmlChar *ctnt; @@ -188,22 +340,35 @@ xmlParserPrintFileContextInternal(xmlParserInputPtr input , } n = 0; /* search backwards for beginning-of-line (to max buff size) */ - while ((n++ < (sizeof(content)-1)) && (cur > base) && - (*(cur) != '\n') && (*(cur) != '\r')) + while ((n < sizeof(content) - 1) && (cur > base) && + (*cur != '\n') && (*cur != '\r')) { cur--; - if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; + n++; + } + if ((n > 0) && ((*cur == '\n') || (*cur == '\r'))) { + cur++; + } else { + /* skip over continuation bytes */ + while ((cur < input->cur) && ((*cur & 0xC0) == 0x80)) + 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; + start = cur; /* copy selected text to our buffer */ - while ((*cur != 0) && (*(cur) != '\n') && - (*(cur) != '\r') && (n < sizeof(content)-1)) { - *ctnt++ = *cur++; - n++; + while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) { + int len = input->end - cur; + int c = xmlGetUTF8Char(cur, &len); + + if ((c < 0) || (n + len > sizeof(content)-1)) + break; + cur += len; + n += len; } - *ctnt = 0; + memcpy(content, start, n); + content[n] = 0; /* print out the selected text */ channel(data ,"%s\n", content); /* create blank line with problem pointer */ @@ -224,6 +389,8 @@ xmlParserPrintFileContextInternal(xmlParserInputPtr input , * xmlParserPrintFileContext: * @input: an xmlParserInputPtr input * + * DEPRECATED: Use xmlFormatError. + * * Displays current context within the input content for error tracking */ void @@ -233,35 +400,37 @@ xmlParserPrintFileContext(xmlParserInputPtr input) { } /** - * xmlReportError: - * @err: the error - * @ctx: the parser context or NULL - * @str: the formatted error message + * xmlFormatError: + * @err: the error + * @channel: callback + * @data: user data for callback + * + * Report a formatted error to a printf-like callback. * - * Report an error with its context, replace the 4 old error/warning - * routines. + * This can result in a verbose multi-line report including additional + * information from the parser context. + * + * Available since 2.13.0. */ -static void -xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, - xmlGenericErrorFunc channel, void *data) +void +xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data) { - char *file = NULL; - int line = 0; - int code = -1; + const char *message; + const char *file; + int line; + int code; int domain; const xmlChar *name = NULL; xmlNodePtr node; xmlErrorLevel level; + xmlParserCtxtPtr ctxt = NULL; xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL; - if (err == NULL) + if ((err == NULL) || (channel == NULL)) return; - if (channel == NULL) { - channel = xmlGenericError; - data = xmlGenericErrorContext; - } + message = err->message; file = err->file; line = err->line; code = err->code; @@ -272,25 +441,30 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, if (code == XML_ERR_OK) return; - if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || + (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || + (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { + ctxt = err->ctxt; + } + + if ((node != NULL) && (node->type == XML_ELEMENT_NODE) && + (domain != XML_FROM_SCHEMASV)) name = node->name; /* * Maintain the compatibility with the legacy error handling */ - if (ctxt != NULL) { + if ((ctxt != NULL) && (ctxt->input != NULL)) { input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && + if ((input->filename == NULL) && (ctxt->inputNr > 1)) { cur = input; input = ctxt->inputTab[ctxt->inputNr - 2]; } - if (input != NULL) { - if (input->filename) - channel(data, "%s:%d: ", input->filename, input->line); - else if ((line != 0) && (domain == XML_FROM_PARSER)) - channel(data, "Entity: line %d: ", input->line); - } + if (input->filename) + channel(data, "%s:%d: ", input->filename, input->line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: ", input->line); } else { if (file != NULL) channel(data, "%s:%d: ", file, line); @@ -391,19 +565,35 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, channel(data, "error : "); break; } - if (str != NULL) { + if (message != NULL) { int len; - len = xmlStrlen((const xmlChar *)str); - if ((len > 0) && (str[len - 1] != '\n')) - channel(data, "%s\n", str); + len = xmlStrlen((const xmlChar *) message); + if ((len > 0) && (message[len - 1] != '\n')) + channel(data, "%s\n", message); else - channel(data, "%s", str); + channel(data, "%s", message); } else { - channel(data, "%s\n", "out of memory error"); + channel(data, "%s\n", "No error message provided"); } if (ctxt != NULL) { + if ((input != NULL) && + ((input->buf == NULL) || (input->buf->encoder == NULL)) && + (code == XML_ERR_INVALID_ENCODING) && + (input->cur < input->end)) { + int i; + + channel(data, "Bytes:"); + for (i = 0; i < 4; i++) { + if (input->cur + i >= input->end) + break; + channel(data, " 0x%02X", input->cur[i]); + } + channel(data, "\n"); + } + xmlParserPrintFileContextInternal(input, channel, data); + if (cur != NULL) { if (cur->filename) channel(data, "%s:%d: \n", cur->filename, cur->line); @@ -428,12 +618,53 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, } /** - * __xmlRaiseError: + * xmlRaiseMemoryError: + * @schannel: the structured callback channel + * @channel: the old callback channel + * @data: the callback data + * @domain: the domain for the error + * @error: optional error struct to be filled + * + * Update the global and optional error structure, then forward the + * error to an error handler. + * + * This function doesn't make memory allocations which are likely + * to fail after an OOM error. + */ +void +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error) +{ + xmlError *lastError = &xmlLastError; + + xmlResetLastError(); + lastError->domain = domain; + lastError->code = XML_ERR_NO_MEMORY; + lastError->level = XML_ERR_FATAL; + + if (error != NULL) { + xmlResetError(error); + error->domain = domain; + error->code = XML_ERR_NO_MEMORY; + error->level = XML_ERR_FATAL; + } + + if (schannel != NULL) { + schannel(data, lastError); + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, lastError); + } else if (channel != NULL) { + channel(data, "libxml2: out of memory\n"); + } +} + +/** + * xmlVRaiseError: * @schannel: the structured callback channel * @channel: the old callback channel * @data: the callback data * @ctx: the parser context or NULL - * @ctx: the parser context or NULL + * @node: the current node or NULL * @domain: the domain for the error * @code: the code for the error * @level: the xmlErrorLevel for the error @@ -445,245 +676,128 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, * @int1: extra int info * @col: column number of the error or 0 if N/A * @msg: the message to display/transmit - * @...: extra parameters for the message display + * @ap: extra parameters for the message display * * Update the appropriate global or contextual error structure, * then forward the error message down the parser or generic * error callback handler + * + * Returns 0 on success, -1 if a memory allocation failed. */ -void 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, ...) +int +xmlVRaiseError(xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, void *data, void *ctx, + xmlNode *node, int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, va_list ap) { xmlParserCtxtPtr ctxt = NULL; - xmlNodePtr node = (xmlNodePtr) nod; - char *str = NULL; - xmlParserInputPtr input = NULL; - xmlErrorPtr to = &xmlLastError; - xmlNodePtr baseptr = NULL; + /* xmlLastError is a macro retrieving the per-thread global. */ + xmlErrorPtr lastError = &xmlLastError; + xmlErrorPtr to = lastError; if (code == XML_ERR_OK) - return; + return(0); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (code == XML_ERR_INTERNAL_ERROR) { + fprintf(stderr, "Unexpected error: %d\n", code); + abort(); + } +#endif if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) - return; + return(0); + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { ctxt = (xmlParserCtxtPtr) ctx; - if ((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; - if ((line == 0) || (line == 65535)) - line = xmlGetLineNo(node); + if (ctxt != NULL) + to = &ctxt->lastError; } - /* - * Save the information about the error - */ - xmlResetError(to); - to->domain = domain; - to->code = code; - to->message = str; - to->level = level; - if (file != NULL) - to->file = (char *) xmlStrdup((const xmlChar *) file); - else if (baseptr != NULL) { -#ifdef LIBXML_XINCLUDE_ENABLED - /* - * We check if the error is within an XInclude section and, - * if so, attempt to print out the href of the XInclude instead - * of the usual "base" (doc->URL) for the node (bug 152623). - */ - xmlNodePtr prev = baseptr; - char *href = NULL; - int inclcount = 0; - while (prev != NULL) { - if (prev->prev == NULL) - prev = prev->parent; - else { - prev = prev->prev; - if (prev->type == XML_XINCLUDE_START) { - if (inclcount > 0) { - --inclcount; - } else { - href = (char *) xmlGetProp(prev, BAD_CAST "href"); - if (href != NULL) - break; - } - } else if (prev->type == XML_XINCLUDE_END) - inclcount++; - } - } - if (href != NULL) - to->file = href; - else -#endif - to->file = (char *) xmlStrdup(baseptr->doc->URL); - if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) { - to->file = (char *) xmlStrdup(node->doc->URL); - } + if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, msg, ap)) + return(-1); + + if (to != lastError) { + if (xmlCopyError(to, lastError) < 0) + return(-1); } - to->line = line; - if (str1 != NULL) - to->str1 = (char *) xmlStrdup((const xmlChar *) str1); - if (str2 != NULL) - to->str2 = (char *) xmlStrdup((const xmlChar *) str2); - if (str3 != NULL) - to->str3 = (char *) xmlStrdup((const xmlChar *) str3); - to->int1 = int1; - to->int2 = col; - to->node = node; - to->ctxt = ctx; - - if (to != &xmlLastError) - xmlCopyError(to,&xmlLastError); if (schannel != NULL) { schannel(data, to); - return; - } - - /* - * Find the callback channel if channel param is NULL - */ - if ((ctxt != NULL) && (channel == NULL) && - (xmlStructuredError == NULL) && (ctxt->sax != NULL)) { - if (level == XML_ERR_WARNING) - channel = ctxt->sax->warning; + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, to); + } else if (channel != NULL) { + /* Don't invoke legacy error handlers */ + if ((channel == xmlGenericErrorDefaultFunc) || + (channel == xmlParserError) || + (channel == xmlParserWarning) || + (channel == xmlParserValidityError) || + (channel == xmlParserValidityWarning)) + xmlFormatError(to, xmlGenericError, xmlGenericErrorContext); else - channel = ctxt->sax->error; - data = ctxt->userData; - } else if (channel == NULL) { - channel = xmlGenericError; - if (ctxt != NULL) { - data = ctxt; - } else { - data = xmlGenericErrorContext; - } + channel(data, "%s", to->message); } - if (channel == NULL) - return; - if ((channel == xmlParserError) || - (channel == xmlParserWarning) || - (channel == xmlParserValidityError) || - (channel == xmlParserValidityWarning)) - xmlReportError(to, ctxt, str, NULL, NULL); - else if (((void(*)(void)) channel == (void(*)(void)) fprintf) || - (channel == xmlGenericErrorDefaultFunc)) - xmlReportError(to, ctxt, str, channel, data); - else - channel(data, "%s", str); + return(0); } /** - * __xmlSimpleError: - * @domain: where the error comes from - * @code: the error code - * @node: the context node - * @extra: extra information - * - * Handle an out of memory condition - */ -void -__xmlSimpleError(int domain, int code, xmlNodePtr node, - const char *msg, const char *extra) -{ - - if (code == XML_ERR_NO_MEMORY) { - if (extra) - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); - } else { - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - code, XML_ERR_ERROR, NULL, 0, extra, - NULL, NULL, 0, 0, msg, extra); - } -} -/** - * xmlParserError: - * @ctx: an XML parser context + * __xmlRaiseError: + * @schannel: the structured callback channel + * @channel: the old callback channel + * @data: the callback data + * @ctx: the parser context or NULL + * @nod: the node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @file: the file source of the error (or NULL) + * @line: the line of the error or 0 if N/A + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @col: column number of the error or 0 if N/A * @msg: the message to display/transmit * @...: extra parameters for the message display * - * Display and format an error messages, gives file, line, position and - * extra parameters. + * Update the appropriate global or contextual error structure, + * then forward the error message down the parser or generic + * error callback handler + * + * Returns 0 on success, -1 if a memory allocation failed. */ -void XMLCDECL -xmlParserError(void *ctx, const char *msg, ...) +int +__xmlRaiseError(xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, void *data, void *ctx, + xmlNode *node, int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, ...) { + va_list ap; + int res; + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code, + level, file, line, str1, str2, str3, int1, col, msg, + ap); + va_end(ap); + + return(res); +} + +static void +xmlVFormatLegacyError(void *ctx, const char *level, + const char *fmt, va_list ap) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL; - char * str; + xmlChar *str = NULL; if (ctxt != NULL) { input = ctxt->input; @@ -695,11 +809,13 @@ xmlParserError(void *ctx, const char *msg, ...) xmlParserPrintFileInfo(input); } - xmlGenericError(xmlGenericErrorContext, "error: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) + xmlGenericError(xmlGenericErrorContext, "%s: ", level); + + xmlStrVASPrintf(&str, MAX_ERR_MSG_SIZE, fmt, ap); + if (str != NULL) { + xmlGenericError(xmlGenericErrorContext, "%s", (char *) str); xmlFree(str); + } if (ctxt != NULL) { xmlParserPrintFileContext(input); @@ -712,54 +828,43 @@ xmlParserError(void *ctx, const char *msg, ...) } /** - * xmlParserWarning: + * xmlParserError: * @ctx: an XML parser context * @msg: the message to display/transmit * @...: extra parameters for the message display * - * Display and format a warning messages, gives file, line, position and + * Display and format an error messages, gives file, line, position and * extra parameters. */ -void XMLCDECL -xmlParserWarning(void *ctx, const char *msg, ...) +void +xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - xmlParserInputPtr cur = NULL; - char * str; + va_list ap; - if (ctxt != NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - cur = input; - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - xmlParserPrintFileInfo(input); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "error", msg, ap); + va_end(ap); +} - xmlGenericError(xmlGenericErrorContext, "warning: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); +/** + * xmlParserWarning: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a warning messages, gives file, line, position and + * extra parameters. + */ +void +xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + va_list ap; - if (ctxt != NULL) { - xmlParserPrintFileContext(input); - if (cur != NULL) { - xmlParserPrintFileInfo(cur); - xmlGenericError(xmlGenericErrorContext, "\n"); - xmlParserPrintFileContext(cur); - } - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "warning", msg, ap); + va_end(ap); } -/************************************************************************ - * * - * Handling of validation errors * - * * - ************************************************************************/ - /** * xmlParserValidityError: * @ctx: an XML parser context @@ -769,39 +874,14 @@ xmlParserWarning(void *ctx, const char *msg, ...) * Display and format an validity error messages, gives file, * line, position and extra parameters. */ -void XMLCDECL -xmlParserValidityError(void *ctx, const char *msg, ...) +void +xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); - static int had_info = 0; - - if ((len > 1) && (msg[len - 2] != ':')) { - if (ctxt != NULL) { - input = ctxt->input; - if ((input->filename == NULL) && (ctxt->inputNr > 1)) - input = ctxt->inputTab[ctxt->inputNr - 2]; - - if (had_info == 0) { - xmlParserPrintFileInfo(input); - } - } - xmlGenericError(xmlGenericErrorContext, "validity error: "); - had_info = 0; - } else { - had_info = 1; - } - - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); + va_list ap; - if ((ctxt != NULL) && (input != NULL)) { - xmlParserPrintFileContext(input); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "validity error", msg, ap); + va_end(ap); } /** @@ -813,31 +893,14 @@ xmlParserValidityError(void *ctx, const char *msg, ...) * Display and format a validity warning messages, gives file, line, * position and extra parameters. */ -void XMLCDECL -xmlParserValidityWarning(void *ctx, const char *msg, ...) +void +xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); + va_list ap; - 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); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "validity warning", msg, ap); + va_end(ap); } @@ -853,9 +916,9 @@ xmlParserValidityWarning(void *ctx, const char *msg, ...) * Get the last global error registered. This is per thread if compiled * with thread support. * - * Returns NULL if no error occurred or a pointer to the error + * Returns a pointer to the error */ -xmlErrorPtr +const xmlError * xmlGetLastError(void) { if (xmlLastError.code == XML_ERR_OK) @@ -912,7 +975,7 @@ xmlResetLastError(void) * * Returns NULL if no error occurred or a pointer to the error */ -xmlErrorPtr +const xmlError * xmlCtxtGetLastError(void *ctx) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; @@ -954,43 +1017,352 @@ xmlCtxtResetLastError(void *ctx) * Returns 0 in case of success and -1 in case of error. */ int -xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { - char *message, *file, *str1, *str2, *str3; +xmlCopyError(const xmlError *from, xmlErrorPtr to) { + const char *fmt = NULL; if ((from == NULL) || (to == NULL)) return(-1); - message = (char *) xmlStrdup((xmlChar *) from->message); - file = (char *) xmlStrdup ((xmlChar *) from->file); - str1 = (char *) xmlStrdup ((xmlChar *) from->str1); - str2 = (char *) xmlStrdup ((xmlChar *) from->str2); - str3 = (char *) xmlStrdup ((xmlChar *) from->str3); - - if (to->message != NULL) - xmlFree(to->message); - if (to->file != NULL) - xmlFree(to->file); - if (to->str1 != NULL) - xmlFree(to->str1); - if (to->str2 != NULL) - xmlFree(to->str2); - if (to->str3 != NULL) - xmlFree(to->str3); - to->domain = from->domain; - to->code = from->code; - to->level = from->level; - to->line = from->line; - to->node = from->node; - to->int1 = from->int1; - to->int2 = from->int2; - to->node = from->node; - to->ctxt = from->ctxt; - to->message = message; - to->file = file; - to->str1 = str1; - to->str2 = str2; - to->str3 = str3; - - return 0; + if (from->message != NULL) + fmt = "%s"; + + return(xmlSetError(to, from->ctxt, from->node, + from->domain, from->code, from->level, + from->file, from->line, + from->str1, from->str2, from->str3, + from->int1, from->int2, + fmt, from->message)); } +/** + * xmlErrString: + * @code: an xmlParserErrors code + * + * Returns an error message for a code. + */ +const char * +xmlErrString(xmlParserErrors code) { + const char *errmsg; + + switch (code) { + case XML_ERR_INVALID_HEX_CHARREF: + errmsg = "CharRef: invalid hexadecimal value"; + break; + case XML_ERR_INVALID_DEC_CHARREF: + errmsg = "CharRef: invalid decimal value"; + break; + case XML_ERR_INVALID_CHARREF: + errmsg = "CharRef: invalid value"; + break; + case XML_ERR_INTERNAL_ERROR: + errmsg = "internal error"; + break; + case XML_ERR_PEREF_AT_EOF: + errmsg = "PEReference at end of document"; + break; + case XML_ERR_PEREF_IN_PROLOG: + errmsg = "PEReference in prolog"; + break; + case XML_ERR_PEREF_IN_EPILOG: + errmsg = "PEReference in epilog"; + break; + case XML_ERR_PEREF_NO_NAME: + errmsg = "PEReference: no name"; + break; + case XML_ERR_PEREF_SEMICOL_MISSING: + errmsg = "PEReference: expecting ';'"; + break; + case XML_ERR_ENTITY_LOOP: + errmsg = "Detected an entity reference loop"; + break; + case XML_ERR_ENTITY_NOT_STARTED: + errmsg = "EntityValue: \" or ' expected"; + break; + case XML_ERR_ENTITY_PE_INTERNAL: + errmsg = "PEReferences forbidden in internal subset"; + break; + case XML_ERR_ENTITY_NOT_FINISHED: + errmsg = "EntityValue: \" or ' expected"; + break; + case XML_ERR_ATTRIBUTE_NOT_STARTED: + errmsg = "AttValue: \" or ' expected"; + break; + case XML_ERR_LT_IN_ATTRIBUTE: + errmsg = "Unescaped '<' not allowed in attributes values"; + break; + case XML_ERR_LITERAL_NOT_STARTED: + errmsg = "SystemLiteral \" or ' expected"; + break; + case XML_ERR_LITERAL_NOT_FINISHED: + errmsg = "Unfinished System or Public ID \" or ' expected"; + break; + case XML_ERR_MISPLACED_CDATA_END: + errmsg = "Sequence ']]>' not allowed in content"; + break; + case XML_ERR_URI_REQUIRED: + errmsg = "SYSTEM or PUBLIC, the URI is missing"; + break; + case XML_ERR_PUBID_REQUIRED: + errmsg = "PUBLIC, the Public Identifier is missing"; + break; + case XML_ERR_HYPHEN_IN_COMMENT: + errmsg = "Comment must not contain '--' (double-hyphen)"; + break; + case XML_ERR_PI_NOT_STARTED: + errmsg = "xmlParsePI : no target name"; + break; + case XML_ERR_RESERVED_XML_NAME: + errmsg = "Invalid PI name"; + break; + case XML_ERR_NOTATION_NOT_STARTED: + errmsg = "NOTATION: Name expected here"; + break; + case XML_ERR_NOTATION_NOT_FINISHED: + errmsg = "'>' required to close NOTATION declaration"; + break; + case XML_ERR_VALUE_REQUIRED: + errmsg = "Entity value required"; + break; + case XML_ERR_URI_FRAGMENT: + errmsg = "Fragment not allowed"; + break; + case XML_ERR_ATTLIST_NOT_STARTED: + errmsg = "'(' required to start ATTLIST enumeration"; + break; + case XML_ERR_NMTOKEN_REQUIRED: + errmsg = "NmToken expected in ATTLIST enumeration"; + break; + case XML_ERR_ATTLIST_NOT_FINISHED: + errmsg = "')' required to finish ATTLIST enumeration"; + break; + case XML_ERR_MIXED_NOT_STARTED: + errmsg = "MixedContentDecl : '|' or ')*' expected"; + break; + case XML_ERR_PCDATA_REQUIRED: + errmsg = "MixedContentDecl : '#PCDATA' expected"; + break; + case XML_ERR_ELEMCONTENT_NOT_STARTED: + errmsg = "ContentDecl : Name or '(' expected"; + break; + case XML_ERR_ELEMCONTENT_NOT_FINISHED: + errmsg = "ContentDecl : ',' '|' or ')' expected"; + break; + case XML_ERR_PEREF_IN_INT_SUBSET: + errmsg = + "PEReference: forbidden within markup decl in internal subset"; + break; + case XML_ERR_GT_REQUIRED: + errmsg = "expected '>'"; + break; + case XML_ERR_CONDSEC_INVALID: + errmsg = "XML conditional section '[' expected"; + break; + case XML_ERR_INT_SUBSET_NOT_FINISHED: + errmsg = "Content error in the internal subset"; + break; + case XML_ERR_EXT_SUBSET_NOT_FINISHED: + errmsg = "Content error in the external subset"; + break; + case XML_ERR_CONDSEC_INVALID_KEYWORD: + errmsg = + "conditional section INCLUDE or IGNORE keyword expected"; + break; + case XML_ERR_CONDSEC_NOT_FINISHED: + errmsg = "XML conditional section not closed"; + break; + case XML_ERR_XMLDECL_NOT_STARTED: + errmsg = "Text declaration '' expected"; + break; + case XML_ERR_EXT_ENTITY_STANDALONE: + errmsg = "external parsed entities cannot be standalone"; + break; + case XML_ERR_ENTITYREF_SEMICOL_MISSING: + errmsg = "EntityRef: expecting ';'"; + break; + case XML_ERR_DOCTYPE_NOT_FINISHED: + errmsg = "DOCTYPE improperly terminated"; + break; + case XML_ERR_LTSLASH_REQUIRED: + errmsg = "EndTag: ' @@ -14,42 +11,155 @@ #define IN_LIBXML #include "libxml.h" +#include #include #include +#define XML_GLOBALS_NO_REDEFINITION #include +#include #include +#include +#include #include +#include +#include +#include -/* #define DEBUG_GLOBALS */ +#include "private/dict.h" +#include "private/error.h" +#include "private/globals.h" +#include "private/threads.h" +#include "private/tree.h" + +/* + * Thread-local storage emulation. + * + * This works by replacing a global variable + * + * extern xmlError xmlLastError; + * + * with a macro that calls a function returning a pointer to the global in + * thread-local storage: + * + * xmlError *__xmlLastError(void); + * #define xmlError (*__xmlLastError()); + * + * The code can operate in a multitude of ways depending on the environment. + * First we support POSIX and Windows threads. Then we support both thread-local + * storage provided by the compiler and older methods like thread-specific data + * (pthreads) or TlsAlloc (Windows). + * + * To clean up thread-local storage, we use thread-specific data on POSIX. + * On Windows, we either use DllMain when compiling a DLL or a registered wait + * function for static builds. + */ /* * Helpful Macro */ #ifdef LIBXML_THREAD_ENABLED -#define IS_MAIN_THREAD (xmlIsMainThread()) +#define IS_MAIN_THREAD (xmlIsMainThreadInternal()) #else #define IS_MAIN_THREAD 1 #endif +#define XML_DECLARE_MEMBER(name, type, attrs) \ + type gs_##name; + +struct _xmlGlobalState { + int initialized; + +#if defined(HAVE_WIN32_THREADS) && \ + defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) + void *threadHandle; + void *waitHandle; +#endif + +#ifdef LIBXML_THREAD_ENABLED + unsigned localRngState[2]; +#endif + +#define XML_OP XML_DECLARE_MEMBER +XML_GLOBALS_ALLOC +XML_GLOBALS_ERROR +XML_GLOBALS_IO +XML_GLOBALS_PARSER +XML_GLOBALS_TREE +#undef XML_OP +}; + +static int parserInitialized; + /* * Mutex to protect "ForNewThreads" variables */ -static xmlMutexPtr xmlThrDefMutex = NULL; +static xmlMutex xmlThrDefMutex; -/** - * xmlInitGlobals: - * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. +#ifdef LIBXML_THREAD_ENABLED + +/* + * On Darwin, thread-local storage destructors seem to be run before + * pthread thread-specific data destructors. This causes ASan to + * report a use-after-free. * - * Additional initialisation for multi-threading + * On Windows, we can't use TLS in static builds. The RegisterWait + * callback would run after TLS was deallocated. */ -void xmlInitGlobals(void) -{ - if (xmlThrDefMutex == NULL) - xmlThrDefMutex = xmlNewMutex(); -} +#if defined(XML_THREAD_LOCAL) && \ + !defined(__APPLE__) && \ + (!defined(HAVE_WIN32_THREADS) || \ + !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) +#define USE_TLS +#endif + +#ifdef USE_TLS +static XML_THREAD_LOCAL xmlGlobalState globalState; +#endif + +#ifdef HAVE_POSIX_THREADS + +/* + * Weak symbol hack, see threads.c + */ +#if defined(__GNUC__) && \ + defined(__GLIBC__) && \ + __GLIBC__ * 100 + __GLIBC_MINOR__ < 234 + +#pragma weak pthread_getspecific +#pragma weak pthread_setspecific +#pragma weak pthread_key_create +#pragma weak pthread_key_delete +#pragma weak pthread_equal +#pragma weak pthread_self + +#define XML_PTHREAD_WEAK + +static int libxml_is_threaded = -1; + +#endif + +/* + * On POSIX, we need thread-specific data even with thread-local storage + * to destroy indirect references from global state (xmlLastError) at + * thread exit. + */ +static pthread_key_t globalkey; +static pthread_t mainthread; + +#elif defined HAVE_WIN32_THREADS + +#ifndef USE_TLS +static DWORD globalkey = TLS_OUT_OF_INDEXES; +#endif +static DWORD mainthread; + +#endif /* HAVE_WIN32_THREADS */ + +static void +xmlFreeGlobalState(void *state); + +#endif /* LIBXML_THREAD_ENABLED */ /************************************************************************ * * @@ -57,22 +167,14 @@ void xmlInitGlobals(void) * * ************************************************************************/ +#ifdef LIBXML_THREAD_ENABLED +static unsigned xmlMainThreadRngState[2]; +#endif + /* * 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 @@ -131,50 +233,12 @@ xmlPosixStrdup(const char *cur) { * Returns the copy of the string or NULL in case of error */ xmlStrdupFunc xmlMemStrdup = xmlPosixStrdup; -#endif /* DEBUG_MEMORY_LOCATION || DEBUG_MEMORY */ - -#include -#include -#include - -#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: * + * DEPRECATED: Don't use. + * * Global setting, default allocation policy for buffers, default is * XML_BUFFER_ALLOC_EXACT */ @@ -183,6 +247,8 @@ static xmlBufferAllocationScheme xmlBufferAllocSchemeThrDef = XML_BUFFER_ALLOC_E /** * xmlDefaultBufferSize: * + * DEPRECATED: Don't use. + * * Global setting, default buffer size. Default value is BASE_BUFFER_SIZE */ int xmlDefaultBufferSize = BASE_BUFFER_SIZE; @@ -197,19 +263,22 @@ static int xmlDefaultBufferSizeThrDef = BASE_BUFFER_SIZE; * * Global setting, DEPRECATED. */ -int oldXMLWDcompatibility = 0; /* DEPRECATED */ +const int oldXMLWDcompatibility = 0; /* DEPRECATED */ /** * xmlParserDebugEntities: * + * DEPRECATED: Don't use + * * Global setting, asking the parser to print out debugging information. * while handling entities. * Disabled by default */ -int xmlParserDebugEntities = 0; -static int xmlParserDebugEntitiesThrDef = 0; +const int xmlParserDebugEntities = 0; /** * xmlDoValidityCheckingDefaultValue: * + * DEPRECATED: Use the modern options API with XML_PARSE_DTDVALID. + * * Global setting, indicate that the parser should work in validating mode. * Disabled by default. */ @@ -218,7 +287,9 @@ static int xmlDoValidityCheckingDefaultValueThrDef = 0; /** * xmlGetWarningsDefaultValue: * - * Global setting, indicate that the parser should provide warnings. + * DEPRECATED: Use the modern options API with XML_PARSE_NOWARNING. + * + * Global setting, indicate that the DTD validation should provide warnings. * Activated by default. */ int xmlGetWarningsDefaultValue = 1; @@ -226,6 +297,8 @@ static int xmlGetWarningsDefaultValueThrDef = 1; /** * xmlLoadExtDtdDefaultValue: * + * DEPRECATED: Use the modern options API with XML_PARSE_DTDLOAD. + * * Global setting, indicate that the parser should load DTD while not * validating. * Disabled by default. @@ -235,6 +308,8 @@ static int xmlLoadExtDtdDefaultValueThrDef = 0; /** * xmlPedanticParserDefaultValue: * + * DEPRECATED: Use the modern options API with XML_PARSE_PEDANTIC. + * * Global setting, indicate that the parser be pedantic * Disabled by default. */ @@ -243,6 +318,8 @@ static int xmlPedanticParserDefaultValueThrDef = 0; /** * xmlLineNumbersDefaultValue: * + * DEPRECATED: The modern options API always enables line numbers. + * * 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 @@ -253,6 +330,8 @@ static int xmlLineNumbersDefaultValueThrDef = 0; /** * xmlKeepBlanksDefaultValue: * + * DEPRECATED: Use the modern options API with XML_PARSE_NOBLANKS. + * * 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 @@ -264,6 +343,8 @@ static int xmlKeepBlanksDefaultValueThrDef = 1; /** * xmlSubstituteEntitiesDefaultValue: * + * DEPRECATED: Use the modern options API with XML_PARSE_NOENT. + * * 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 @@ -273,26 +354,38 @@ static int xmlKeepBlanksDefaultValueThrDef = 1; int xmlSubstituteEntitiesDefaultValue = 0; static int xmlSubstituteEntitiesDefaultValueThrDef = 0; +/** + * xmlRegisterNodeDefaultValue: + * + * DEPRECATED: Don't use + */ xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL; static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL; + +/** + * xmlDeregisterNodeDefaultValue: + * + * DEPRECATED: Don't use + */ xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL; static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL; +/** + * xmlParserInputBufferCreateFilenameValue: + * + * DEPRECATED: Don't use + */ xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue = NULL; static xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValueThrDef = NULL; +/** + * xmlOutputBufferCreateFilenameValue: + * + * DEPRECATED: Don't use + */ 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: * @@ -323,6 +416,7 @@ void *xmlStructuredErrorContext = NULL; static void *xmlStructuredErrorContextThrDef = NULL; xmlError xmlLastError; +#ifdef LIBXML_OUTPUT_ENABLED /* * output defaults */ @@ -353,14 +447,18 @@ static const char *xmlTreeIndentStringThrDef = " "; */ int xmlSaveNoEmptyTags = 0; static int xmlSaveNoEmptyTagsThrDef = 0; +#endif /* LIBXML_OUTPUT_ENABLED */ #ifdef LIBXML_SAX1_ENABLED /** * xmlDefaultSAXHandler: * + * DEPRECATED: This handler is unused and will be removed from future + * versions. + * * Default SAX version1 handler for XML, builds the DOM tree */ -xmlSAXHandlerV1 xmlDefaultSAXHandler = { +const xmlSAXHandlerV1 xmlDefaultSAXHandler = { xmlSAX2InternalSubset, xmlSAX2IsStandalone, xmlSAX2HasInternalSubset, @@ -388,30 +486,35 @@ xmlSAXHandlerV1 xmlDefaultSAXHandler = { xmlSAX2GetParameterEntity, xmlSAX2CDataBlock, xmlSAX2ExternalSubset, - 0, + 1, }; #endif /* LIBXML_SAX1_ENABLED */ /** * xmlDefaultSAXLocator: * + * DEPRECATED: Don't use + * * The default SAX Locator * { getPublicId, getSystemId, getLineNumber, getColumnNumber} */ -xmlSAXLocator xmlDefaultSAXLocator = { +const xmlSAXLocator xmlDefaultSAXLocator = { xmlSAX2GetPublicId, xmlSAX2GetSystemId, xmlSAX2GetLineNumber, xmlSAX2GetColumnNumber }; -#ifdef LIBXML_HTML_ENABLED +#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_SAX1_ENABLED) /** * htmlDefaultSAXHandler: * + * DEPRECATED: This handler is unused and will be removed from future + * versions. + * * Default old SAX v1 handler for HTML, builds the DOM tree */ -xmlSAXHandlerV1 htmlDefaultSAXHandler = { +const xmlSAXHandlerV1 htmlDefaultSAXHandler = { xmlSAX2InternalSubset, NULL, NULL, @@ -436,644 +539,700 @@ xmlSAXHandlerV1 htmlDefaultSAXHandler = { xmlParserWarning, xmlParserError, xmlParserError, - xmlSAX2GetParameterEntity, + NULL, xmlSAX2CDataBlock, NULL, - 0, + 1, }; #endif /* LIBXML_HTML_ENABLED */ +/************************************************************************ + * * + * Per thread global state handling * + * * + ************************************************************************/ + /** - * xmlInitializeGlobalState: - * @gs: a pointer to a newly allocated global state + * xmlInitGlobals: * - * xmlInitializeGlobalState() initialize a global state with all the - * default values of the library. + * DEPRECATED: Alias for xmlInitParser. */ -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); +void xmlInitGlobals(void) { + xmlInitParser(); +} -#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_LEGACY_ENABLED) && defined(LIBXML_SAX1_ENABLED) - inithtmlDefaultSAXHandler(&gs->htmlDefaultSAXHandler); +/** + * xmlInitGlobalsInternal: + * + * Additional initialisation for multi-threading + */ +void xmlInitGlobalsInternal(void) { + xmlInitMutex(&xmlThrDefMutex); + +#ifdef HAVE_POSIX_THREADS +#ifdef XML_PTHREAD_WEAK + if (libxml_is_threaded == -1) + libxml_is_threaded = + (pthread_getspecific != NULL) && + (pthread_setspecific != NULL) && + (pthread_key_create != NULL) && + (pthread_key_delete != NULL) && + /* + * pthread_equal can be inline, resuting in -Waddress warnings. + * Let's assume it's available if all the other functions are. + */ + /* (pthread_equal != NULL) && */ + (pthread_self != NULL); + if (libxml_is_threaded == 0) + return; +#endif /* XML_PTHREAD_WEAK */ + pthread_key_create(&globalkey, xmlFreeGlobalState); + mainthread = pthread_self(); +#elif defined(HAVE_WIN32_THREADS) +#ifndef USE_TLS + globalkey = TlsAlloc(); #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; + mainthread = GetCurrentThreadId(); #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); +#ifdef LIBXML_THREAD_ENABLED + xmlMainThreadRngState[0] = xmlGlobalRandom(); + xmlMainThreadRngState[1] = xmlGlobalRandom(); +#endif } /** * xmlCleanupGlobals: * - * DEPRECATED: This function will be made private. Call xmlCleanupParser + * DEPRECATED: This function is a no-op. Call xmlCleanupParser * to free global state but see the warnings there. xmlCleanupParser * should be only called once at program exit. In most cases, you don't * have call cleanup functions at all. + */ +void xmlCleanupGlobals(void) { +} + +/** + * xmlCleanupGlobalsInternal: * * Additional cleanup for multi-threading */ -void xmlCleanupGlobals(void) -{ +void xmlCleanupGlobalsInternal(void) { xmlResetError(&xmlLastError); - if (xmlThrDefMutex != NULL) { - xmlFreeMutex(xmlThrDefMutex); - xmlThrDefMutex = NULL; + xmlCleanupMutex(&xmlThrDefMutex); + +#ifdef HAVE_POSIX_THREADS +#ifdef XML_PTHREAD_WEAK + if (libxml_is_threaded == 0) + return; +#endif /* XML_PTHREAD_WEAK */ + pthread_key_delete(globalkey); +#elif defined(HAVE_WIN32_THREADS) +#ifndef USE_TLS + if (globalkey != TLS_OUT_OF_INDEXES) { + TlsFree(globalkey); + globalkey = TLS_OUT_OF_INDEXES; } - __xmlGlobalInitMutexDestroy(); +#endif +#endif + + parserInitialized = 0; } /** - * DOC_DISABLE : we ignore missing doc for the xmlThrDef functions, - * those are really internal work + * xmlInitializeGlobalState: + * @gs: a pointer to a newly allocated global state + * + * DEPRECATED: No-op. */ 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); +xmlInitializeGlobalState(xmlGlobalStatePtr gs ATTRIBUTE_UNUSED) +{ } /** - * xmlRegisterNodeDefault: - * @func: function pointer to the new RegisterNodeFunc + * xmlGetGlobalState: * - * Registers a callback for node creation + * DEPRECATED * - * Returns the old value of the registration function + * Returns NULL. */ -xmlRegisterNodeFunc -xmlRegisterNodeDefault(xmlRegisterNodeFunc func) +xmlGlobalStatePtr +xmlGetGlobalState(void) { - xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue; - - __xmlRegisterCallbacks = 1; - xmlRegisterNodeDefaultValue = func; - return(old); + return(NULL); } -xmlRegisterNodeFunc -xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func) -{ - xmlRegisterNodeFunc old; - - xmlMutexLock(xmlThrDefMutex); - old = xmlRegisterNodeDefaultValueThrDef; - - __xmlRegisterCallbacks = 1; - xmlRegisterNodeDefaultValueThrDef = func; - xmlMutexUnlock(xmlThrDefMutex); +static int +xmlIsMainThreadInternal(void) { + if (parserInitialized == 0) { + xmlInitParser(); + parserInitialized = 1; + } - return(old); +#ifdef HAVE_POSIX_THREADS +#ifdef XML_PTHREAD_WEAK + if (libxml_is_threaded == 0) + return (1); +#endif + return (pthread_equal(mainthread, pthread_self())); +#elif defined HAVE_WIN32_THREADS + return (mainthread == GetCurrentThreadId()); +#else + return (1); +#endif } /** - * xmlDeregisterNodeDefault: - * @func: function pointer to the new DeregisterNodeFunc + * xmlIsMainThread: + * + * DEPRECATED: Internal function, do not use. * - * Registers a callback for node destruction + * Check whether the current thread is the main thread. * - * Returns the previous value of the deregistration function + * Returns 1 if the current thread is the main thread, 0 otherwise */ -xmlDeregisterNodeFunc -xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func) -{ - xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue; - - __xmlRegisterCallbacks = 1; - xmlDeregisterNodeDefaultValue = func; - return(old); +int +xmlIsMainThread(void) { + return(xmlIsMainThreadInternal()); } -xmlDeregisterNodeFunc -xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func) +#ifdef LIBXML_THREAD_ENABLED + +static void +xmlFreeGlobalState(void *state) { - xmlDeregisterNodeFunc old; + xmlGlobalState *gs = (xmlGlobalState *) state; - xmlMutexLock(xmlThrDefMutex); - old = xmlDeregisterNodeDefaultValueThrDef; + /* + * Free any memory allocated in the thread's xmlLastError. If it + * weren't for this indirect allocation, we wouldn't need + * a destructor with thread-local storage at all! + * + * It would be nice if we could make xmlLastError a special error + * type which uses statically allocated, fixed-size buffers. + * But the xmlError struct is fully public and widely used, + * so changes are dangerous. + */ + xmlResetError(&(gs->gs_xmlLastError)); +#ifndef USE_TLS + free(state); +#endif +} - __xmlRegisterCallbacks = 1; - xmlDeregisterNodeDefaultValueThrDef = func; - xmlMutexUnlock(xmlThrDefMutex); +#if defined(HAVE_WIN32_THREADS) && \ + defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) +static void WINAPI +xmlGlobalStateDtor(void *ctxt, unsigned char timedOut ATTRIBUTE_UNUSED) { + xmlGlobalStatePtr gs = ctxt; - return(old); + UnregisterWait(gs->waitHandle); + CloseHandle(gs->threadHandle); + xmlFreeGlobalState(gs); } -xmlParserInputBufferCreateFilenameFunc -xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) -{ - xmlParserInputBufferCreateFilenameFunc old; +static int +xmlRegisterGlobalStateDtor(xmlGlobalState *gs) { + void *processHandle = GetCurrentProcess(); + void *threadHandle; + void *waitHandle; - xmlMutexLock(xmlThrDefMutex); - old = xmlParserInputBufferCreateFilenameValueThrDef; - if (old == NULL) { - old = __xmlParserInputBufferCreateFilename; - } + if (DuplicateHandle(processHandle, GetCurrentThread(), processHandle, + &threadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) { + return(-1); + } - xmlParserInputBufferCreateFilenameValueThrDef = func; - xmlMutexUnlock(xmlThrDefMutex); + if (RegisterWaitForSingleObject(&waitHandle, threadHandle, + xmlGlobalStateDtor, gs, INFINITE, WT_EXECUTEONLYONCE) == 0) { + CloseHandle(threadHandle); + return(-1); + } - return(old); + gs->threadHandle = threadHandle; + gs->waitHandle = waitHandle; + return(0); } +#endif /* LIBXML_STATIC */ -xmlOutputBufferCreateFilenameFunc -xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) -{ - xmlOutputBufferCreateFilenameFunc old; +static void +xmlInitGlobalState(xmlGlobalStatePtr gs) { + xmlMutexLock(&xmlThrDefMutex); - xmlMutexLock(xmlThrDefMutex); - old = xmlOutputBufferCreateFilenameValueThrDef; +#ifdef LIBXML_THREAD_ENABLED + gs->localRngState[0] = xmlGlobalRandom(); + gs->localRngState[1] = xmlGlobalRandom(); +#endif + + gs->gs_xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef; + gs->gs_xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef; + gs->gs_xmlDoValidityCheckingDefaultValue = + xmlDoValidityCheckingDefaultValueThrDef; +#ifdef LIBXML_THREAD_ALLOC_ENABLED + gs->gs_xmlFree = free; + gs->gs_xmlMalloc = malloc; + gs->gs_xmlMallocAtomic = malloc; + gs->gs_xmlRealloc = realloc; + gs->gs_xmlMemStrdup = xmlPosixStrdup; +#endif + gs->gs_xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef; #ifdef LIBXML_OUTPUT_ENABLED - if (old == NULL) { - old = __xmlOutputBufferCreateFilename; - } + gs->gs_xmlIndentTreeOutput = xmlIndentTreeOutputThrDef; + gs->gs_xmlTreeIndentString = xmlTreeIndentStringThrDef; + gs->gs_xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef; #endif - xmlOutputBufferCreateFilenameValueThrDef = func; - xmlMutexUnlock(xmlThrDefMutex); + gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef; + gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef; + gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef; + gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef; + gs->gs_xmlSubstituteEntitiesDefaultValue = + xmlSubstituteEntitiesDefaultValueThrDef; - return(old); + gs->gs_xmlGenericError = xmlGenericErrorThrDef; + gs->gs_xmlStructuredError = xmlStructuredErrorThrDef; + gs->gs_xmlGenericErrorContext = xmlGenericErrorContextThrDef; + gs->gs_xmlStructuredErrorContext = xmlStructuredErrorContextThrDef; + gs->gs_xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef; + gs->gs_xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef; + + gs->gs_xmlParserInputBufferCreateFilenameValue = + xmlParserInputBufferCreateFilenameValueThrDef; + gs->gs_xmlOutputBufferCreateFilenameValue = + xmlOutputBufferCreateFilenameValueThrDef; + memset(&gs->gs_xmlLastError, 0, sizeof(xmlError)); + + xmlMutexUnlock(&xmlThrDefMutex); + +#ifdef HAVE_POSIX_THREADS + pthread_setspecific(globalkey, gs); +#elif defined HAVE_WIN32_THREADS +#ifndef USE_TLS + TlsSetValue(globalkey, gs); +#endif +#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) + xmlRegisterGlobalStateDtor(gs); +#endif +#endif + + gs->initialized = 1; } -#ifdef LIBXML_HTML_ENABLED -#undef htmlDefaultSAXHandler -xmlSAXHandlerV1 * -__htmlDefaultSAXHandler(void) { - if (IS_MAIN_THREAD) - return (&htmlDefaultSAXHandler); - else - return (&xmlGetGlobalState()->htmlDefaultSAXHandler); +#ifndef USE_TLS +/** + * 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(int allowFailure) +{ + xmlGlobalState *gs; + + gs = malloc(sizeof(xmlGlobalState)); + if (gs == NULL) { + if (allowFailure) + return(NULL); + + /* + * If an application didn't call xmlCheckThreadLocalStorage to make + * sure that global state could be allocated, it's too late to + * handle the error. + */ + fprintf(stderr, "libxml2: Failed to allocate globals for thread\n" + "libxml2: See xmlCheckThreadLocalStorage\n"); + abort(); + } + + memset(gs, 0, sizeof(xmlGlobalState)); + xmlInitGlobalState(gs); + return (gs); } #endif -#undef xmlLastError -xmlError * -__xmlLastError(void) { - if (IS_MAIN_THREAD) - return (&xmlLastError); - else - return (&xmlGetGlobalState()->xmlLastError); +static xmlGlobalStatePtr +xmlGetThreadLocalStorage(int allowFailure) { + xmlGlobalState *gs; + + (void) allowFailure; + +#ifdef USE_TLS + gs = &globalState; + if (gs->initialized == 0) + xmlInitGlobalState(gs); +#elif defined(HAVE_POSIX_THREADS) + gs = (xmlGlobalState *) pthread_getspecific(globalkey); + if (gs == NULL) + gs = xmlNewGlobalState(allowFailure); +#elif defined(HAVE_WIN32_THREADS) + gs = (xmlGlobalState *) TlsGetValue(globalkey); + if (gs == NULL) + gs = xmlNewGlobalState(allowFailure); +#else + gs = NULL; +#endif + + return(gs); } -/* - * 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 :-) +/* Define thread-local storage accessors with macro magic */ + +#define XML_DEFINE_GLOBAL_WRAPPER(name, type, attrs) \ + type *__vtklibxml2_##name(void) { \ + if (IS_MAIN_THREAD) \ + return (&name); \ + else \ + return (&xmlGetThreadLocalStorage(0)->gs_##name); \ + } + +#define XML_OP XML_DEFINE_GLOBAL_WRAPPER +XML_GLOBALS_ALLOC +XML_GLOBALS_ERROR +XML_GLOBALS_IO +XML_GLOBALS_PARSER +XML_GLOBALS_TREE +#undef XML_OP + +#ifdef LIBXML_THREAD_ENABLED +/** + * xmlGetLocalRngState: + * + * Returns the local RNG state. */ -#if defined(LIBXML_THREAD_ALLOC_ENABLED) && defined(LIBXML_THREAD_ENABLED) -#undef xmlMalloc -xmlMallocFunc * -__xmlMalloc(void){ +unsigned * +xmlGetLocalRngState(void) { if (IS_MAIN_THREAD) - return (&xmlMalloc); + return(xmlMainThreadRngState); else - return (&xmlGetGlobalState()->xmlMalloc); + return(xmlGetThreadLocalStorage(0)->localRngState); } +#endif -#undef xmlMallocAtomic -xmlMallocFunc * -__xmlMallocAtomic(void){ - if (IS_MAIN_THREAD) - return (&xmlMallocAtomic); - else - return (&xmlGetGlobalState()->xmlMallocAtomic); +/* For backward compatibility */ + +const char *const * +__xmlParserVersion(void) { + return &xmlParserVersion; } -#undef xmlRealloc -xmlReallocFunc * -__xmlRealloc(void){ - if (IS_MAIN_THREAD) - return (&xmlRealloc); - else - return (&xmlGetGlobalState()->xmlRealloc); +const int * +__oldXMLWDcompatibility(void) { + return &oldXMLWDcompatibility; } -#undef xmlFree -xmlFreeFunc * -__xmlFree(void){ - if (IS_MAIN_THREAD) - return (&xmlFree); - else - return (&xmlGetGlobalState()->xmlFree); +const int * +__xmlParserDebugEntities(void) { + return &xmlParserDebugEntities; } -xmlStrdupFunc * -__xmlMemStrdup(void){ - if (IS_MAIN_THREAD) - return (&xmlMemStrdup); - else - return (&xmlGetGlobalState()->xmlMemStrdup); +const xmlSAXLocator * +__xmlDefaultSAXLocator(void) { + return &xmlDefaultSAXLocator; } -#endif +#ifdef LIBXML_SAX1_ENABLED +const xmlSAXHandlerV1 * +__xmlDefaultSAXHandler(void) { + return &xmlDefaultSAXHandler; +} -/* - * Everything starting from the line below is - * Automatically generated by build_glob.py. - * Do not modify the previous line. +#ifdef LIBXML_HTML_ENABLED +const xmlSAXHandlerV1 * +__htmlDefaultSAXHandler(void) { + return &htmlDefaultSAXHandler; +} +#endif /* LIBXML_HTML_ENABLED */ +#endif /* LIBXML_SAX1_ENABLED */ + +#endif /* LIBXML_THREAD_ENABLED */ + +/** + * xmlCheckThreadLocalStorage: + * + * Check whether thread-local storage could be allocated. + * + * In cross-platform code running in multithreaded environments, this + * function should be called once in each thread before calling other + * library functions to make sure that thread-local storage was + * allocated properly. + * + * Returns 0 on success or -1 if a memory allocation failed. A failed + * allocation signals a typically fatal and irrecoverable out-of-memory + * situation. Don't call any library functions in this case. + * + * This function never fails if the library is compiled with support + * for thread-local storage. + * + * This function never fails for the "main" thread which is the first + * thread calling xmlInitParser. + * + * Available since v2.12.0. */ +int +xmlCheckThreadLocalStorage(void) { +#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS) + if ((!xmlIsMainThreadInternal()) && (xmlGetThreadLocalStorage(1) == NULL)) + return(-1); +#endif + return(0); +} +/** DOC_DISABLE */ -#undef oldXMLWDcompatibility -int * -__oldXMLWDcompatibility(void) { - if (IS_MAIN_THREAD) - return (&oldXMLWDcompatibility); - else - return (&xmlGetGlobalState()->oldXMLWDcompatibility); +/** + * 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 + */ +#if defined(HAVE_WIN32_THREADS) && \ + (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) +#if defined(LIBXML_STATIC_FOR_DLL) +int +xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason, + ATTRIBUTE_UNUSED void *lpvReserved) +#else +/* declare to avoid "no previous prototype for 'DllMain'" warning */ +/* Note that we do NOT want to include this function declaration in + a public header because it's meant to be called by Windows itself, + not a program that uses this library. This also has to be exported. */ + +XMLPUBFUN BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); + +BOOL WINAPI +DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason, + ATTRIBUTE_UNUSED LPVOID lpvReserved) +#endif +{ + switch (fdwReason) { + case DLL_THREAD_DETACH: +#ifdef USE_TLS + xmlFreeGlobalState(&globalState); +#else + if (globalkey != TLS_OUT_OF_INDEXES) { + xmlGlobalState *globalval; + + globalval = (xmlGlobalState *) TlsGetValue(globalkey); + if (globalval) { + xmlFreeGlobalState(globalval); + TlsSetValue(globalkey, NULL); + } + } +#endif + break; + } + return TRUE; } +#endif -#undef xmlBufferAllocScheme -xmlBufferAllocationScheme * -__xmlBufferAllocScheme(void) { - if (IS_MAIN_THREAD) - return (&xmlBufferAllocScheme); +void +xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { + xmlMutexLock(&xmlThrDefMutex); + xmlGenericErrorContextThrDef = ctx; + if (handler != NULL) + xmlGenericErrorThrDef = handler; else - return (&xmlGetGlobalState()->xmlBufferAllocScheme); + xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc; + xmlMutexUnlock(&xmlThrDefMutex); +} + +void +xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { + xmlMutexLock(&xmlThrDefMutex); + xmlStructuredErrorContextThrDef = ctx; + xmlStructuredErrorThrDef = handler; + xmlMutexUnlock(&xmlThrDefMutex); } + xmlBufferAllocationScheme xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v) { xmlBufferAllocationScheme ret; - xmlMutexLock(xmlThrDefMutex); + xmlMutexLock(&xmlThrDefMutex); ret = xmlBufferAllocSchemeThrDef; xmlBufferAllocSchemeThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlDefaultBufferSizeThrDef; xmlDefaultBufferSizeThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlDoValidityCheckingDefaultValueThrDef; xmlDoValidityCheckingDefaultValueThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlGetWarningsDefaultValueThrDef; xmlGetWarningsDefaultValueThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + xmlMutexUnlock(&xmlThrDefMutex); return ret; } -#undef xmlIndentTreeOutput -int * -__xmlIndentTreeOutput(void) { - if (IS_MAIN_THREAD) - return (&xmlIndentTreeOutput); - else - return (&xmlGetGlobalState()->xmlIndentTreeOutput); -} +#ifdef LIBXML_OUTPUT_ENABLED int xmlThrDefIndentTreeOutput(int v) { int ret; - xmlMutexLock(xmlThrDefMutex); + xmlMutexLock(&xmlThrDefMutex); ret = xmlIndentTreeOutputThrDef; xmlIndentTreeOutputThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlTreeIndentStringThrDef; xmlTreeIndentStringThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + xmlMutexUnlock(&xmlThrDefMutex); return ret; } -#undef xmlKeepBlanksDefaultValue -int * -__xmlKeepBlanksDefaultValue(void) { - if (IS_MAIN_THREAD) - return (&xmlKeepBlanksDefaultValue); - else - return (&xmlGetGlobalState()->xmlKeepBlanksDefaultValue); +int xmlThrDefSaveNoEmptyTags(int v) { + int ret; + xmlMutexLock(&xmlThrDefMutex); + ret = xmlSaveNoEmptyTagsThrDef; + xmlSaveNoEmptyTagsThrDef = v; + xmlMutexUnlock(&xmlThrDefMutex); + return ret; } +#endif + int xmlThrDefKeepBlanksDefaultValue(int v) { int ret; - xmlMutexLock(xmlThrDefMutex); + xmlMutexLock(&xmlThrDefMutex); ret = xmlKeepBlanksDefaultValueThrDef; xmlKeepBlanksDefaultValueThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlLineNumbersDefaultValueThrDef; xmlLineNumbersDefaultValueThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + 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); + 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); + xmlMutexUnlock(&xmlThrDefMutex); return ret; } -#undef xmlParserVersion -const char * * -__xmlParserVersion(void) { - if (IS_MAIN_THREAD) - return (&xmlParserVersion); - else - return (&xmlGetGlobalState()->xmlParserVersion); +int xmlThrDefParserDebugEntities(int v ATTRIBUTE_UNUSED) { + return(xmlParserDebugEntities); } -#undef xmlPedanticParserDefaultValue -int * -__xmlPedanticParserDefaultValue(void) { - if (IS_MAIN_THREAD) - return (&xmlPedanticParserDefaultValue); - else - return (&xmlGetGlobalState()->xmlPedanticParserDefaultValue); -} int xmlThrDefPedanticParserDefaultValue(int v) { int ret; - xmlMutexLock(xmlThrDefMutex); + 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); + 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); + xmlMutexLock(&xmlThrDefMutex); ret = xmlSubstituteEntitiesDefaultValueThrDef; xmlSubstituteEntitiesDefaultValueThrDef = v; - xmlMutexUnlock(xmlThrDefMutex); + xmlMutexUnlock(&xmlThrDefMutex); return ret; } -#undef xmlRegisterNodeDefaultValue -xmlRegisterNodeFunc * -__xmlRegisterNodeDefaultValue(void) { - if (IS_MAIN_THREAD) - return (&xmlRegisterNodeDefaultValue); - else - return (&xmlGetGlobalState()->xmlRegisterNodeDefaultValue); +xmlRegisterNodeFunc +xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func) +{ + xmlRegisterNodeFunc old; + + xmlMutexLock(&xmlThrDefMutex); + old = xmlRegisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlRegisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(&xmlThrDefMutex); + + return(old); } -#undef xmlDeregisterNodeDefaultValue -xmlDeregisterNodeFunc * -__xmlDeregisterNodeDefaultValue(void) { - if (IS_MAIN_THREAD) - return (&xmlDeregisterNodeDefaultValue); - else - return (&xmlGetGlobalState()->xmlDeregisterNodeDefaultValue); +xmlDeregisterNodeFunc +xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func) +{ + xmlDeregisterNodeFunc old; + + xmlMutexLock(&xmlThrDefMutex); + old = xmlDeregisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlDeregisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(&xmlThrDefMutex); + + return(old); } -#undef xmlParserInputBufferCreateFilenameValue -xmlParserInputBufferCreateFilenameFunc * -__xmlParserInputBufferCreateFilenameValue(void) { - if (IS_MAIN_THREAD) - return (&xmlParserInputBufferCreateFilenameValue); - else - return (&xmlGetGlobalState()->xmlParserInputBufferCreateFilenameValue); +xmlParserInputBufferCreateFilenameFunc +xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) +{ + xmlParserInputBufferCreateFilenameFunc old; + + xmlMutexLock(&xmlThrDefMutex); + old = xmlParserInputBufferCreateFilenameValueThrDef; + if (old == NULL) { + old = __xmlParserInputBufferCreateFilename; + } + + xmlParserInputBufferCreateFilenameValueThrDef = func; + xmlMutexUnlock(&xmlThrDefMutex); + + return(old); } -#undef xmlOutputBufferCreateFilenameValue -xmlOutputBufferCreateFilenameFunc * -__xmlOutputBufferCreateFilenameValue(void) { - if (IS_MAIN_THREAD) - return (&xmlOutputBufferCreateFilenameValue); - else - return (&xmlGetGlobalState()->xmlOutputBufferCreateFilenameValue); +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); } +/** DOC_ENABLE */ + diff --git a/hash.c b/hash.c index 894174fb99a..6af8527eafb 100644 --- a/hash.c +++ b/hash.c @@ -1,200 +1,197 @@ /* - * hash.c: chained hash tables + * hash.c: hash tables * - * Reference: Your favorite introductory book on algorithms + * Hash table with open addressing, linear probing and + * Robin Hood reordering. * - * 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 - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND - * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. - * - * Author: breese@users.sourceforge.net + * See Copyright for the status of this software. */ #define IN_LIBXML #include "libxml.h" #include -#include -#include - -/* - * 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(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) -#define HASH_RANDOMIZATION -#endif +#include #include #include +#include #include -#include -#include +#include + +#include "private/dict.h" -#define MAX_HASH_LEN 8 +#ifndef SIZE_MAX + #define SIZE_MAX ((size_t) -1) +#endif -/* #define DEBUG_GROW */ +#define MAX_FILL_NUM 7 +#define MAX_FILL_DENOM 8 +#define MIN_HASH_SIZE 8 +#define MAX_HASH_SIZE (1u << 31) /* * 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; +typedef struct { + unsigned hashValue; /* 0 means unoccupied, occupied entries have the + * MAX_HASH_SIZE bit set to 1 */ + xmlChar *key; + xmlChar *key2; /* TODO: Don't allocate possibly empty keys */ + xmlChar *key3; void *payload; - int valid; -}; +} xmlHashEntry; /* * The entire hash table */ struct _xmlHashTable { - struct _xmlHashEntry *table; - int size; - int nbElems; + xmlHashEntry *table; + unsigned size; /* power of two */ + unsigned nbElems; xmlDictPtr dict; -#ifdef HASH_RANDOMIZATION - int random_seed; -#endif + unsigned randomSeed; }; -/* - * xmlHashComputeKey: - * Calculate the hash key - */ -#ifdef __clang__ -ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") -#endif -static unsigned long -xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, - const xmlChar *name2, const xmlChar *name3) { - unsigned long value = 0L; - unsigned long 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) + ch); - } +static int +xmlHashGrow(xmlHashTablePtr hash, unsigned size); + +ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xmlHashValue(unsigned seed, const xmlChar *key, const xmlChar *key2, + const xmlChar *key3, size_t *lengths) { + unsigned h1, h2; + size_t i; + + HASH_INIT(h1, h2, seed); + + for (i = 0; key[i] != 0; i++) { + HASH_UPDATE(h1, h2, key[i]); } - value = value ^ ((value << 5) + (value >> 3)); - if (name2 != NULL) { - while ((ch = *name2++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } + if (lengths) + lengths[0] = i; + + HASH_UPDATE(h1, h2, 0); + + if (key2 != NULL) { + for (i = 0; key2[i] != 0; i++) { + HASH_UPDATE(h1, h2, key2[i]); + } + if (lengths) + lengths[1] = i; } - value = value ^ ((value << 5) + (value >> 3)); - if (name3 != NULL) { - while ((ch = *name3++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } + + HASH_UPDATE(h1, h2, 0); + + if (key3 != NULL) { + for (i = 0; key3[i] != 0; i++) { + HASH_UPDATE(h1, h2, key3[i]); + } + if (lengths) + lengths[2] = i; } - return (value % table->size); + + HASH_FINISH(h1, h2); + + return(h2); } -#ifdef __clang__ -ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") -#endif -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; - unsigned long ch; - -#ifdef HASH_RANDOMIZATION - value = table->random_seed; -#endif - if (prefix != NULL) - value += 30 * (*prefix); - else - value += 30 * (*name); +ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xmlHashQNameValue(unsigned seed, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned h1, h2, ch; + + HASH_INIT(h1, h2, seed); if (prefix != NULL) { - while ((ch = *prefix++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } - value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + while ((ch = *prefix++) != 0) { + HASH_UPDATE(h1, h2, ch); + } + HASH_UPDATE(h1, h2, ':'); } if (name != NULL) { - while ((ch = *name++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } + while ((ch = *name++) != 0) { + HASH_UPDATE(h1, h2, ch); + } } - value = value ^ ((value << 5) + (value >> 3)); + HASH_UPDATE(h1, h2, 0); if (prefix2 != NULL) { - while ((ch = *prefix2++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } - value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + while ((ch = *prefix2++) != 0) { + HASH_UPDATE(h1, h2, ch); + } + HASH_UPDATE(h1, h2, ':'); } if (name2 != NULL) { - while ((ch = *name2++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } + while ((ch = *name2++) != 0) { + HASH_UPDATE(h1, h2, ch); + } } - value = value ^ ((value << 5) + (value >> 3)); + HASH_UPDATE(h1, h2, 0); if (prefix3 != NULL) { - while ((ch = *prefix3++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } - value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + while ((ch = *prefix3++) != 0) { + HASH_UPDATE(h1, h2, ch); + } + HASH_UPDATE(h1, h2, ':'); } if (name3 != NULL) { - while ((ch = *name3++) != 0) { - value = value ^ ((value << 5) + (value >> 3) + ch); - } + while ((ch = *name3++) != 0) { + HASH_UPDATE(h1, h2, ch); + } } - return (value % table->size); + + HASH_FINISH(h1, h2); + + return(h2); } /** * xmlHashCreate: - * @size: the size of the hash table + * @size: initial size of the hash table * - * Create a new xmlHashTablePtr. + * Create a new hash table. Set size to zero if the number of entries + * can't be estimated. * - * Returns the newly created object, or NULL if an error occurred. + * Returns the newly created object, or NULL if a memory allocation failed. */ 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 - table->random_seed = __xmlRandom(); + xmlHashTablePtr hash; + + xmlInitParser(); + + hash = xmlMalloc(sizeof(*hash)); + if (hash == NULL) + return(NULL); + hash->dict = NULL; + hash->size = 0; + hash->table = NULL; + hash->nbElems = 0; + hash->randomSeed = xmlRandom(); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + hash->randomSeed = 0; #endif - return(table); + + /* + * Unless a larger size is passed, the backing table is created + * lazily with MIN_HASH_SIZE capacity. In practice, there are many + * hash tables which are never filled. + */ + if (size > MIN_HASH_SIZE) { + unsigned newSize = MIN_HASH_SIZE * 2; + + while ((newSize < (unsigned) size) && (newSize < MAX_HASH_SIZE)) + newSize *= 2; + + if (xmlHashGrow(hash, newSize) != 0) { + xmlFree(hash); + return(NULL); } - xmlFree(table); } - return(NULL); + + return(hash); } /** @@ -202,938 +199,1147 @@ xmlHashCreate(int size) { * @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 + * Create a new hash table backed by a dictionary. This can reduce + * resource usage considerably if most keys passed to API functions + * originate from this dictionary. * - * Returns the newly created object, or NULL if an error occurred. + * Returns the newly created object, or NULL if a memory allocation failed. */ xmlHashTablePtr xmlHashCreateDict(int size, xmlDictPtr dict) { - xmlHashTablePtr table; + xmlHashTablePtr hash; + + hash = xmlHashCreate(size); + if (hash != NULL) { + hash->dict = dict; + xmlDictReference(dict); + } + return(hash); +} + +/** + * xmlHashFree: + * @hash: hash table + * @dealloc: deallocator function or NULL + * + * Free the hash and its contents. The payload is deallocated with + * @dealloc if provided. + */ +void +xmlHashFree(xmlHashTablePtr hash, xmlHashDeallocator dealloc) { + if (hash == NULL) + return; + + if (hash->table) { + const xmlHashEntry *end = &hash->table[hash->size]; + const xmlHashEntry *entry; + + for (entry = hash->table; entry < end; entry++) { + if (entry->hashValue == 0) + continue; + if ((dealloc != NULL) && (entry->payload != NULL)) + dealloc(entry->payload, entry->key); + if (hash->dict == NULL) { + if (entry->key) + xmlFree(entry->key); + if (entry->key2) + xmlFree(entry->key2); + if (entry->key3) + xmlFree(entry->key3); + } + } - table = xmlHashCreate(size); - if (table != NULL) { - table->dict = dict; - xmlDictReference(dict); + xmlFree(hash->table); } - return(table); + + if (hash->dict) + xmlDictFree(hash->dict); + + xmlFree(hash); +} + +/** + * xmlFastStrEqual: + * @s1: string + * @s2: string + * + * Compare two strings for equality, allowing NULL values. + */ +static int +xmlFastStrEqual(const xmlChar *s1, const xmlChar *s2) { + if (s1 == NULL) + return(s2 == NULL); + else + return((s2 != NULL) && + (strcmp((const char *) s1, (const char *) s2) == 0)); +} + +/** + * xmlHashFindEntry: + * @hash: hash table, non-NULL, size > 0 + * @key: first string key, non-NULL + * @key2: second string key + * @key3: third string key + * @hashValue: valid hash value of keys + * @pfound: result of search + * + * Try to find a matching hash table entry. If an entry was found, set + * @found to 1 and return the entry. Otherwise, set @found to 0 and return + * the location where a new entry should be inserted. + */ +ATTRIBUTE_NO_SANITIZE_INTEGER +static xmlHashEntry * +xmlHashFindEntry(const xmlHashTable *hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + unsigned hashValue, int *pfound) { + xmlHashEntry *entry; + unsigned mask, pos, displ; + int found = 0; + + mask = hash->size - 1; + pos = hashValue & mask; + entry = &hash->table[pos]; + + if (entry->hashValue != 0) { + /* + * Robin hood hashing: abort if the displacement of the entry + * is smaller than the displacement of the key we look for. + * This also stops at the correct position when inserting. + */ + displ = 0; + hashValue |= MAX_HASH_SIZE; + + do { + if (entry->hashValue == hashValue) { + if (hash->dict) { + if ((entry->key == key) && + (entry->key2 == key2) && + (entry->key3 == key3)) { + found = 1; + break; + } + } + if ((strcmp((const char *) entry->key, + (const char *) key) == 0) && + (xmlFastStrEqual(entry->key2, key2)) && + (xmlFastStrEqual(entry->key3, key3))) { + found = 1; + break; + } + } + + displ++; + pos++; + entry++; + if ((pos & mask) == 0) + entry = hash->table; + } while ((entry->hashValue != 0) && + (((pos - entry->hashValue) & mask) >= displ)); + } + + *pfound = found; + return(entry); } /** * xmlHashGrow: - * @table: the hash table - * @size: the new size of the hash table + * @hash: hash table + * @size: new size of the hash table * - * resize the hash table + * Resize the hash table. * - * Returns 0 in case of success, -1 in case of failure + * Returns 0 in case of success, -1 if a memory allocation failed. */ 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 +xmlHashGrow(xmlHashTablePtr hash, unsigned size) { + const xmlHashEntry *oldentry, *oldend, *end; + xmlHashEntry *table; + unsigned oldsize, i; + /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */ + if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0])) + return(-1); + table = xmlMalloc(size * sizeof(table[0])); if (table == NULL) - return(-1); - if (size < 8) return(-1); - if (size > 8 * 2048) - return(-1); + memset(table, 0, size * sizeof(table[0])); - oldsize = table->size; - oldtable = table->table; - if (oldtable == NULL) - return(-1); + oldsize = hash->size; + if (oldsize == 0) + goto done; - 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; + oldend = &hash->table[oldsize]; + end = &table[size]; + + /* + * Robin Hood sorting order is maintained if we + * + * - compute hash indices with modulo + * - resize by an integer factor + * - start to copy from the beginning of a probe sequence + */ + oldentry = hash->table; + while (oldentry->hashValue != 0) { + if (++oldentry >= oldend) + oldentry = hash->table; } 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 + if (oldentry->hashValue != 0) { + xmlHashEntry *entry = &table[oldentry->hashValue & (size - 1)]; - iter = next; - } + while (entry->hashValue != 0) { + if (++entry >= end) + entry = table; + } + *entry = *oldentry; + } + + if (++oldentry >= oldend) + oldentry = hash->table; } - xmlFree(oldtable); + xmlFree(hash->table); -#ifdef DEBUG_GROW - xmlGenericError(xmlGenericErrorContext, - "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); -#endif +done: + hash->table = table; + hash->size = size; return(0); } /** - * xmlHashFree: - * @table: the hash table - * @f: the deallocator function for items in the hash + * xmlHashUpdateInternal: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @payload: pointer to the payload + * @dealloc: deallocator function for replaced item or NULL + * @update: whether existing entries should be updated * - * Free the hash @table and its contents. The userdata is - * deallocated with @f if provided. + * Internal function to add or update hash entries. */ -void -xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { - int i; - xmlHashEntryPtr iter; - xmlHashEntryPtr next; - int inside_table = 0; - int nbElems; +ATTRIBUTE_NO_SANITIZE_INTEGER +static int +xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + void *payload, xmlHashDeallocator dealloc, int update) { + xmlChar *copy, *copy2, *copy3; + xmlHashEntry *entry = NULL; + size_t lengths[3]; + unsigned hashValue; + int found = 0; + + if ((hash == NULL) || (key == NULL)) + return(-1); - 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); + /* + * Check for an existing entry + */ + hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, lengths); + if (hash->size > 0) + entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found); + if (found) { + if (update) { + if (dealloc) + dealloc(entry->payload, entry->key); + entry->payload = payload; + } + + return(0); + } + + /* + * Grow the hash table if needed + */ + if (hash->nbElems + 1 > hash->size / MAX_FILL_DENOM * MAX_FILL_NUM) { + unsigned newSize, mask, displ, pos; + + if (hash->size == 0) { + newSize = MIN_HASH_SIZE; + } else { + /* This guarantees that nbElems < INT_MAX */ + if (hash->size >= MAX_HASH_SIZE) + return(-1); + newSize = hash->size * 2; + } + if (xmlHashGrow(hash, newSize) != 0) + return(-1); + + /* + * Find new entry + */ + mask = hash->size - 1; + displ = 0; + pos = hashValue & mask; + entry = &hash->table[pos]; + + if (entry->hashValue != 0) { + do { + displ++; + pos++; + entry++; + if ((pos & mask) == 0) + entry = hash->table; + } while ((entry->hashValue != 0) && + ((pos - entry->hashValue) & mask) >= displ); + } + } + + /* + * Copy keys + */ + if (hash->dict != NULL) { + if (xmlDictOwns(hash->dict, key)) { + copy = (xmlChar *) key; + } else { + copy = (xmlChar *) xmlDictLookup(hash->dict, key, -1); + if (copy == NULL) + return(-1); + } + + if ((key2 == NULL) || (xmlDictOwns(hash->dict, key2))) { + copy2 = (xmlChar *) key2; + } else { + copy2 = (xmlChar *) xmlDictLookup(hash->dict, key2, -1); + if (copy2 == NULL) + return(-1); + } + if ((key3 == NULL) || (xmlDictOwns(hash->dict, key3))) { + copy3 = (xmlChar *) key3; + } else { + copy3 = (xmlChar *) xmlDictLookup(hash->dict, key3, -1); + if (copy3 == NULL) + return(-1); + } + } else { + copy = xmlMalloc(lengths[0] + 1); + if (copy == NULL) + return(-1); + memcpy(copy, key, lengths[0] + 1); + + if (key2 != NULL) { + copy2 = xmlMalloc(lengths[1] + 1); + if (copy2 == NULL) { + xmlFree(copy); + return(-1); + } + memcpy(copy2, key2, lengths[1] + 1); + } else { + copy2 = NULL; + } + + if (key3 != NULL) { + copy3 = xmlMalloc(lengths[2] + 1); + if (copy3 == NULL) { + xmlFree(copy); + xmlFree(copy2); + return(-1); + } + memcpy(copy3, key3, lengths[2] + 1); + } else { + copy3 = NULL; + } + } + + /* + * Shift the remainder of the probe sequence to the right + */ + if (entry->hashValue != 0) { + const xmlHashEntry *end = &hash->table[hash->size]; + const xmlHashEntry *cur = entry; + + do { + cur++; + if (cur >= end) + cur = hash->table; + } while (cur->hashValue != 0); + + if (cur < entry) { + /* + * If we traversed the end of the buffer, handle the part + * at the start of the buffer. + */ + memmove(&hash->table[1], hash->table, + (char *) cur - (char *) hash->table); + cur = end - 1; + hash->table[0] = *cur; + } + + memmove(&entry[1], entry, (char *) cur - (char *) entry); } - if (table->dict) - xmlDictFree(table->dict); - xmlFree(table); + + /* + * Populate entry + */ + entry->key = copy; + entry->key2 = copy2; + entry->key3 = copy3; + entry->payload = payload; + /* OR with MAX_HASH_SIZE to make sure that the value is non-zero */ + entry->hashValue = hashValue | MAX_HASH_SIZE; + + hash->nbElems++; + + return(1); } /** * xmlHashDefaultDeallocator: - * @entry: the hash table entry - * @name: the entry's name + * @entry: hash table entry + * @key: the entry's string key * * Free a hash table entry with xmlFree. */ void -xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) { +xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) { xmlFree(entry); } /** - * xmlHashAddEntry: - * @table: the hash table - * @name: the name of the userdata - * @userdata: a pointer to the userdata + * xmlHashAdd: + * @hash: hash table + * @key: string key + * @payload: pointer to the payload + * + * Add a hash table entry. If an entry with this key already exists, + * payload will not be updated and 0 is returned. This return value + * can't be distinguished from out-of-memory errors, so this function + * should be used with care. * - * Add the @userdata to the hash @table. This can later be retrieved - * by using the @name. Duplicate names generate errors. + * Available since 2.13.0. * - * Returns 0 the addition succeeded and -1 in case of error. + * Returns 1 on success, 0 if an entry exists and -1 in case of error. */ int -xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) { - return(xmlHashAddEntry3(table, name, NULL, NULL, userdata)); +xmlHashAdd(xmlHashTablePtr hash, const xmlChar *key, void *payload) { + return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0)); } /** - * xmlHashAddEntry2: - * @table: the hash table - * @name: the name of the userdata - * @name2: a second name of the userdata - * @userdata: a pointer to the userdata + * xmlHashAdd2: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @payload: pointer to the payload * - * Add the @userdata to the hash @table. This can later be retrieved - * by using the (@name, @name2) tuple. Duplicate tuples generate errors. + * Add a hash table entry with two strings as key. * - * 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) + * See xmlHashAdd. * - * 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. + * Available since 2.13.0. * - * Returns 0 the addition succeeded and -1 in case of error. + * Returns 1 on success, 0 if an entry exists 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)); +xmlHashAdd2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, void *payload) { + return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0)); } /** - * 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) + * xmlHashAdd3: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @payload: pointer to the payload * - * 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. + * Add a hash table entry with three strings as key. * - * Returns 0 the addition succeeded and -1 in case of error. + * See xmlHashAdd. + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if an entry exists 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)); +xmlHashAdd3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + void *payload) { + return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0)); } /** - * xmlHashLookup: - * @table: the hash table - * @name: the name of the userdata + * xmlHashAddEntry: + * @hash: hash table + * @key: string key + * @payload: pointer to the payload + * + * Add a hash table entry. If an entry with this key already exists, + * payload will not be updated and -1 is returned. This return value + * can't be distinguished from out-of-memory errors, so this function + * should be used with care. * - * Find the userdata specified by the @name. + * NOTE: This function doesn't allow to distinguish malloc failures from + * existing entries. Use xmlHashAdd instead. * - * Returns the pointer to the userdata + * Returns 0 on success and -1 in case of error. */ -void * -xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) { - return(xmlHashLookup3(table, name, NULL, NULL)); +int +xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) { + int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); } /** - * xmlHashLookup2: - * @table: the hash table - * @name: the name of the userdata - * @name2: a second name of the userdata + * xmlHashAddEntry2: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @payload: pointer to the payload + * + * Add a hash table entry with two strings as key. * - * Find the userdata specified by the (@name, @name2) tuple. + * See xmlHashAddEntry. * - * Returns the pointer to the userdata + * Returns 0 on success and -1 in case of error. */ -void * -xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, - const xmlChar *name2) { - return(xmlHashLookup3(table, name, name2, NULL)); +int +xmlHashAddEntry2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, void *payload) { + int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); } /** - * xmlHashQLookup: - * @table: the hash table - * @prefix: the prefix of the userdata - * @name: the name of the userdata + * xmlHashAddEntry3: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @payload: pointer to the payload * - * Find the userdata specified by the QName @prefix:@name/@name. + * Add a hash table entry with three strings as key. * - * Returns the pointer to the userdata + * See xmlHashAddEntry. + * + * Returns 0 on success and -1 in case of error. */ -void * -xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, - const xmlChar *name) { - return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); +int +xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + void *payload) { + int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); } /** - * 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 + * xmlHashUpdateEntry: + * @hash: hash table + * @key: string key + * @payload: pointer to the payload + * @dealloc: deallocator function for replaced item or NULL * - * Find the userdata specified by the QNames tuple + * Add a hash table entry. If an entry with this key already exists, + * the old payload will be freed and updated with the new value. * - * Returns the pointer to the userdata + * Returns 0 in case of success, -1 if a memory allocation failed. */ -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)); +int +xmlHashUpdateEntry(xmlHashTablePtr hash, const xmlChar *key, + void *payload, xmlHashDeallocator dealloc) { + int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, + dealloc, 1); + + if (res == 1) + res = 0; + + return(res); } /** - * 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 + * xmlHashUpdateEntry2: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @payload: pointer to the payload + * @dealloc: deallocator function for replaced item or NULL * - * Add the @userdata to the hash @table. This can later be retrieved - * by using the tuple (@name, @name2, @name3). Duplicate entries generate - * errors. + * Add a hash table entry with two strings as key. * - * Returns 0 the addition succeeded and -1 in case of error. + * See xmlHashUpdateEntry. + * + * Returns 0 on success 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; +xmlHashUpdateEntry2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, void *payload, + xmlHashDeallocator dealloc) { + int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, + dealloc, 1); + if (res == 1) + res = 0; - if (insert != NULL) - insert->next = entry; - - table->nbElems++; - - if (len > MAX_HASH_LEN) - xmlHashGrow(table, MAX_HASH_LEN * table->size); - - return(0); + return(res); } /** * 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. + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @payload: pointer to the payload + * @dealloc: deallocator function for replaced item or NULL + * + * Add a hash table entry with three strings as key. + * + * See xmlHashUpdateEntry. + * + * Returns 0 on success 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); +xmlHashUpdateEntry3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + void *payload, xmlHashDeallocator dealloc) { + int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, + dealloc, 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); - } - } + if (res == 1) + res = 0; - /* - * 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); - } - } - } + return(res); +} - if (insert == NULL) { - entry = &(table->table[key]); - } else { - entry = xmlMalloc(sizeof(xmlHashEntry)); - if (entry == NULL) - return(-1); - } +/** + * xmlHashLookup: + * @hash: hash table + * @key: string key + * + * Find the entry specified by @key. + * + * Returns a pointer to the payload or NULL if no entry was found. + */ +void * +xmlHashLookup(xmlHashTablePtr hash, const xmlChar *key) { + return(xmlHashLookup3(hash, key, NULL, NULL)); +} - 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++; +/** + * xmlHashLookup2: + * @hash: hash table + * @key: first string key + * @key2: second string key + * + * Find the payload specified by the (@key, @key2) tuple. + * + * Returns a pointer to the payload or NULL if no entry was found. + */ +void * +xmlHashLookup2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2) { + return(xmlHashLookup3(hash, key, key2, NULL)); +} +/** + * xmlHashQLookup: + * @hash: hash table + * @prefix: prefix of the string key + * @name: local name of the string key + * + * Find the payload specified by the QName @prefix:@name or @name. + * + * Returns a pointer to the payload or NULL if no entry was found. + */ +void * +xmlHashQLookup(xmlHashTablePtr hash, const xmlChar *prefix, + const xmlChar *name) { + return(xmlHashQLookup3(hash, prefix, name, NULL, NULL, NULL, NULL)); +} - if (insert != NULL) { - insert->next = entry; - } - return(0); +/** + * xmlHashQLookup2: + * @hash: hash table + * @prefix: first prefix + * @name: first local name + * @prefix2: second prefix + * @name2: second local name + * + * Find the payload specified by the QNames tuple. + * + * Returns a pointer to the payload or NULL if no entry was found. + */ +void * +xmlHashQLookup2(xmlHashTablePtr hash, const xmlChar *prefix, + const xmlChar *name, const xmlChar *prefix2, + const xmlChar *name2) { + return(xmlHashQLookup3(hash, prefix, name, prefix2, name2, NULL, NULL)); } /** * 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 + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key * - * Find the userdata specified by the (@name, @name2, @name3) tuple. + * Find the payload specified by the (@key, @key2, @key3) tuple. * - * Returns the a pointer to the userdata + * Returns a pointer to the payload or NULL if no entry was found. */ void * -xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, - const xmlChar *name2, const xmlChar *name3) { - unsigned long key; - xmlHashEntryPtr entry; +xmlHashLookup3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3) { + const xmlHashEntry *entry; + unsigned hashValue; + int found; - 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); - } + if ((hash == NULL) || (hash->size == 0) || (key == NULL)) + return(NULL); + hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, NULL); + entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found); + if (found) + 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 + * @hash: hash table + * @prefix: first prefix + * @name: first local name + * @prefix2: second prefix + * @name2: second local name + * @prefix3: third prefix + * @name3: third local name * - * Find the userdata specified by the (@name, @name2, @name3) tuple. + * Find the payload specified by the QNames tuple. * - * Returns the a pointer to the userdata + * Returns a pointer to the payload or NULL if no entry was found. */ +ATTRIBUTE_NO_SANITIZE_INTEGER void * -xmlHashQLookup3(xmlHashTablePtr table, +xmlHashQLookup3(xmlHashTablePtr hash, const xmlChar *prefix, const xmlChar *name, - const xmlChar *prefix2, const xmlChar *name2, - const xmlChar *prefix3, const xmlChar *name3) { - unsigned long key; - xmlHashEntryPtr entry; + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + const xmlHashEntry *entry; + unsigned hashValue, mask, pos, displ; - 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); + if ((hash == NULL) || (hash->size == 0) || (name == NULL)) + return(NULL); + + hashValue = xmlHashQNameValue(hash->randomSeed, prefix, name, prefix2, + name2, prefix3, name3); + mask = hash->size - 1; + pos = hashValue & mask; + entry = &hash->table[pos]; + + if (entry->hashValue != 0) { + displ = 0; + hashValue |= MAX_HASH_SIZE; + + do { + if ((hashValue == entry->hashValue) && + (xmlStrQEqual(prefix, name, entry->key)) && + (xmlStrQEqual(prefix2, name2, entry->key2)) && + (xmlStrQEqual(prefix3, name3, entry->key3))) + return(entry->payload); + + displ++; + pos++; + entry++; + if ((pos & mask) == 0) + entry = hash->table; + } while ((entry->hashValue != 0) && + (((pos - entry->hashValue) & mask) >= displ)); } + return(NULL); } typedef struct { - xmlHashScanner hashscanner; + xmlHashScanner scan; 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); +stubHashScannerFull(void *payload, void *data, const xmlChar *key, + const xmlChar *key2 ATTRIBUTE_UNUSED, + const xmlChar *key3 ATTRIBUTE_UNUSED) { + stubData *sdata = (stubData *) data; + sdata->scan(payload, sdata->data, key); } /** * xmlHashScan: - * @table: the hash table - * @f: the scanner function for items in the hash - * @data: extra data passed to f + * @hash: hash table + * @scan: scanner function for items in the hash + * @data: extra data passed to @scan * - * Scan the hash @table and applied @f to each value. + * Scan the hash @table and apply @scan to each value. */ void -xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { - stubData stubdata; - stubdata.data = data; - stubdata.hashscanner = f; - xmlHashScanFull (table, stubHashScannerFull, &stubdata); +xmlHashScan(xmlHashTablePtr hash, xmlHashScanner scan, void *data) { + stubData sdata; + sdata.data = data; + sdata.scan = scan; + xmlHashScanFull(hash, stubHashScannerFull, &sdata); } /** * xmlHashScanFull: - * @table: the hash table - * @f: the scanner function for items in the hash - * @data: extra data passed to f + * @hash: hash table + * @scan: scanner function for items in the hash + * @data: extra data passed to @scan * - * Scan the hash @table and applied @f to each value. + * Scan the hash @table and apply @scan to each value. */ void -xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { - int i, nb; - xmlHashEntryPtr iter; - xmlHashEntryPtr next; +xmlHashScanFull(xmlHashTablePtr hash, xmlHashScannerFull scan, void *data) { + const xmlHashEntry *entry, *end; + xmlHashEntry old; + unsigned i; - 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; - } - } + if ((hash == NULL) || (hash->size == 0) || (scan == NULL)) + return; + + /* + * We must handle the case that a scanned entry is removed when executing + * the callback (xmlCleanSpecialAttr and possibly other places). + * + * Find the start of a probe sequence to avoid scanning entries twice if + * a deletion happens. + */ + entry = hash->table; + end = &hash->table[hash->size]; + while (entry->hashValue != 0) { + if (++entry >= end) + entry = hash->table; + } + + for (i = 0; i < hash->size; i++) { + if ((entry->hashValue != 0) && (entry->payload != NULL)) { + /* + * Make sure to rescan after a possible deletion. + */ + do { + old = *entry; + scan(entry->payload, data, entry->key, entry->key2, entry->key3); + } while ((entry->hashValue != 0) && + (entry->payload != NULL) && + ((entry->key != old.key) || + (entry->key2 != old.key2) || + (entry->key3 != old.key3))); + } + if (++entry >= end) + entry = hash->table; } } /** * 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, + * @hash: hash table + * @key: first string key or NULL + * @key2: second string key or NULL + * @key3: third string key or NULL + * @scan: scanner function for items in the hash + * @data: extra data passed to @scan + * + * Scan the hash @table and apply @scan to each value matching + * (@key, @key2, @key3) tuple. If one of the keys 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) { - stubData stubdata; - stubdata.data = data; - stubdata.hashscanner = f; - xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull, - &stubdata); +xmlHashScan3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + xmlHashScanner scan, void *data) { + stubData sdata; + sdata.data = data; + sdata.scan = scan; + xmlHashScanFull3(hash, key, key2, key3, stubHashScannerFull, &sdata); } /** * 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, + * @hash: hash table + * @key: first string key or NULL + * @key2: second string key or NULL + * @key3: third string key or NULL + * @scan: scanner function for items in the hash + * @data: extra data passed to @scan + * + * Scan the hash @table and apply @scan to each value matching + * (@key, @key2, @key3) tuple. If one of the keys 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; +xmlHashScanFull3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + xmlHashScannerFull scan, void *data) { + const xmlHashEntry *entry, *end; + xmlHashEntry old; + unsigned i; - 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; - } - } + if ((hash == NULL) || (hash->size == 0) || (scan == NULL)) + return; + + /* + * We must handle the case that a scanned entry is removed when executing + * the callback (xmlCleanSpecialAttr and possibly other places). + * + * Find the start of a probe sequence to avoid scanning entries twice if + * a deletion happens. + */ + entry = hash->table; + end = &hash->table[hash->size]; + while (entry->hashValue != 0) { + if (++entry >= end) + entry = hash->table; + } + + for (i = 0; i < hash->size; i++) { + if ((entry->hashValue != 0) && (entry->payload != NULL)) { + /* + * Make sure to rescan after a possible deletion. + */ + do { + if (((key != NULL) && (strcmp((const char *) key, + (const char *) entry->key) != 0)) || + ((key2 != NULL) && (!xmlFastStrEqual(key2, entry->key2))) || + ((key3 != NULL) && (!xmlFastStrEqual(key3, entry->key3)))) + break; + old = *entry; + scan(entry->payload, data, entry->key, entry->key2, entry->key3); + } while ((entry->hashValue != 0) && + (entry->payload != NULL) && + ((entry->key != old.key) || + (entry->key2 != old.key2) || + (entry->key3 != old.key3))); + } + if (++entry >= end) + entry = hash->table; } } -/** - * xmlHashCopy: - * @table: the hash table - * @f: the copier function for items in the hash +/* + * xmlHashCopySafe: + * @hash: hash table + * @copyFunc: copier function for items in the hash + * @deallocFunc: deallocation function in case of errors * - * Scan the hash @table and applied @f to each value. + * Copy the hash table using @copyFunc to copy payloads. * - * Returns the new table or NULL in case of error. + * Available since 2.13.0. + * + * Returns the new table or NULL if a memory allocation failed. */ xmlHashTablePtr -xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) { - int i; - xmlHashEntryPtr iter; - xmlHashEntryPtr next; +xmlHashCopySafe(xmlHashTablePtr hash, xmlHashCopier copyFunc, + xmlHashDeallocator deallocFunc) { + const xmlHashEntry *entry, *end; xmlHashTablePtr ret; - if (table == NULL) - return(NULL); - if (f == NULL) - return(NULL); + if ((hash == NULL) || (copyFunc == NULL)) + return(NULL); - ret = xmlHashCreate(table->size); + ret = xmlHashCreate(hash->size); if (ret == NULL) return(NULL); - 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; - } - } + if (hash->size == 0) + return(ret); + + end = &hash->table[hash->size]; + + for (entry = hash->table; entry < end; entry++) { + if (entry->hashValue != 0) { + void *copy; + + copy = copyFunc(entry->payload, entry->key); + if (copy == NULL) + goto error; + if (xmlHashAdd3(ret, entry->key, entry->key2, entry->key3, + copy) <= 0) { + if (deallocFunc != NULL) + deallocFunc(copy, entry->key); + goto error; + } + } } - ret->nbElems = table->nbElems; + return(ret); + +error: + xmlHashFree(ret, deallocFunc); + return(NULL); +} + +/* + * xmlHashCopy: + * @hash: hash table + * @copy: copier function for items in the hash + * + * DEPRECATED: Leaks memory in error case. + * + * Copy the hash table using @copy to copy payloads. + * + * Returns the new table or NULL if a memory allocation failed. + */ +xmlHashTablePtr +xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) { + return(xmlHashCopySafe(hash, copy, NULL)); } /** * xmlHashSize: - * @table: the hash table + * @hash: hash table * - * Query the number of elements installed in the hash @table. + * Query the number of elements in the hash table. * * Returns the number of elements in the hash table or - * -1 in case of error + * -1 in case of error. */ int -xmlHashSize(xmlHashTablePtr table) { - if (table == NULL) - return(-1); - return(table->nbElems); +xmlHashSize(xmlHashTablePtr hash) { + if (hash == NULL) + return(-1); + return(hash->nbElems); } /** * xmlHashRemoveEntry: - * @table: the hash table - * @name: the name of the userdata - * @f: the deallocator function for removed item (if any) + * @hash: hash table + * @key: string key + * @dealloc: deallocator function for removed item or NULL * - * 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. + * Find the entry specified by the @key and remove it from the hash table. + * Payload will be freed with @dealloc. * - * Returns 0 if the removal succeeded and -1 in case of error or not found. + * Returns 0 on success and -1 if no entry was found. */ -int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, - xmlHashDeallocator f) { - return(xmlHashRemoveEntry3(table, name, NULL, NULL, f)); +int xmlHashRemoveEntry(xmlHashTablePtr hash, const xmlChar *key, + xmlHashDeallocator dealloc) { + return(xmlHashRemoveEntry3(hash, key, NULL, NULL, dealloc)); } /** * 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) + * @hash: hash table + * @key: first string key + * @key2: second string key + * @dealloc: deallocator function for removed item or NULL * - * 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. + * Remove an entry with two strings as key. * - * Returns 0 if the removal succeeded and -1 in case of error or not found. + * See xmlHashRemoveEntry. + * + * Returns 0 on success and -1 in case of error. */ int -xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, - const xmlChar *name2, xmlHashDeallocator f) { - return(xmlHashRemoveEntry3(table, name, name2, NULL, f)); +xmlHashRemoveEntry2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, xmlHashDeallocator dealloc) { + return(xmlHashRemoveEntry3(hash, key, key2, NULL, dealloc)); } /** * 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) + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @dealloc: deallocator function for removed item or NULL + * + * Remove an entry with three strings as key. * - * 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. + * See xmlHashRemoveEntry. * - * Returns 0 if the removal succeeded and -1 in case of error or not found. + * Returns 0 on success and -1 in case of error. */ +ATTRIBUTE_NO_SANITIZE_INTEGER 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) +xmlHashRemoveEntry3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + xmlHashDeallocator dealloc) { + xmlHashEntry *entry, *cur, *next; + unsigned hashValue, mask, pos, nextpos; + int found; + + if ((hash == NULL) || (hash->size == 0) || (key == 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; - } + hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, NULL); + entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found); + if (!found) return(-1); + + if ((dealloc != NULL) && (entry->payload != NULL)) + dealloc(entry->payload, entry->key); + if (hash->dict == NULL) { + if (entry->key) + xmlFree(entry->key); + if (entry->key2) + xmlFree(entry->key2); + if (entry->key3) + xmlFree(entry->key3); + } + + /* + * Find end of probe sequence. Entries at their initial probe + * position start a new sequence. + */ + mask = hash->size - 1; + pos = entry - hash->table; + cur = entry; + + while (1) { + nextpos = pos + 1; + next = cur + 1; + if ((nextpos & mask) == 0) + next = hash->table; + + if ((next->hashValue == 0) || + (((next->hashValue - nextpos) & mask) == 0)) + break; + + cur = next; + pos = nextpos; + } + + /* + * Backward shift + */ + next = entry + 1; + + if (cur < entry) { + xmlHashEntry *end = &hash->table[hash->size]; + + memmove(entry, next, (char *) end - (char *) next); + entry = hash->table; + end[-1] = *entry; + next = entry + 1; } + + memmove(entry, next, (char *) cur - (char *) entry); + + /* + * Update entry + */ + cur->hashValue = 0; + + hash->nbElems--; + + return(0); } diff --git a/include/libxml/HTMLparser.h b/include/libxml/HTMLparser.h index 1d4fec2f734..7be3d2b8a43 100644 --- a/include/libxml/HTMLparser.h +++ b/include/libxml/HTMLparser.h @@ -80,90 +80,117 @@ struct _htmlEntityDesc { const char *desc; /* the description */ }; +#ifdef LIBXML_SAX1_ENABLED + +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 htmlDefaultSAXHandler; + +#ifdef LIBXML_THREAD_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__htmlDefaultSAXHandler(void); +#endif + +#endif /* LIBXML_SAX1_ENABLED */ + /* * There is only few public functions. */ -XMLPUBFUN const htmlElemDesc * XMLCALL +XML_DEPRECATED +XMLPUBFUN void + htmlInitAutoClose (void); +XMLPUBFUN const htmlElemDesc * htmlTagLookup (const xmlChar *tag); -XMLPUBFUN const htmlEntityDesc * XMLCALL +XMLPUBFUN const htmlEntityDesc * htmlEntityLookup(const xmlChar *name); -XMLPUBFUN const htmlEntityDesc * XMLCALL +XMLPUBFUN const htmlEntityDesc * htmlEntityValueLookup(unsigned int value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlIsAutoClosed(htmlDocPtr doc, htmlNodePtr elem); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlAutoCloseTag(htmlDocPtr doc, const xmlChar *name, htmlNodePtr elem); -XMLPUBFUN const htmlEntityDesc * XMLCALL +XML_DEPRECATED +XMLPUBFUN const htmlEntityDesc * htmlParseEntityRef(htmlParserCtxtPtr ctxt, const xmlChar **str); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int htmlParseCharRef(htmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void htmlParseElement(htmlParserCtxtPtr ctxt); -XMLPUBFUN htmlParserCtxtPtr XMLCALL +XMLPUBFUN htmlParserCtxtPtr htmlNewParserCtxt(void); +XMLPUBFUN htmlParserCtxtPtr + htmlNewSAXParserCtxt(const htmlSAXHandler *sax, + void *userData); -XMLPUBFUN htmlParserCtxtPtr XMLCALL +XMLPUBFUN htmlParserCtxtPtr htmlCreateMemoryParserCtxt(const char *buffer, int size); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlParseDocument(htmlParserCtxtPtr ctxt); -XMLPUBFUN htmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN htmlDocPtr htmlSAXParseDoc (const xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void *userData); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlParseDoc (const xmlChar *cur, const char *encoding); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlParserCtxtPtr + htmlCreateFileParserCtxt(const char *filename, + const char *encoding); +XML_DEPRECATED +XMLPUBFUN htmlDocPtr htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax, void *userData); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlParseFile (const char *filename, const char *encoding); -XMLPUBFUN int XMLCALL +XMLPUBFUN int UTF8ToHtml (unsigned char *out, int *outlen, const unsigned char *in, int *inlen); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlEncodeEntities(unsigned char *out, int *outlen, const unsigned char *in, int *inlen, int quoteChar); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlIsScriptAttribute(const xmlChar *name); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int htmlHandleOmittedElem(int val); #ifdef LIBXML_PUSH_ENABLED /** * Interfaces for the Push mode. */ -XMLPUBFUN htmlParserCtxtPtr XMLCALL +XMLPUBFUN htmlParserCtxtPtr htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename, xmlCharEncoding enc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlParseChunk (htmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate); #endif /* LIBXML_PUSH_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlFreeParserCtxt (htmlParserCtxtPtr ctxt); /* @@ -188,63 +215,66 @@ typedef enum { HTML_PARSE_IGNORE_ENC=1<<21 /* ignore internal document encoding hint */ } htmlParserOption; -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlCtxtReset (htmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlCtxtUseOptions (htmlParserCtxtPtr ctxt, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlReadDoc (const xmlChar *cur, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlReadFile (const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlReadMemory (const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlReadFd (int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlReadIO (xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr + htmlCtxtParseDocument (htmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN htmlDocPtr htmlCtxtReadDoc (xmlParserCtxtPtr ctxt, const xmlChar *cur, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlCtxtReadFile (xmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlCtxtReadMemory (xmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlCtxtReadFd (xmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlCtxtReadIO (xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, @@ -266,10 +296,10 @@ typedef enum { /* Using htmlElemDesc rather than name here, to emphasise the fact that otherwise there's a lookup overhead */ -XMLPUBFUN htmlStatus XMLCALL htmlAttrAllowed(const htmlElemDesc*, const xmlChar*, int) ; -XMLPUBFUN int XMLCALL htmlElementAllowedHere(const htmlElemDesc*, const xmlChar*) ; -XMLPUBFUN htmlStatus XMLCALL htmlElementStatusHere(const htmlElemDesc*, const htmlElemDesc*) ; -XMLPUBFUN htmlStatus XMLCALL htmlNodeStatus(const htmlNodePtr, int) ; +XMLPUBFUN htmlStatus htmlAttrAllowed(const htmlElemDesc*, const xmlChar*, int) ; +XMLPUBFUN int htmlElementAllowedHere(const htmlElemDesc*, const xmlChar*) ; +XMLPUBFUN htmlStatus htmlElementStatusHere(const htmlElemDesc*, const htmlElemDesc*) ; +XMLPUBFUN htmlStatus htmlNodeStatus(htmlNodePtr, int) ; /** * htmlDefaultSubelement: * @elt: HTML element diff --git a/include/libxml/HTMLtree.h b/include/libxml/HTMLtree.h index c0e110330c5..8e1ba90e915 100644 --- a/include/libxml/HTMLtree.h +++ b/include/libxml/HTMLtree.h @@ -59,73 +59,73 @@ extern "C" { */ #define HTML_PI_NODE XML_PI_NODE -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlNewDoc (const xmlChar *URI, const xmlChar *ExternalID); -XMLPUBFUN htmlDocPtr XMLCALL +XMLPUBFUN htmlDocPtr htmlNewDocNoDtD (const xmlChar *URI, const xmlChar *ExternalID); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * htmlGetMetaEncoding (htmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlSetMetaEncoding (htmlDocPtr doc, const xmlChar *encoding); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlDocDumpMemory (xmlDocPtr cur, xmlChar **mem, int *size); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlDocDumpMemoryFormat (xmlDocPtr cur, xmlChar **mem, int *size, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlDocDump (FILE *f, xmlDocPtr cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlSaveFile (const char *filename, xmlDocPtr cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlNodeDump (xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlNodeDumpFile (FILE *out, xmlDocPtr doc, xmlNodePtr cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlNodeDumpFileFormat (FILE *out, xmlDocPtr doc, xmlNodePtr cur, const char *encoding, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlSaveFileEnc (const char *filename, xmlDocPtr cur, const char *encoding); -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlSaveFileFormat (const char *filename, xmlDocPtr cur, const char *encoding, int format); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const char *encoding, int format); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format); -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlNodeDumpOutput (xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, @@ -133,7 +133,7 @@ XMLPUBFUN void XMLCALL #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int htmlIsBooleanAttr (const xmlChar *name); diff --git a/include/libxml/SAX.h b/include/libxml/SAX.h index fa50568f253..eea1057bfcc 100644 --- a/include/libxml/SAX.h +++ b/include/libxml/SAX.h @@ -12,8 +12,6 @@ #ifndef __XML_SAX_H__ #define __XML_SAX_H__ -#include -#include #include #include @@ -23,61 +21,61 @@ extern "C" { #endif XML_DEPRECATED -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * getPublicId (void *ctx); XML_DEPRECATED -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * getSystemId (void *ctx); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void setDocumentLocator (void *ctx, xmlSAXLocatorPtr loc); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int getLineNumber (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int getColumnNumber (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int isStandalone (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int hasInternalSubset (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int hasExternalSubset (void *ctx); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void internalSubset (void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void externalSubset (void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); XML_DEPRECATED -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr getEntity (void *ctx, const xmlChar *name); XML_DEPRECATED -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr getParameterEntity (void *ctx, const xmlChar *name); XML_DEPRECATED -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr resolveEntity (void *ctx, const xmlChar *publicId, const xmlChar *systemId); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void entityDecl (void *ctx, const xmlChar *name, int type, @@ -85,7 +83,7 @@ XMLPUBFUN void XMLCALL const xmlChar *systemId, xmlChar *content); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void attributeDecl (void *ctx, const xmlChar *elem, const xmlChar *fullname, @@ -94,19 +92,19 @@ XMLPUBFUN void XMLCALL const xmlChar *defaultValue, xmlEnumerationPtr tree); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void elementDecl (void *ctx, const xmlChar *name, int type, xmlElementContentPtr content); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void notationDecl (void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void unparsedEntityDecl (void *ctx, const xmlChar *name, const xmlChar *publicId, @@ -114,83 +112,83 @@ XMLPUBFUN void XMLCALL const xmlChar *notationName); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void startDocument (void *ctx); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void endDocument (void *ctx); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void attribute (void *ctx, const xmlChar *fullname, const xmlChar *value); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void startElement (void *ctx, const xmlChar *fullname, const xmlChar **atts); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void endElement (void *ctx, const xmlChar *name); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void reference (void *ctx, const xmlChar *name); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void characters (void *ctx, const xmlChar *ch, int len); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void ignorableWhitespace (void *ctx, const xmlChar *ch, int len); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void processingInstruction (void *ctx, const xmlChar *target, const xmlChar *data); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void globalNamespace (void *ctx, const xmlChar *href, const xmlChar *prefix); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void setNamespace (void *ctx, const xmlChar *name); XML_DEPRECATED -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr getNamespace (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int checkNamespace (void *ctx, xmlChar *nameSpace); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void namespaceDecl (void *ctx, const xmlChar *href, const xmlChar *prefix); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void comment (void *ctx, const xmlChar *value); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void cdataBlock (void *ctx, const xmlChar *value, int len); #ifdef LIBXML_SAX1_ENABLED XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void initxmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr, int warning); #ifdef LIBXML_HTML_ENABLED XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void inithtmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr); #endif #endif /* LIBXML_SAX1_ENABLED */ diff --git a/include/libxml/SAX2.h b/include/libxml/SAX2.h index 8e9b0b95fe5..4c4ecce8e59 100644 --- a/include/libxml/SAX2.h +++ b/include/libxml/SAX2.h @@ -12,63 +12,61 @@ #ifndef __XML_SAX2_H__ #define __XML_SAX2_H__ -#include -#include #include #include #ifdef __cplusplus extern "C" { #endif -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlSAX2GetPublicId (void *ctx); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlSAX2GetSystemId (void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2SetDocumentLocator (void *ctx, xmlSAXLocatorPtr loc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAX2GetLineNumber (void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAX2GetColumnNumber (void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAX2IsStandalone (void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAX2HasInternalSubset (void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAX2HasExternalSubset (void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2InternalSubset (void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2ExternalSubset (void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlSAX2GetEntity (void *ctx, const xmlChar *name); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlSAX2GetParameterEntity (void *ctx, const xmlChar *name); -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlSAX2ResolveEntity (void *ctx, const xmlChar *publicId, const xmlChar *systemId); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2EntityDecl (void *ctx, const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2AttributeDecl (void *ctx, const xmlChar *elem, const xmlChar *fullname, @@ -76,38 +74,38 @@ XMLPUBFUN void XMLCALL int def, const xmlChar *defaultValue, xmlEnumerationPtr tree); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2ElementDecl (void *ctx, const xmlChar *name, int type, xmlElementContentPtr content); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2NotationDecl (void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2UnparsedEntityDecl (void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2StartDocument (void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2EndDocument (void *ctx); #if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED) -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2StartElement (void *ctx, const xmlChar *fullname, const xmlChar **atts); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2EndElement (void *ctx, const xmlChar *name); #endif /* LIBXML_SAX1_ENABLED or LIBXML_HTML_ENABLED or LIBXML_LEGACY_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2StartElementNs (void *ctx, const xmlChar *localname, const xmlChar *prefix, @@ -117,54 +115,55 @@ XMLPUBFUN void XMLCALL int nb_attributes, int nb_defaulted, const xmlChar **attributes); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2EndElementNs (void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2Reference (void *ctx, const xmlChar *name); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2Characters (void *ctx, const xmlChar *ch, int len); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2IgnorableWhitespace (void *ctx, const xmlChar *ch, int len); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2ProcessingInstruction (void *ctx, const xmlChar *target, const xmlChar *data); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2Comment (void *ctx, const xmlChar *value); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2CDataBlock (void *ctx, const xmlChar *value, int len); #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlSAXDefaultVersion (int version); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSAXVersion (xmlSAXHandler *hdlr, int version); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2InitDefaultSAXHandler (xmlSAXHandler *hdlr, int warning); #ifdef LIBXML_HTML_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void htmlDefaultSAXHandlerInit (void); #endif XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDefaultSAXHandlerInit (void); #ifdef __cplusplus } diff --git a/include/libxml/c14n.h b/include/libxml/c14n.h index af93de63a4c..8ccd1cef632 100644 --- a/include/libxml/c14n.h +++ b/include/libxml/c14n.h @@ -20,7 +20,6 @@ #include #ifdef LIBXML_C14N_ENABLED -#ifdef LIBXML_OUTPUT_ENABLED #include #include @@ -40,18 +39,7 @@ extern "C" { * a) default attributes (if any) are added to all nodes * b) all character and parsed entity references are resolved * In order to achieve this in libxml2 the document MUST be loaded with - * following global settings: - * - * 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; - * ... + * following options: XML_PARSE_DTDATTR | XML_PARSE_NOENT */ /* @@ -66,7 +54,7 @@ typedef enum { XML_C14N_1_1 = 2 /* C14N 1.1 spec */ } xmlC14NMode; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlC14NDocSaveTo (xmlDocPtr doc, xmlNodeSetPtr nodes, int mode, /* a xmlC14NMode */ @@ -74,7 +62,7 @@ XMLPUBFUN int XMLCALL int with_comments, xmlOutputBufferPtr buf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlC14NDocDumpMemory (xmlDocPtr doc, xmlNodeSetPtr nodes, int mode, /* a xmlC14NMode */ @@ -82,7 +70,7 @@ XMLPUBFUN int XMLCALL int with_comments, xmlChar **doc_txt_ptr); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlC14NDocSave (xmlDocPtr doc, xmlNodeSetPtr nodes, int mode, /* a xmlC14NMode */ @@ -109,7 +97,7 @@ typedef int (*xmlC14NIsVisibleCallback) (void* user_data, xmlNodePtr node, xmlNodePtr parent); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlC14NExecute (xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, void* user_data, @@ -122,7 +110,6 @@ XMLPUBFUN int XMLCALL } #endif /* __cplusplus */ -#endif /* LIBXML_OUTPUT_ENABLED */ #endif /* LIBXML_C14N_ENABLED */ #endif /* __XML_C14N_H__ */ diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h index 26b178dbbc9..02fa7ab2a03 100644 --- a/include/libxml/catalog.h +++ b/include/libxml/catalog.h @@ -66,113 +66,113 @@ typedef xmlCatalog *xmlCatalogPtr; /* * Operations on a given catalog. */ -XMLPUBFUN xmlCatalogPtr XMLCALL +XMLPUBFUN xmlCatalogPtr xmlNewCatalog (int sgml); -XMLPUBFUN xmlCatalogPtr XMLCALL +XMLPUBFUN xmlCatalogPtr xmlLoadACatalog (const char *filename); -XMLPUBFUN xmlCatalogPtr XMLCALL +XMLPUBFUN xmlCatalogPtr xmlLoadSGMLSuperCatalog (const char *filename); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlConvertSGMLCatalog (xmlCatalogPtr catal); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlACatalogAdd (xmlCatalogPtr catal, const xmlChar *type, const xmlChar *orig, const xmlChar *replace); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlACatalogRemove (xmlCatalogPtr catal, const xmlChar *value); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlACatalogResolve (xmlCatalogPtr catal, const xmlChar *pubID, const xmlChar *sysID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlACatalogResolveURI (xmlCatalogPtr catal, const xmlChar *URI); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlACatalogDump (xmlCatalogPtr catal, FILE *out); #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeCatalog (xmlCatalogPtr catal); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCatalogIsEmpty (xmlCatalogPtr catal); /* * Global operations. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlInitializeCatalog (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlLoadCatalog (const char *filename); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlLoadCatalogs (const char *paths); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCatalogCleanup (void); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCatalogDump (FILE *out); #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogResolve (const xmlChar *pubID, const xmlChar *sysID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogResolveSystem (const xmlChar *sysID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogResolvePublic (const xmlChar *pubID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogResolveURI (const xmlChar *URI); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCatalogAdd (const xmlChar *type, const xmlChar *orig, const xmlChar *replace); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCatalogRemove (const xmlChar *value); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlParseCatalogFile (const char *filename); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCatalogConvert (void); /* * Strictly minimal interfaces for per-document catalogs used * by the parser. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCatalogFreeLocal (void *catalogs); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlCatalogAddLocal (void *catalogs, const xmlChar *URL); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogLocalResolve (void *catalogs, const xmlChar *pubID, const xmlChar *sysID); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI); /* * Preference settings. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCatalogSetDebug (int level); -XMLPUBFUN xmlCatalogPrefer XMLCALL +XMLPUBFUN xmlCatalogPrefer xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCatalogSetDefaults (xmlCatalogAllow allow); -XMLPUBFUN xmlCatalogAllow XMLCALL +XMLPUBFUN xmlCatalogAllow xmlCatalogGetDefaults (void); /* DEPRECATED interfaces */ -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlCatalogGetSystem (const xmlChar *sysID); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlCatalogGetPublic (const xmlChar *pubID); #ifdef __cplusplus diff --git a/include/libxml/chvalid.h b/include/libxml/chvalid.h index fb43016982d..8225c95ee86 100644 --- a/include/libxml/chvalid.h +++ b/include/libxml/chvalid.h @@ -51,7 +51,7 @@ struct _xmlChRangeGroup { /** * Range checking routine */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCharInRange(unsigned int val, const xmlChRangeGroup *group); @@ -207,21 +207,21 @@ XMLPUBVAR const unsigned char xmlIsPubidChar_tab[256]; #define xmlIsPubidCharQ(c) (((c) < 0x100) ? \ xmlIsPubidChar_ch((c)) : 0) -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsBaseChar(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsBlank(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsChar(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsCombining(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsDigit(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsExtender(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsIdeographic(unsigned int ch); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsPubidChar(unsigned int ch); #ifdef __cplusplus diff --git a/include/libxml/debugXML.h b/include/libxml/debugXML.h index 5b3be13d857..1332dd73d9c 100644 --- a/include/libxml/debugXML.h +++ b/include/libxml/debugXML.h @@ -25,39 +25,39 @@ extern "C" { /* * The standard Dump routines. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpString (FILE *output, const xmlChar *str); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpAttr (FILE *output, xmlAttrPtr attr, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpAttrList (FILE *output, xmlAttrPtr attr, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpOneNode (FILE *output, xmlNodePtr node, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpNode (FILE *output, xmlNodePtr node, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpNodeList (FILE *output, xmlNodePtr node, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpDocument (FILE *output, xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpDTD (FILE *output, xmlDtdPtr dtd); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDebugDumpEntities (FILE *output, xmlDocPtr doc); @@ -67,7 +67,7 @@ XMLPUBFUN void XMLCALL * * ****************************************************************/ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDebugCheckDocument (FILE * output, xmlDocPtr doc); @@ -77,12 +77,12 @@ XMLPUBFUN int XMLCALL * * ****************************************************************/ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlLsOneNode (FILE *output, xmlNodePtr node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlLsCountNode (xmlNodePtr node); -XMLPUBFUN const char * XMLCALL +XMLPUBFUN const char * xmlBoolToText (int boolval); /**************************************************************** @@ -136,63 +136,63 @@ typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlShellPrintXPathError (int errorType, const char *arg); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlShellPrintXPathResult(xmlXPathObjectPtr list); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellList (xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellBase (xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellDir (xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellLoad (xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, xmlNodePtr node2); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlShellPrintNode (xmlNodePtr node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellCat (xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellWrite (xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellSave (xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, xmlNodePtr node2); #endif /* LIBXML_OUTPUT_ENABLED */ #ifdef LIBXML_VALID_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellValidate (xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node, xmlNodePtr node2); #endif /* LIBXML_VALID_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellDu (xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree, xmlNodePtr node2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlShellPwd (xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node, @@ -201,9 +201,9 @@ XMLPUBFUN int XMLCALL /* * The Shell interface. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlShell (xmlDocPtr doc, - char *filename, + const char *filename, xmlShellReadlineFunc input, FILE *output); diff --git a/include/libxml/dict.h b/include/libxml/dict.h index 91f74d1b8ff..22aa3d9db8b 100644 --- a/include/libxml/dict.h +++ b/include/libxml/dict.h @@ -13,6 +13,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -28,51 +29,51 @@ typedef xmlDict *xmlDictPtr; * Initializer */ XML_DEPRECATED -XMLPUBFUN int XMLCALL xmlInitializeDict(void); +XMLPUBFUN int xmlInitializeDict(void); /* * Constructor and destructor. */ -XMLPUBFUN xmlDictPtr XMLCALL +XMLPUBFUN xmlDictPtr xmlDictCreate (void); -XMLPUBFUN size_t XMLCALL +XMLPUBFUN size_t xmlDictSetLimit (xmlDictPtr dict, size_t limit); -XMLPUBFUN size_t XMLCALL +XMLPUBFUN size_t xmlDictGetUsage (xmlDictPtr dict); -XMLPUBFUN xmlDictPtr XMLCALL +XMLPUBFUN xmlDictPtr xmlDictCreateSub(xmlDictPtr sub); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDictReference(xmlDictPtr dict); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDictFree (xmlDictPtr dict); /* * Lookup of entry in the dictionary. */ -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlDictLookup (xmlDictPtr dict, const xmlChar *name, int len); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlDictExists (xmlDictPtr dict, const xmlChar *name, int len); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlDictQLookup (xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDictOwns (xmlDictPtr dict, const xmlChar *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDictSize (xmlDictPtr dict); /* * Cleanup function */ XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDictCleanup (void); #ifdef __cplusplus diff --git a/include/libxml/encoding.h b/include/libxml/encoding.h index 381e1886bf8..599a03e12cd 100644 --- a/include/libxml/encoding.h +++ b/include/libxml/encoding.h @@ -32,6 +32,15 @@ extern "C" { #endif +typedef enum { + XML_ENC_ERR_SUCCESS = 0, + XML_ENC_ERR_SPACE = -1, + XML_ENC_ERR_INPUT = -2, + XML_ENC_ERR_PARTIAL = -3, + XML_ENC_ERR_INTERNAL = -4, + XML_ENC_ERR_MEMORY = -5 +} xmlCharEncError; + /* * xmlCharEncoding: * @@ -142,30 +151,29 @@ struct _xmlCharEncodingHandler { #endif /* LIBXML_ICU_ENABLED */ }; -#ifdef __cplusplus -} -#endif -#include -#ifdef __cplusplus -extern "C" { -#endif - /* * Interfaces for encoding handlers. */ XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlInitCharEncodingHandlers (void); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupCharEncodingHandlers (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRegisterCharEncodingHandler (xmlCharEncodingHandlerPtr handler); -XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL +XMLPUBFUN int + xmlLookupCharEncodingHandler (xmlCharEncoding enc, + xmlCharEncodingHandlerPtr *out); +XMLPUBFUN int + xmlOpenCharEncodingHandler (const char *name, + int output, + xmlCharEncodingHandlerPtr *out); +XMLPUBFUN xmlCharEncodingHandlerPtr xmlGetCharEncodingHandler (xmlCharEncoding enc); -XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL +XMLPUBFUN xmlCharEncodingHandlerPtr xmlFindCharEncodingHandler (const char *name); -XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL +XMLPUBFUN xmlCharEncodingHandlerPtr xmlNewCharEncodingHandler (const char *name, xmlCharEncodingInputFunc input, xmlCharEncodingOutputFunc output); @@ -173,54 +181,58 @@ XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL /* * Interfaces for encoding names and aliases. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlAddEncodingAlias (const char *name, const char *alias); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDelEncodingAlias (const char *alias); -XMLPUBFUN const char * XMLCALL +XMLPUBFUN const char * xmlGetEncodingAlias (const char *alias); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupEncodingAliases (void); -XMLPUBFUN xmlCharEncoding XMLCALL +XMLPUBFUN xmlCharEncoding xmlParseCharEncoding (const char *name); -XMLPUBFUN const char * XMLCALL +XMLPUBFUN const char * xmlGetCharEncodingName (xmlCharEncoding enc); /* * Interfaces directly used by the parsers. */ -XMLPUBFUN xmlCharEncoding XMLCALL +XMLPUBFUN xmlCharEncoding xmlDetectCharEncoding (const unsigned char *in, int len); -XMLPUBFUN int XMLCALL +/** DOC_DISABLE */ +struct _xmlBuffer; +/** DOC_ENABLE */ +XMLPUBFUN int xmlCharEncOutFunc (xmlCharEncodingHandler *handler, - xmlBufferPtr out, - xmlBufferPtr in); + struct _xmlBuffer *out, + struct _xmlBuffer *in); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCharEncInFunc (xmlCharEncodingHandler *handler, - xmlBufferPtr out, - xmlBufferPtr in); -XMLPUBFUN int XMLCALL + struct _xmlBuffer *out, + struct _xmlBuffer *in); +XML_DEPRECATED +XMLPUBFUN int xmlCharEncFirstLine (xmlCharEncodingHandler *handler, - xmlBufferPtr out, - xmlBufferPtr in); -XMLPUBFUN int XMLCALL + struct _xmlBuffer *out, + struct _xmlBuffer *in); +XMLPUBFUN int xmlCharEncCloseFunc (xmlCharEncodingHandler *handler); /* * Export a few useful functions */ #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int UTF8Toisolat1 (unsigned char *out, int *outlen, const unsigned char *in, int *inlen); #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int isolat1ToUTF8 (unsigned char *out, int *outlen, const unsigned char *in, diff --git a/include/libxml/entities.h b/include/libxml/entities.h index 2b60d9e6228..a0cfca8133f 100644 --- a/include/libxml/entities.h +++ b/include/libxml/entities.h @@ -11,8 +11,12 @@ #ifndef __XML_ENTITIES_H__ #define __XML_ENTITIES_H__ +/** DOC_DISABLE */ #include +#define XML_TREE_INTERNALS #include +#undef XML_TREE_INTERNALS +/** DOC_ENABLE */ #ifdef __cplusplus extern "C" { @@ -55,11 +59,9 @@ struct _xmlEntity { 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 entities - * references done from that entity - * and if it contains '<' */ + int owner; /* unused */ + int flags; /* various flags */ + unsigned long expandedSize; /* expanded size */ }; /* @@ -76,72 +78,83 @@ typedef xmlEntitiesTable *xmlEntitiesTablePtr; #ifdef LIBXML_LEGACY_ENABLED XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlInitializePredefinedEntities (void); #endif /* LIBXML_LEGACY_ENABLED */ -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlNewEntity (xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN void + xmlFreeEntity (xmlEntityPtr entity); +XMLPUBFUN int + xmlAddEntity (xmlDocPtr doc, + int extSubset, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content, + xmlEntityPtr *out); +XMLPUBFUN xmlEntityPtr xmlAddDocEntity (xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlAddDtdEntity (xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlGetPredefinedEntity (const xmlChar *name); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlGetDocEntity (const xmlDoc *doc, const xmlChar *name); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlGetDtdEntity (xmlDocPtr doc, const xmlChar *name); -XMLPUBFUN xmlEntityPtr XMLCALL +XMLPUBFUN xmlEntityPtr xmlGetParameterEntity (xmlDocPtr doc, const xmlChar *name); #ifdef LIBXML_LEGACY_ENABLED XML_DEPRECATED -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlEncodeEntities (xmlDocPtr doc, const xmlChar *input); #endif /* LIBXML_LEGACY_ENABLED */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlEncodeSpecialChars (const xmlDoc *doc, const xmlChar *input); -XMLPUBFUN xmlEntitiesTablePtr XMLCALL +XMLPUBFUN xmlEntitiesTablePtr xmlCreateEntitiesTable (void); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlEntitiesTablePtr XMLCALL +XMLPUBFUN xmlEntitiesTablePtr xmlCopyEntitiesTable (xmlEntitiesTablePtr table); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeEntitiesTable (xmlEntitiesTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDumpEntitiesTable (xmlBufferPtr buf, xmlEntitiesTablePtr table); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDumpEntityDecl (xmlBufferPtr buf, xmlEntityPtr ent); #endif /* LIBXML_OUTPUT_ENABLED */ #ifdef LIBXML_LEGACY_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupPredefinedEntities(void); #endif /* LIBXML_LEGACY_ENABLED */ diff --git a/include/libxml/globals.h b/include/libxml/globals.h index d57ccb05415..92f41312f54 100644 --- a/include/libxml/globals.h +++ b/include/libxml/globals.h @@ -1,496 +1,38 @@ /* * 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 + * Description: Deprecated, don't use * * 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 - -#ifdef __cplusplus -extern "C" { -#endif - -XML_DEPRECATED -XMLPUBFUN void XMLCALL xmlInitGlobals(void); -XML_DEPRECATED -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 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 + * This file was required to access global variables until version v2.12.0. * - * Signature for the deregistration callback of a discarded node + * These includes are for backward compatibility. */ -typedef void (*xmlDeregisterNodeFunc) (xmlNodePtr node); - -typedef struct _xmlGlobalState xmlGlobalState; -typedef xmlGlobalState *xmlGlobalStatePtr; -struct _xmlGlobalState -{ - const char *xmlParserVersion; - - xmlSAXLocator xmlDefaultSAXLocator; - xmlSAXHandlerV1 xmlDefaultSAXHandler; - xmlSAXHandlerV1 docbDefaultSAXHandler; /* unused */ - 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 +#include +#include +#include +#include #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_HTML_ENABLED -XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __htmlDefaultSAXHandler(void); -#ifdef LIBXML_THREAD_ENABLED -#define htmlDefaultSAXHandler \ -(*(__htmlDefaultSAXHandler())) -#else -XMLPUBVAR xmlSAXHandlerV1 htmlDefaultSAXHandler; -#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 +typedef struct _xmlGlobalState xmlGlobalState; +typedef xmlGlobalState *xmlGlobalStatePtr; -XMLPUBFUN xmlOutputBufferCreateFilenameFunc * XMLCALL __xmlOutputBufferCreateFilenameValue(void); -#ifdef LIBXML_THREAD_ENABLED -#define xmlOutputBufferCreateFilenameValue \ -(*(__xmlOutputBufferCreateFilenameValue())) -#else -XMLPUBVAR xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue; -#endif +XML_DEPRECATED XMLPUBFUN void +xmlInitializeGlobalState(xmlGlobalStatePtr gs); +XML_DEPRECATED XMLPUBFUN +xmlGlobalStatePtr xmlGetGlobalState(void); #ifdef __cplusplus } diff --git a/include/libxml/hash.h b/include/libxml/hash.h index b682b6b9403..135b69669b3 100644 --- a/include/libxml/hash.h +++ b/include/libxml/hash.h @@ -11,6 +11,10 @@ #ifndef __XML_HASH_H__ #define __XML_HASH_H__ +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -21,18 +25,6 @@ extern "C" { 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 @@ -55,7 +47,6 @@ extern "C" { #define XML_CAST_FPTR(fptr) fptr - /* * function types: */ @@ -103,132 +94,156 @@ typedef void (*xmlHashScannerFull)(void *payload, void *data, /* * Constructor and destructor. */ -XMLPUBFUN xmlHashTablePtr XMLCALL - xmlHashCreate (int size); -XMLPUBFUN xmlHashTablePtr XMLCALL - xmlHashCreateDict(int size, +XMLPUBFUN xmlHashTablePtr + xmlHashCreate (int size); +XMLPUBFUN xmlHashTablePtr + xmlHashCreateDict (int size, xmlDictPtr dict); -XMLPUBFUN void XMLCALL - xmlHashFree (xmlHashTablePtr table, - xmlHashDeallocator f); -XMLPUBFUN void XMLCALL - xmlHashDefaultDeallocator(void *entry, +XMLPUBFUN void + xmlHashFree (xmlHashTablePtr hash, + xmlHashDeallocator dealloc); +XMLPUBFUN void + xmlHashDefaultDeallocator(void *entry, const xmlChar *name); /* * Add a new entry to the hash table. */ -XMLPUBFUN int XMLCALL - xmlHashAddEntry (xmlHashTablePtr table, +XMLPUBFUN int + xmlHashAdd (xmlHashTablePtr hash, + const xmlChar *name, + void *userdata); +XMLPUBFUN int + xmlHashAddEntry (xmlHashTablePtr hash, const xmlChar *name, void *userdata); -XMLPUBFUN int XMLCALL - xmlHashUpdateEntry(xmlHashTablePtr table, +XMLPUBFUN int + xmlHashUpdateEntry (xmlHashTablePtr hash, const xmlChar *name, void *userdata, - xmlHashDeallocator f); -XMLPUBFUN int XMLCALL - xmlHashAddEntry2(xmlHashTablePtr table, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd2 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, void *userdata); -XMLPUBFUN int XMLCALL - xmlHashUpdateEntry2(xmlHashTablePtr table, +XMLPUBFUN int + xmlHashAddEntry2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + void *userdata); +XMLPUBFUN int + xmlHashUpdateEntry2 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, void *userdata, - xmlHashDeallocator f); -XMLPUBFUN int XMLCALL - xmlHashAddEntry3(xmlHashTablePtr table, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); +XMLPUBFUN int + xmlHashAddEntry3 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, void *userdata); -XMLPUBFUN int XMLCALL - xmlHashUpdateEntry3(xmlHashTablePtr table, +XMLPUBFUN int + xmlHashUpdateEntry3 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, void *userdata, - xmlHashDeallocator f); + xmlHashDeallocator dealloc); /* * 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); +XMLPUBFUN int + xmlHashRemoveEntry (xmlHashTablePtr hash, + const xmlChar *name, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashRemoveEntry2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashRemoveEntry3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashDeallocator dealloc); /* - * Retrieve the userdata. + * Retrieve the payload. */ -XMLPUBFUN void * XMLCALL - xmlHashLookup (xmlHashTablePtr table, +XMLPUBFUN void * + xmlHashLookup (xmlHashTablePtr hash, const xmlChar *name); -XMLPUBFUN void * XMLCALL - xmlHashLookup2 (xmlHashTablePtr table, +XMLPUBFUN void * + xmlHashLookup2 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2); -XMLPUBFUN void * XMLCALL - xmlHashLookup3 (xmlHashTablePtr table, +XMLPUBFUN void * + xmlHashLookup3 (xmlHashTablePtr hash, 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, +XMLPUBFUN void * + xmlHashQLookup (xmlHashTablePtr hash, + const xmlChar *prefix, + const xmlChar *name); +XMLPUBFUN void * + xmlHashQLookup2 (xmlHashTablePtr hash, const xmlChar *prefix, - const xmlChar *name2, - const xmlChar *prefix2); -XMLPUBFUN void * XMLCALL - xmlHashQLookup3 (xmlHashTablePtr table, const xmlChar *name, + const xmlChar *prefix2, + const xmlChar *name2); +XMLPUBFUN void * + xmlHashQLookup3 (xmlHashTablePtr hash, const xmlChar *prefix, - const xmlChar *name2, + const xmlChar *name, const xmlChar *prefix2, - const xmlChar *name3, - const xmlChar *prefix3); + const xmlChar *name2, + const xmlChar *prefix3, + const xmlChar *name3); /* * Helpers. */ -XMLPUBFUN xmlHashTablePtr XMLCALL - xmlHashCopy (xmlHashTablePtr table, - xmlHashCopier f); -XMLPUBFUN int XMLCALL - xmlHashSize (xmlHashTablePtr table); -XMLPUBFUN void XMLCALL - xmlHashScan (xmlHashTablePtr table, - xmlHashScanner f, +XMLPUBFUN xmlHashTablePtr + xmlHashCopySafe (xmlHashTablePtr hash, + xmlHashCopier copy, + xmlHashDeallocator dealloc); +XMLPUBFUN xmlHashTablePtr + xmlHashCopy (xmlHashTablePtr hash, + xmlHashCopier copy); +XMLPUBFUN int + xmlHashSize (xmlHashTablePtr hash); +XMLPUBFUN void + xmlHashScan (xmlHashTablePtr hash, + xmlHashScanner scan, void *data); -XMLPUBFUN void XMLCALL - xmlHashScan3 (xmlHashTablePtr table, +XMLPUBFUN void + xmlHashScan3 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, - xmlHashScanner f, + xmlHashScanner scan, void *data); -XMLPUBFUN void XMLCALL - xmlHashScanFull (xmlHashTablePtr table, - xmlHashScannerFull f, +XMLPUBFUN void + xmlHashScanFull (xmlHashTablePtr hash, + xmlHashScannerFull scan, void *data); -XMLPUBFUN void XMLCALL - xmlHashScanFull3(xmlHashTablePtr table, +XMLPUBFUN void + xmlHashScanFull3 (xmlHashTablePtr hash, const xmlChar *name, const xmlChar *name2, const xmlChar *name3, - xmlHashScannerFull f, + xmlHashScannerFull scan, void *data); #ifdef __cplusplus } diff --git a/include/libxml/list.h b/include/libxml/list.h index 3211c755247..1fa76aff084 100644 --- a/include/libxml/list.h +++ b/include/libxml/list.h @@ -52,79 +52,79 @@ typedef int (*xmlListDataCompare) (const void *data0, const void *data1); typedef int (*xmlListWalker) (const void *data, void *user); /* Creation/Deletion */ -XMLPUBFUN xmlListPtr XMLCALL +XMLPUBFUN xmlListPtr xmlListCreate (xmlListDeallocator deallocator, xmlListDataCompare compare); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListDelete (xmlListPtr l); /* Basic Operators */ -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlListSearch (xmlListPtr l, void *data); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlListReverseSearch (xmlListPtr l, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListInsert (xmlListPtr l, void *data) ; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListAppend (xmlListPtr l, void *data) ; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListRemoveFirst (xmlListPtr l, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListRemoveLast (xmlListPtr l, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListRemoveAll (xmlListPtr l, void *data); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListClear (xmlListPtr l); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListEmpty (xmlListPtr l); -XMLPUBFUN xmlLinkPtr XMLCALL +XMLPUBFUN xmlLinkPtr xmlListFront (xmlListPtr l); -XMLPUBFUN xmlLinkPtr XMLCALL +XMLPUBFUN xmlLinkPtr xmlListEnd (xmlListPtr l); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListSize (xmlListPtr l); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListPopFront (xmlListPtr l); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListPopBack (xmlListPtr l); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListPushFront (xmlListPtr l, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlListPushBack (xmlListPtr l, void *data); /* Advanced Operators */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListReverse (xmlListPtr l); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListSort (xmlListPtr l); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListWalk (xmlListPtr l, xmlListWalker walker, void *user); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListReverseWalk (xmlListPtr l, xmlListWalker walker, void *user); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlListMerge (xmlListPtr l1, xmlListPtr l2); -XMLPUBFUN xmlListPtr XMLCALL - xmlListDup (const xmlListPtr old); -XMLPUBFUN int XMLCALL +XMLPUBFUN xmlListPtr + xmlListDup (xmlListPtr old); +XMLPUBFUN int xmlListCopy (xmlListPtr cur, - const xmlListPtr old); + xmlListPtr old); /* Link operators */ -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlLinkGetData (xmlLinkPtr lk); /* xmlListUnique() */ diff --git a/include/libxml/nanoftp.h b/include/libxml/nanoftp.h index f39bde5be07..ed3ac4f1fd2 100644 --- a/include/libxml/nanoftp.h +++ b/include/libxml/nanoftp.h @@ -14,7 +14,7 @@ #include -#ifdef LIBXML_FTP_ENABLED +#if defined(LIBXML_FTP_ENABLED) /* Needed for portability to Windows 64 bits */ #if defined(_WIN32) @@ -80,52 +80,52 @@ typedef void (*ftpDataCallback) (void *userData, * Init */ XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNanoFTPInit (void); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNanoFTPCleanup (void); /* * Creating/freeing contexts. */ XML_DEPRECATED -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlNanoFTPNewCtxt (const char *URL); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNanoFTPFreeCtxt (void * ctx); XML_DEPRECATED -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlNanoFTPConnectTo (const char *server, int port); /* * Opening/closing session connections. */ XML_DEPRECATED -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlNanoFTPOpen (const char *URL); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPConnect (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPClose (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPQuit (void *ctx); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNanoFTPScanProxy (const char *URL); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNanoFTPProxy (const char *host, int port, const char *user, const char *passwd, int type); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPUpdateURL (void *ctx, const char *URL); @@ -133,48 +133,48 @@ XMLPUBFUN int XMLCALL * Rather internal commands. */ XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPGetResponse (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPCheckResponse (void *ctx); /* * CD/DIR/GET handlers. */ XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPCwd (void *ctx, const char *directory); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPDele (void *ctx, const char *file); XML_DEPRECATED -XMLPUBFUN SOCKET XMLCALL +XMLPUBFUN SOCKET xmlNanoFTPGetConnection (void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPCloseConnection(void *ctx); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPList (void *ctx, ftpListCallback callback, void *userData, const char *filename); XML_DEPRECATED -XMLPUBFUN SOCKET XMLCALL +XMLPUBFUN SOCKET xmlNanoFTPGetSocket (void *ctx, const char *filename); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPGet (void *ctx, ftpDataCallback callback, void *userData, const char *filename); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNanoFTPRead (void *ctx, void *dest, int len); @@ -182,5 +182,5 @@ XMLPUBFUN int XMLCALL #ifdef __cplusplus } #endif -#endif /* LIBXML_FTP_ENABLED */ +#endif /* defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */ #endif /* __NANO_FTP_H__ */ diff --git a/include/libxml/nanohttp.h b/include/libxml/nanohttp.h index 22b8fb43381..c70d1c26bb8 100644 --- a/include/libxml/nanohttp.h +++ b/include/libxml/nanohttp.h @@ -18,24 +18,30 @@ #ifdef __cplusplus extern "C" { #endif -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlNanoHTTPInit (void); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlNanoHTTPCleanup (void); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlNanoHTTPScanProxy (const char *URL); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlNanoHTTPFetch (const char *URL, const char *filename, char **contentType); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlNanoHTTPMethod (const char *URL, const char *method, const char *input, char **contentType, const char *headers, int ilen); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlNanoHTTPMethodRedir (const char *URL, const char *method, const char *input, @@ -43,35 +49,46 @@ XMLPUBFUN void * XMLCALL char **redir, const char *headers, int ilen); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlNanoHTTPOpen (const char *URL, char **contentType); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlNanoHTTPOpenRedir (const char *URL, char **contentType, char **redir); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlNanoHTTPReturnCode (void *ctx); -XMLPUBFUN const char * XMLCALL +XML_DEPRECATED +XMLPUBFUN const char * xmlNanoHTTPAuthHeader (void *ctx); -XMLPUBFUN const char * XMLCALL +XML_DEPRECATED +XMLPUBFUN const char * xmlNanoHTTPRedir (void *ctx); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlNanoHTTPContentLength( void * ctx ); -XMLPUBFUN const char * XMLCALL +XML_DEPRECATED +XMLPUBFUN const char * xmlNanoHTTPEncoding (void *ctx); -XMLPUBFUN const char * XMLCALL +XML_DEPRECATED +XMLPUBFUN const char * xmlNanoHTTPMimeType (void *ctx); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlNanoHTTPRead (void *ctx, void *dest, int len); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlNanoHTTPSave (void *ctxt, const char *filename); #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlNanoHTTPClose (void *ctx); #ifdef __cplusplus } diff --git a/include/libxml/parser.h b/include/libxml/parser.h index 82c61d67e92..831aa53b423 100644 --- a/include/libxml/parser.h +++ b/include/libxml/parser.h @@ -10,14 +10,24 @@ #ifndef __XML_PARSER_H__ #define __XML_PARSER_H__ +/** DOC_DISABLE */ #include +#define XML_TREE_INTERNALS #include +#undef XML_TREE_INTERNALS #include #include #include #include #include #include +#include +#include +#include +/* for compatibility */ +#include +#include +/** DOC_ENABLE */ #ifdef __cplusplus extern "C" { @@ -54,24 +64,21 @@ struct _xmlParserInput { xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ const char *filename; /* The file analyzed, if any */ - const char *directory; /* the directory/base of the file */ + const char *directory; /* unused */ const xmlChar *base; /* Base of the array to parse */ const xmlChar *cur; /* Current char being parsed */ const xmlChar *end; /* end of the array to parse */ - int length; /* length if known */ + int length; /* unused */ int line; /* Current line */ int col; /* Current column */ - /* - * 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 *encoding; /* unused */ const xmlChar *version; /* the version string for entity */ - int standalone; /* Was that entity marked standalone */ + int flags; /* Flags */ int id; /* an unique identifier for the entity */ + unsigned long parentConsumed; /* unused */ + xmlEntityPtr entity; /* entity, if any */ }; /** @@ -125,33 +132,18 @@ typedef enum { 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 */ + XML_PARSER_PUBLIC_LITERAL, /* within a PUBLIC value */ + XML_PARSER_XML_DECL /* before XML decl (but after BOM) */ } xmlParserInputState; -/** - * XML_DETECT_IDS: - * - * Bit in the loadsubset context field to tell to do ID/REFs lookups. - * Use it to initialize xmlLoadExtDtdDefaultValue. +/** DOC_DISABLE */ +/* + * Internal bits in the 'loadsubset' context member */ #define XML_DETECT_IDS 2 - -/** - * XML_COMPLETE_ATTRS: - * - * Bit in the loadsubset context field to tell to do complete the - * elements attributes lists with the ones defaulted from the DTDs. - * Use it to initialize xmlLoadExtDtdDefaultValue. - */ #define XML_COMPLETE_ATTRS 4 - -/** - * XML_SKIP_IDS: - * - * Bit in the loadsubset context field to tell to not do ID/REFs registration. - * Used to initialize xmlLoadExtDtdDefaultValue in some special cases. - */ #define XML_SKIP_IDS 8 +/** DOC_ENABLE */ /** * xmlParserMode: @@ -168,6 +160,8 @@ typedef enum { } xmlParserMode; typedef struct _xmlStartTag xmlStartTag; +typedef struct _xmlParserNsData xmlParserNsData; +typedef struct _xmlAttrHashBucket xmlAttrHashBucket; /** * xmlParserCtxt: @@ -214,16 +208,16 @@ struct _xmlParserCtxt { int hasExternalSubset; /* reference and external subset */ int hasPErefs; /* the internal subset has PE refs */ - int external; /* are we parsing an external entity */ + int external; /* unused */ int valid; /* is the document valid */ int validate; /* shall we try to validate ? */ xmlValidCtxt vctxt; /* The validity context */ - xmlParserInputState instate; /* current type of input */ - int token; /* next char look-ahead */ + xmlParserInputState instate; /* push parser state */ + int token; /* unused */ - char *directory; /* the data directory */ + char *directory; /* unused */ /* Node name stack */ const xmlChar *name; /* Current parsed Node */ @@ -247,9 +241,8 @@ struct _xmlParserCtxt { 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 */ + xmlParserInputPtr entity; /* unused */ + int charset; /* unused */ int nodelen; /* Those two fields are there to */ int nodemem; /* Speed up large node parsing */ int pedantic; /* signal pedantic warnings */ @@ -259,11 +252,11 @@ struct _xmlParserCtxt { int linenumbers; /* set line number in element content */ void *catalogs; /* document's own catalog */ int recovery; /* run in recovery mode */ - int progressive; /* is this a progressive parsing */ + int progressive; /* unused */ xmlDictPtr dict; /* dictionary for the parser */ const xmlChar * *atts; /* array for the attributes callbacks */ int maxatts; /* the size of the array */ - int docdict; /* use strings from dict to build tree */ + int docdict; /* unused */ /* * pre-interned strings @@ -279,7 +272,7 @@ struct _xmlParserCtxt { 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 */ + unsigned *attallocs; /* which attribute were allocated */ xmlStartTag *pushTab; /* array of data for push */ xmlHashTablePtr attsDefault; /* defaulted attributes if any */ xmlHashTablePtr attsSpecial; /* non-CDATA attributes if any */ @@ -300,8 +293,8 @@ struct _xmlParserCtxt { */ xmlError lastError; xmlParserMode parseMode; /* the parser mode */ - unsigned long nbentities; /* number of entities references */ - unsigned long sizeentities; /* size of parsed entities */ + unsigned long nbentities; /* unused */ + unsigned long sizeentities; /* size of external entities */ /* for use by HTML non-recursive parser */ xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ @@ -311,6 +304,18 @@ struct _xmlParserCtxt { int input_id; /* we need to label inputs */ unsigned long sizeentcopy; /* volume of entity copy */ + + int endCheckState; /* quote state for push parser */ + unsigned short nbErrors; /* number of errors */ + unsigned short nbWarnings; /* number of warnings */ + unsigned maxAmpl; /* maximum amplification factor */ + + xmlParserNsData *nsdb; /* namespace database */ + unsigned attrHashMax; /* allocated size */ + xmlAttrHashBucket *attrHash; /* atttribute hash table */ + + xmlStructuredErrorFunc errorHandler; + void *errorCtxt; }; /** @@ -605,7 +610,7 @@ typedef void (*cdataBlockSAXFunc) ( * * Display and format a warning messages, callback. */ -typedef void (XMLCDECL *warningSAXFunc) (void *ctx, +typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** * errorSAXFunc: @@ -615,7 +620,7 @@ typedef void (XMLCDECL *warningSAXFunc) (void *ctx, * * Display and format an error messages, callback. */ -typedef void (XMLCDECL *errorSAXFunc) (void *ctx, +typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** * fatalErrorSAXFunc: @@ -627,7 +632,7 @@ typedef void (XMLCDECL *errorSAXFunc) (void *ctx, * Note: so far fatalError() SAX callbacks are not used, error() * get all the callbacks for errors. */ -typedef void (XMLCDECL *fatalErrorSAXFunc) (void *ctx, +typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** * isStandaloneSAXFunc: @@ -731,6 +736,19 @@ struct _xmlSAXHandler { setDocumentLocatorSAXFunc setDocumentLocator; startDocumentSAXFunc startDocument; endDocumentSAXFunc endDocument; + /* + * `startElement` and `endElement` are only used by the legacy SAX1 + * interface and should not be used in new software. If you really + * have to enable SAX1, the preferred way is set the `initialized` + * member to 1 instead of XML_SAX2_MAGIC. + * + * For backward compatibility, it's also possible to set the + * `startElementNs` and `endElementNs` handlers to NULL. + * + * You can also set the XML_PARSE_SAX1 parser option, but versions + * older than 2.12.0 will probably crash if this option is provided + * together with custom SAX callbacks. + */ startElementSAXFunc startElement; endElementSAXFunc endElement; referenceSAXFunc reference; @@ -744,8 +762,14 @@ struct _xmlSAXHandler { getParameterEntitySAXFunc getParameterEntity; cdataBlockSAXFunc cdataBlock; externalSubsetSAXFunc externalSubset; + /* + * `initialized` should always be set to XML_SAX2_MAGIC to enable the + * modern SAX2 interface. + */ unsigned int initialized; - /* The following fields are extensions available only on version 2 */ + /* + * The following members are only used by the SAX2 interface. + */ void *_private; startElementNsSAX2Func startElementNs; endElementNsSAX2Func endElementNs; @@ -803,34 +827,119 @@ typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL, const char *ID, xmlParserCtxtPtr context); -#ifdef __cplusplus -} +/* + * Variables + */ + +XMLPUBVAR const char *const xmlParserVersion; +XML_DEPRECATED +XMLPUBVAR const int oldXMLWDcompatibility; +XML_DEPRECATED +XMLPUBVAR const int xmlParserDebugEntities; +XML_DEPRECATED +XMLPUBVAR const xmlSAXLocator xmlDefaultSAXLocator; +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 xmlDefaultSAXHandler; #endif -#include -#include -#include +#ifdef LIBXML_THREAD_ENABLED +/* backward compatibility */ +XMLPUBFUN const char *const *__xmlParserVersion(void); +XML_DEPRECATED +XMLPUBFUN const int *__oldXMLWDcompatibility(void); +XML_DEPRECATED +XMLPUBFUN const int *__xmlParserDebugEntities(void); +XML_DEPRECATED +XMLPUBFUN const xmlSAXLocator *__xmlDefaultSAXLocator(void); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__xmlDefaultSAXHandler(void); +#endif +#endif -#ifdef __cplusplus -extern "C" { +/** DOC_DISABLE */ +#define XML_GLOBALS_PARSER_CORE \ + XML_OP(xmlDoValidityCheckingDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlGetWarningsDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlKeepBlanksDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlLineNumbersDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlLoadExtDtdDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlPedanticParserDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlSubstituteEntitiesDefaultValue, int, XML_DEPRECATED) + +#ifdef LIBXML_OUTPUT_ENABLED + #define XML_GLOBALS_PARSER_OUTPUT \ + XML_OP(xmlIndentTreeOutput, int, XML_NO_ATTR) \ + XML_OP(xmlTreeIndentString, const char *, XML_NO_ATTR) \ + XML_OP(xmlSaveNoEmptyTags, int, XML_NO_ATTR) +#else + #define XML_GLOBALS_PARSER_OUTPUT #endif +#define XML_GLOBALS_PARSER \ + XML_GLOBALS_PARSER_CORE \ + XML_GLOBALS_PARSER_OUTPUT + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_PARSER +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlDoValidityCheckingDefaultValue \ + XML_GLOBAL_MACRO(xmlDoValidityCheckingDefaultValue) + #define xmlGetWarningsDefaultValue \ + XML_GLOBAL_MACRO(xmlGetWarningsDefaultValue) + #define xmlKeepBlanksDefaultValue XML_GLOBAL_MACRO(xmlKeepBlanksDefaultValue) + #define xmlLineNumbersDefaultValue \ + XML_GLOBAL_MACRO(xmlLineNumbersDefaultValue) + #define xmlLoadExtDtdDefaultValue XML_GLOBAL_MACRO(xmlLoadExtDtdDefaultValue) + #define xmlPedanticParserDefaultValue \ + XML_GLOBAL_MACRO(xmlPedanticParserDefaultValue) + #define xmlSubstituteEntitiesDefaultValue \ + XML_GLOBAL_MACRO(xmlSubstituteEntitiesDefaultValue) + #ifdef LIBXML_OUTPUT_ENABLED + #define xmlIndentTreeOutput XML_GLOBAL_MACRO(xmlIndentTreeOutput) + #define xmlTreeIndentString XML_GLOBAL_MACRO(xmlTreeIndentString) + #define xmlSaveNoEmptyTags XML_GLOBAL_MACRO(xmlSaveNoEmptyTags) + #endif +#else +#define xmlDoValidityCheckingDefaultValue vtklibxml2_xmlDoValidityCheckingDefaultValue +#define xmlGetWarningsDefaultValue vtklibxml2_xmlGetWarningsDefaultValue +#define xmlKeepBlanksDefaultValue vtklibxml2_xmlKeepBlanksDefaultValue +#define xmlLineNumbersDefaultValue vtklibxml2_xmlLineNumbersDefaultValue +#define xmlLoadExtDtdDefaultValue vtklibxml2_xmlLoadExtDtdDefaultValue +#define xmlPedanticParserDefaultValue vtklibxml2_xmlPedanticParserDefaultValue +#define xmlSubstituteEntitiesDefaultValue vtklibxml2_xmlSubstituteEntitiesDefaultValue +#define xmlIndentTreeOutput vtklibxml2_xmlIndentTreeOutput +#define xmlTreeIndentString vtklibxml2_xmlTreeIndentString +#define xmlSaveNoEmptyTags vtklibxml2_xmlSaveNoEmptyTags +#endif +/** DOC_ENABLE */ /* * Init/Cleanup */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlInitParser (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupParser (void); +XML_DEPRECATED +XMLPUBFUN void + xmlInitGlobals (void); +XML_DEPRECATED +XMLPUBFUN void + xmlCleanupGlobals (void); /* * Input functions */ -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParserInputRead (xmlParserInputPtr in, int len); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParserInputGrow (xmlParserInputPtr in, int len); @@ -838,101 +947,130 @@ XMLPUBFUN int XMLCALL * Basic parsing Interfaces */ #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlParseDoc (const xmlChar *cur); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlParseFile (const char *filename); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlParseMemory (const char *buffer, int size); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN int XMLCALL +XML_DEPRECATED XMLPUBFUN int xmlSubstituteEntitiesDefault(int val); -XMLPUBFUN int XMLCALL +XML_DEPRECATED XMLPUBFUN int + xmlThrDefSubstituteEntitiesDefaultValue(int v); +XMLPUBFUN int xmlKeepBlanksDefault (int val); -XMLPUBFUN void XMLCALL +XML_DEPRECATED XMLPUBFUN int + xmlThrDefKeepBlanksDefaultValue(int v); +XMLPUBFUN void xmlStopParser (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XML_DEPRECATED XMLPUBFUN int xmlPedanticParserDefault(int val); -XMLPUBFUN int XMLCALL +XML_DEPRECATED XMLPUBFUN int + xmlThrDefPedanticParserDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int xmlLineNumbersDefault (int val); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefLineNumbersDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefDoValidityCheckingDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefGetWarningsDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefLoadExtDtdDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefParserDebugEntities(int v); #ifdef LIBXML_SAX1_ENABLED /* * Recovery mode */ -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlRecoverDoc (const xmlChar *cur); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlRecoverMemory (const char *buffer, int size); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlRecoverFile (const char *filename); #endif /* LIBXML_SAX1_ENABLED */ /* * Less common routines and SAX interfaces */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseDocument (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseExtParsedEnt (xmlParserCtxtPtr ctxt); #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlSAXUserParseFile (xmlSAXHandlerPtr sax, void *user_data, const char *filename); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlSAXUserParseMemory (xmlSAXHandlerPtr sax, void *user_data, const char *buffer, int size); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseDoc (xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseMemory (xmlSAXHandlerPtr sax, const char *buffer, int size, int recovery); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseMemoryWithData (xmlSAXHandlerPtr sax, const char *buffer, int size, int recovery, void *data); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseFile (xmlSAXHandlerPtr sax, const char *filename, int recovery); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseFileWithData (xmlSAXHandlerPtr sax, const char *filename, int recovery, void *data); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlSAXParseEntity (xmlSAXHandlerPtr sax, const char *filename); -XMLPUBFUN xmlDocPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDocPtr xmlParseEntity (const char *filename); #endif /* LIBXML_SAX1_ENABLED */ #ifdef LIBXML_VALID_ENABLED -XMLPUBFUN xmlDtdPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlDtdPtr xmlSAXParseDTD (xmlSAXHandlerPtr sax, const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlParseDTD (const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlIOParseDTD (xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlCharEncoding enc); #endif /* LIBXML_VALID_ENABLE */ #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, @@ -940,14 +1078,14 @@ XMLPUBFUN int XMLCALL const xmlChar *string, xmlNodePtr *lst); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN xmlParserErrors XMLCALL +XMLPUBFUN xmlParserErrors xmlParseInNodeContext (xmlNodePtr node, const char *data, int datalen, int options, xmlNodePtr *lst); #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, @@ -955,7 +1093,8 @@ XMLPUBFUN int XMLCALL const xmlChar *string, xmlNodePtr *lst, int recover); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseExternalEntity (xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, @@ -964,7 +1103,7 @@ XMLPUBFUN int XMLCALL const xmlChar *ID, xmlNodePtr *lst); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, const xmlChar *ID, @@ -973,21 +1112,25 @@ XMLPUBFUN int XMLCALL /* * Parser contexts handling. */ -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlNewParserCtxt (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN xmlParserCtxtPtr + xmlNewSAXParserCtxt (const xmlSAXHandler *sax, + void *userData); +XMLPUBFUN int xmlInitParserCtxt (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlClearParserCtxt (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeParserCtxt (xmlParserCtxtPtr ctxt); #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlSetupParserForBuffer (xmlParserCtxtPtr ctxt, const xmlChar* buffer, const char *filename); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateDocParserCtxt (const xmlChar *cur); #ifdef LIBXML_LEGACY_ENABLED @@ -995,16 +1138,16 @@ XMLPUBFUN xmlParserCtxtPtr XMLCALL * Reading/setting optional parsing features. */ XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGetFeaturesList (int *len, const char **result); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGetFeature (xmlParserCtxtPtr ctxt, const char *name, void *result); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSetFeature (xmlParserCtxtPtr ctxt, const char *name, void *value); @@ -1014,13 +1157,13 @@ XMLPUBFUN int XMLCALL /* * Interfaces for the Push mode. */ -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseChunk (xmlParserCtxtPtr ctxt, const char *chunk, int size, @@ -1031,7 +1174,7 @@ XMLPUBFUN int XMLCALL * Special I/O mode. */ -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateIOParserCtxt (xmlSAXHandlerPtr sax, void *user_data, xmlInputReadCallback ioread, @@ -1039,7 +1182,7 @@ XMLPUBFUN xmlParserCtxtPtr XMLCALL void *ioctx, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlNewIOInputStream (xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr input, xmlCharEncoding enc); @@ -1047,29 +1190,29 @@ XMLPUBFUN xmlParserInputPtr XMLCALL /* * Node infos. */ -XMLPUBFUN const xmlParserNodeInfo* XMLCALL - xmlParserFindNodeInfo (const xmlParserCtxtPtr ctxt, - const xmlNodePtr node); -XMLPUBFUN void XMLCALL +XMLPUBFUN const xmlParserNodeInfo* + xmlParserFindNodeInfo (xmlParserCtxtPtr ctxt, + xmlNodePtr node); +XMLPUBFUN void xmlInitNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlClearNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); -XMLPUBFUN unsigned long XMLCALL - xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, - const xmlNodePtr node); -XMLPUBFUN void XMLCALL +XMLPUBFUN unsigned long + xmlParserFindNodeInfoIndex(xmlParserNodeInfoSeqPtr seq, + xmlNodePtr node); +XMLPUBFUN void xmlParserAddNodeInfo (xmlParserCtxtPtr ctxt, - const xmlParserNodeInfoPtr info); + xmlParserNodeInfoPtr info); /* * External entities handling actually implemented in xmlIO. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetExternalEntityLoader(xmlExternalEntityLoader f); -XMLPUBFUN xmlExternalEntityLoader XMLCALL +XMLPUBFUN xmlExternalEntityLoader xmlGetExternalEntityLoader(void); -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlLoadExternalEntity (const char *URL, const char *ID, xmlParserCtxtPtr ctxt); @@ -1077,7 +1220,7 @@ XMLPUBFUN xmlParserInputPtr XMLCALL /* * Index lookup, actually implemented in the encoding module */ -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlByteConsumed (xmlParserCtxtPtr ctxt); /* @@ -1114,72 +1257,86 @@ typedef enum { XML_PARSE_HUGE = 1<<19,/* relax any hardcoded limit from the parser */ XML_PARSE_OLDSAX = 1<<20,/* parse using SAX2 interface before 2.7.0 */ XML_PARSE_IGNORE_ENC= 1<<21,/* ignore internal document encoding hint */ - XML_PARSE_BIG_LINES = 1<<22 /* Store big lines numbers in text PSVI field */ + XML_PARSE_BIG_LINES = 1<<22,/* Store big lines numbers in text PSVI field */ + XML_PARSE_NO_XXE = 1<<23 /* disable loading of external content */ } xmlParserOption; -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCtxtReset (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCtxtResetPush (xmlParserCtxtPtr ctxt, const char *chunk, int size, const char *filename, const char *encoding); -XMLPUBFUN int XMLCALL +XMLPUBFUN int + xmlCtxtSetOptions (xmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN int xmlCtxtUseOptions (xmlParserCtxtPtr ctxt, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN void + xmlCtxtSetErrorHandler (xmlParserCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); +XMLPUBFUN void + xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, + unsigned maxAmpl); +XMLPUBFUN xmlDocPtr xmlReadDoc (const xmlChar *cur, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlReadFile (const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlReadMemory (const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlReadFd (int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlReadIO (xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr + xmlCtxtParseDocument (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN xmlDocPtr xmlCtxtReadDoc (xmlParserCtxtPtr ctxt, const xmlChar *cur, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlCtxtReadFile (xmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlCtxtReadMemory (xmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlCtxtReadFd (xmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlCtxtReadIO (xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, @@ -1228,14 +1385,14 @@ typedef enum { XML_WITH_MODULES = 27, XML_WITH_DEBUG = 28, XML_WITH_DEBUG_MEM = 29, - XML_WITH_DEBUG_RUN = 30, + XML_WITH_DEBUG_RUN = 30, /* unused */ XML_WITH_ZLIB = 31, XML_WITH_ICU = 32, XML_WITH_LZMA = 33, XML_WITH_NONE = 99999 /* just to be sure of allocation size */ } xmlFeature; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlHasFeature (xmlFeature feature); #ifdef __cplusplus diff --git a/include/libxml/parserInternals.h b/include/libxml/parserInternals.h index 656ee4625c3..c4d4363b53a 100644 --- a/include/libxml/parserInternals.h +++ b/include/libxml/parserInternals.h @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -24,11 +25,14 @@ extern "C" { /** * xmlParserMaxDepth: * + * DEPRECATED: has no effect + * * arbitrary depth limit for the XML documents that we allow to * process. This is not a limitation of the parser but a safety * boundary feature, use XML_PARSE_HUGE option to override it. */ -XMLPUBVAR unsigned int xmlParserMaxDepth; +XML_DEPRECATED +XMLPUBVAR const unsigned int xmlParserMaxDepth; /** * XML_MAX_TEXT_LENGTH: @@ -40,6 +44,13 @@ XMLPUBVAR unsigned int xmlParserMaxDepth; */ #define XML_MAX_TEXT_LENGTH 10000000 +/** + * XML_MAX_HUGE_LENGTH: + * + * Maximum size allowed when XML_PARSE_HUGE is set. + */ +#define XML_MAX_HUGE_LENGTH 1000000000 + /** * XML_MAX_NAME_LENGTH: * @@ -278,34 +289,6 @@ XMLPUBVAR unsigned int xmlParserMaxDepth; */ #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. */ @@ -316,71 +299,67 @@ XMLPUBVAR const xmlChar xmlStringComment[]; /* * Function to finish the work of the macros where needed. */ -XMLPUBFUN int XMLCALL xmlIsLetter (int c); +XMLPUBFUN int xmlIsLetter (int c); /** * Parser context. */ -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateFileParserCtxt (const char *filename); -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateURLParserCtxt (const char *filename, int options); -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateMemoryParserCtxt(const char *buffer, int size); -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, const xmlChar *base); -XMLPUBFUN int XMLCALL +XMLPUBFUN void + xmlCtxtErrMemory (xmlParserCtxtPtr ctxt); +XMLPUBFUN int xmlSwitchEncoding (xmlParserCtxtPtr ctxt, xmlCharEncoding enc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int + xmlSwitchEncodingName (xmlParserCtxtPtr ctxt, + const char *encoding); +XMLPUBFUN int xmlSwitchToEncoding (xmlParserCtxtPtr ctxt, xmlCharEncodingHandlerPtr handler); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int 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) LIBXML_ATTR_FORMAT(3,0); -#endif - /** * Input Streams. */ -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlNewStringInputStream (xmlParserCtxtPtr ctxt, const xmlChar *buffer); -XMLPUBFUN xmlParserInputPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlParserInputPtr xmlNewEntityInputStream (xmlParserCtxtPtr ctxt, xmlEntityPtr entity); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPushInput (xmlParserCtxtPtr ctxt, xmlParserInputPtr input); -XMLPUBFUN xmlChar XMLCALL +XMLPUBFUN xmlChar xmlPopInput (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeInputStream (xmlParserInputPtr input); -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlNewInputFromFile (xmlParserCtxtPtr ctxt, const char *filename); -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr xmlNewInputStream (xmlParserCtxtPtr ctxt); /** * Namespaces. */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlSplitQName (xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix); @@ -388,109 +367,151 @@ XMLPUBFUN xmlChar * XMLCALL /** * Generic production rules. */ -XMLPUBFUN const xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN const xmlChar * xmlParseName (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseNmtoken (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseEntityValue (xmlParserCtxtPtr ctxt, xmlChar **orig); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseAttValue (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseSystemLiteral (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParsePubidLiteral (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseCharData (xmlParserCtxtPtr ctxt, int cdata); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseExternalID (xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseComment (xmlParserCtxtPtr ctxt); -XMLPUBFUN const xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN const xmlChar * xmlParsePITarget (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParsePI (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseNotationDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseEntityDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseDefaultDecl (xmlParserCtxtPtr ctxt, xmlChar **value); -XMLPUBFUN xmlEnumerationPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlEnumerationPtr xmlParseNotationType (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlEnumerationPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlEnumerationPtr xmlParseEnumerationType (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseEnumeratedType (xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseAttributeType (xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlElementContentPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlElementContentPtr xmlParseElementMixedContentDecl (xmlParserCtxtPtr ctxt, int inputchk); -XMLPUBFUN xmlElementContentPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlElementContentPtr xmlParseElementChildrenContentDecl (xmlParserCtxtPtr ctxt, int inputchk); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlElementContentPtr *result); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseElementDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseMarkupDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseCharRef (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlEntityPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlEntityPtr xmlParseEntityRef (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseReference (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParsePEReference (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseDocTypeDecl (xmlParserCtxtPtr ctxt); #ifdef LIBXML_SAX1_ENABLED -XMLPUBFUN const xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN const xmlChar * xmlParseAttribute (xmlParserCtxtPtr ctxt, xmlChar **value); -XMLPUBFUN const xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN const xmlChar * xmlParseStartTag (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseEndTag (xmlParserCtxtPtr ctxt); #endif /* LIBXML_SAX1_ENABLED */ -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseCDSect (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlParseContent (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseElement (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseVersionNum (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseVersionInfo (xmlParserCtxtPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlParseEncName (xmlParserCtxtPtr ctxt); -XMLPUBFUN const xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN const xmlChar * xmlParseEncodingDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlParseSDDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseXMLDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseTextDecl (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlParseMisc (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlParseExternalSubset (xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, const xmlChar *SystemID); @@ -519,14 +540,16 @@ XMLPUBFUN void XMLCALL */ #define XML_SUBSTITUTE_BOTH 3 -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlStringDecodeEntities (xmlParserCtxtPtr ctxt, const xmlChar *str, int what, xmlChar end, xmlChar end2, xmlChar end3); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlStringLenDecodeEntities (xmlParserCtxtPtr ctxt, const xmlChar *str, int len, @@ -538,48 +561,49 @@ XMLPUBFUN xmlChar * XMLCALL /* * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP. */ -XMLPUBFUN int XMLCALL nodePush (xmlParserCtxtPtr ctxt, +XML_DEPRECATED +XMLPUBFUN int nodePush (xmlParserCtxtPtr ctxt, xmlNodePtr value); -XMLPUBFUN xmlNodePtr XMLCALL nodePop (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL inputPush (xmlParserCtxtPtr ctxt, +XML_DEPRECATED +XMLPUBFUN xmlNodePtr nodePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int inputPush (xmlParserCtxtPtr ctxt, xmlParserInputPtr value); -XMLPUBFUN xmlParserInputPtr XMLCALL inputPop (xmlParserCtxtPtr ctxt); -XMLPUBFUN const xmlChar * XMLCALL namePop (xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL namePush (xmlParserCtxtPtr ctxt, +XMLPUBFUN xmlParserInputPtr inputPop (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN const xmlChar * namePop (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int 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, +XML_DEPRECATED +XMLPUBFUN int xmlSkipBlankChars (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int xmlStringCurrentChar (xmlParserCtxtPtr ctxt, const xmlChar *cur, int *len); -XMLPUBFUN void XMLCALL xmlParserHandlePEReference(xmlParserCtxtPtr ctxt); -XMLPUBFUN int XMLCALL xmlCheckLanguageID (const xmlChar *lang); +XML_DEPRECATED +XMLPUBFUN void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int xmlCheckLanguageID (const xmlChar *lang); /* * Really core function shared with HTML parser. */ -XMLPUBFUN int XMLCALL xmlCurrentChar (xmlParserCtxtPtr ctxt, +XML_DEPRECATED +XMLPUBFUN int xmlCurrentChar (xmlParserCtxtPtr ctxt, int *len); -XMLPUBFUN int XMLCALL xmlCopyCharMultiByte (xmlChar *out, +XMLPUBFUN int xmlCopyCharMultiByte (xmlChar *out, int val); -XMLPUBFUN int XMLCALL xmlCopyChar (int len, +XMLPUBFUN int xmlCopyChar (int len, xmlChar *out, int val); -XMLPUBFUN void XMLCALL xmlNextChar (xmlParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL xmlParserInputShrink (xmlParserInputPtr in); - -#ifdef LIBXML_HTML_ENABLED -/* - * Actually comes from the HTML parser but launched from the init stuff. - */ XML_DEPRECATED -XMLPUBFUN void XMLCALL htmlInitAutoClose (void); -XMLPUBFUN htmlParserCtxtPtr XMLCALL htmlCreateFileParserCtxt(const char *filename, - const char *encoding); -#endif +XMLPUBFUN void xmlNextChar (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void xmlParserInputShrink (xmlParserInputPtr in); /* * Specific function to keep track of entities references @@ -600,34 +624,34 @@ typedef void (*xmlEntityReferenceFunc) (xmlEntityPtr ent, xmlNodePtr lastNode); XML_DEPRECATED -XMLPUBFUN void XMLCALL xmlSetEntityReferenceFunc (xmlEntityReferenceFunc func); +XMLPUBFUN void xmlSetEntityReferenceFunc (xmlEntityReferenceFunc func); XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlParseQuotedString (xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlParseNamespace (xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNamespaceParseNSDef (xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlScanName (xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNamespaceParseNCName (xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN void XMLCALL xmlParserHandleReference(xmlParserCtxtPtr ctxt); +XMLPUBFUN void xmlParserHandleReference(xmlParserCtxtPtr ctxt); XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNamespaceParseQName (xmlParserCtxtPtr ctxt, xmlChar **prefix); /** * Entities */ XML_DEPRECATED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlDecodeEntities (xmlParserCtxtPtr ctxt, int len, int what, @@ -635,21 +659,12 @@ XMLPUBFUN xmlChar * XMLCALL xmlChar end2, xmlChar end3); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void 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 diff --git a/include/libxml/pattern.h b/include/libxml/pattern.h index 97d2cd2bc08..947f0900a23 100644 --- a/include/libxml/pattern.h +++ b/include/libxml/pattern.h @@ -43,18 +43,24 @@ typedef enum { XML_PATTERN_XSFIELD = 1<<2 /* XPath subset for schema field */ } xmlPatternFlags; -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreePattern (xmlPatternPtr comp); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreePatternList (xmlPatternPtr comp); -XMLPUBFUN xmlPatternPtr XMLCALL +XMLPUBFUN xmlPatternPtr xmlPatterncompile (const xmlChar *pattern, xmlDict *dict, int flags, const xmlChar **namespaces); -XMLPUBFUN int XMLCALL +XMLPUBFUN int + xmlPatternCompileSafe (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces, + xmlPatternPtr *patternOut); +XMLPUBFUN int xmlPatternMatch (xmlPatternPtr comp, xmlNodePtr node); @@ -62,34 +68,34 @@ XMLPUBFUN int XMLCALL typedef struct _xmlStreamCtxt xmlStreamCtxt; typedef xmlStreamCtxt *xmlStreamCtxtPtr; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPatternStreamable (xmlPatternPtr comp); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPatternMaxDepth (xmlPatternPtr comp); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPatternMinDepth (xmlPatternPtr comp); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPatternFromRoot (xmlPatternPtr comp); -XMLPUBFUN xmlStreamCtxtPtr XMLCALL +XMLPUBFUN xmlStreamCtxtPtr xmlPatternGetStreamCtxt (xmlPatternPtr comp); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeStreamCtxt (xmlStreamCtxtPtr stream); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStreamPushNode (xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns, int nodeType); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStreamPush (xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStreamPushAttr (xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStreamPop (xmlStreamCtxtPtr stream); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStreamWantsAnyNode (xmlStreamCtxtPtr stream); #ifdef __cplusplus } diff --git a/include/libxml/relaxng.h b/include/libxml/relaxng.h index 6369785cef0..079b7f125d0 100644 --- a/include/libxml/relaxng.h +++ b/include/libxml/relaxng.h @@ -11,8 +11,9 @@ #define __XML_RELAX_NG__ #include -#include +#include #include +#include #ifdef LIBXML_SCHEMAS_ENABLED @@ -32,7 +33,7 @@ typedef xmlRelaxNG *xmlRelaxNGPtr; * * Signature of an error callback from a Relax-NG validation */ -typedef void (XMLCDECL *xmlRelaxNGValidityErrorFunc) (void *ctx, +typedef void (*xmlRelaxNGValidityErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); @@ -44,7 +45,7 @@ typedef void (XMLCDECL *xmlRelaxNGValidityErrorFunc) (void *ctx, * * Signature of a warning callback from a Relax-NG validation */ -typedef void (XMLCDECL *xmlRelaxNGValidityWarningFunc) (void *ctx, +typedef void (*xmlRelaxNGValidityWarningFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); @@ -116,95 +117,95 @@ typedef enum { XML_RELAXNGP_CRNG = 2 } xmlRelaxNGParserFlag; -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGInitTypes (void); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGCleanupTypes (void); /* * Interfaces for parsing. */ -XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL +XMLPUBFUN xmlRelaxNGParserCtxtPtr xmlRelaxNGNewParserCtxt (const char *URL); -XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL +XMLPUBFUN xmlRelaxNGParserCtxtPtr xmlRelaxNGNewMemParserCtxt (const char *buffer, int size); -XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL +XMLPUBFUN xmlRelaxNGParserCtxtPtr xmlRelaxNGNewDocParserCtxt (xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxParserSetFlag (xmlRelaxNGParserCtxtPtr ctxt, int flag); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGFreeParserCtxt (xmlRelaxNGParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGValidityErrorFunc err, xmlRelaxNGValidityWarningFunc warn, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGValidityErrorFunc *err, xmlRelaxNGValidityWarningFunc *warn, void **ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGSetParserStructuredErrors( xmlRelaxNGParserCtxtPtr ctxt, xmlStructuredErrorFunc serror, void *ctx); -XMLPUBFUN xmlRelaxNGPtr XMLCALL +XMLPUBFUN xmlRelaxNGPtr xmlRelaxNGParse (xmlRelaxNGParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGFree (xmlRelaxNGPtr schema); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGDump (FILE *output, xmlRelaxNGPtr schema); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGDumpTree (FILE * output, xmlRelaxNGPtr schema); #endif /* LIBXML_OUTPUT_ENABLED */ /* * Interfaces for validating */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidityErrorFunc err, xmlRelaxNGValidityWarningFunc warn, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidityErrorFunc *err, xmlRelaxNGValidityWarningFunc *warn, void **ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, xmlStructuredErrorFunc serror, void *ctx); -XMLPUBFUN xmlRelaxNGValidCtxtPtr XMLCALL +XMLPUBFUN xmlRelaxNGValidCtxtPtr xmlRelaxNGNewValidCtxt (xmlRelaxNGPtr schema); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRelaxNGFreeValidCtxt (xmlRelaxNGValidCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGValidateDoc (xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc); /* * Interfaces for progressive validation when possible */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGValidatePushElement (xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGValidatePushCData (xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *data, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGValidatePopElement (xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRelaxNGValidateFullElement (xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); diff --git a/include/libxml/schemasInternals.h b/include/libxml/schemasInternals.h index c521d1c184c..e9d3b3c7abb 100644 --- a/include/libxml/schemasInternals.h +++ b/include/libxml/schemasInternals.h @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -947,8 +948,8 @@ struct _xmlSchema { void *volatiles; /* Obsolete */ }; -XMLPUBFUN void XMLCALL xmlSchemaFreeType (xmlSchemaTypePtr type); -XMLPUBFUN void XMLCALL xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard); +XMLPUBFUN void xmlSchemaFreeType (xmlSchemaTypePtr type); +XMLPUBFUN void xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard); #ifdef __cplusplus } diff --git a/include/libxml/schematron.h b/include/libxml/schematron.h index c61e61b3cf5..8dd8d25c451 100644 --- a/include/libxml/schematron.h +++ b/include/libxml/schematron.h @@ -15,6 +15,7 @@ #ifdef LIBXML_SCHEMATRON_ENABLED +#include #include #ifdef __cplusplus @@ -69,68 +70,68 @@ typedef xmlSchematronValidCtxt *xmlSchematronValidCtxtPtr; /* * Interfaces for parsing. */ -XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchematronParserCtxtPtr xmlSchematronNewParserCtxt (const char *URL); -XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchematronParserCtxtPtr xmlSchematronNewMemParserCtxt(const char *buffer, int size); -XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchematronParserCtxtPtr xmlSchematronNewDocParserCtxt(xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronFreeParserCtxt (xmlSchematronParserCtxtPtr ctxt); /***** -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronSetParserErrors(xmlSchematronParserCtxtPtr ctxt, xmlSchematronValidityErrorFunc err, xmlSchematronValidityWarningFunc warn, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronGetParserErrors(xmlSchematronParserCtxtPtr ctxt, xmlSchematronValidityErrorFunc * err, xmlSchematronValidityWarningFunc * warn, void **ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronIsValid (xmlSchematronValidCtxtPtr ctxt); *****/ -XMLPUBFUN xmlSchematronPtr XMLCALL +XMLPUBFUN xmlSchematronPtr xmlSchematronParse (xmlSchematronParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronFree (xmlSchematronPtr schema); /* * Interfaces for validating */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronSetValidStructuredErrors( xmlSchematronValidCtxtPtr ctxt, xmlStructuredErrorFunc serror, void *ctx); /****** -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronSetValidErrors (xmlSchematronValidCtxtPtr ctxt, xmlSchematronValidityErrorFunc err, xmlSchematronValidityWarningFunc warn, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronGetValidErrors (xmlSchematronValidCtxtPtr ctxt, xmlSchematronValidityErrorFunc *err, xmlSchematronValidityWarningFunc *warn, void **ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronSetValidOptions(xmlSchematronValidCtxtPtr ctxt, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronValidCtxtGetOptions(xmlSchematronValidCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronValidateOneElement (xmlSchematronValidCtxtPtr ctxt, xmlNodePtr elem); *******/ -XMLPUBFUN xmlSchematronValidCtxtPtr XMLCALL +XMLPUBFUN xmlSchematronValidCtxtPtr xmlSchematronNewValidCtxt (xmlSchematronPtr schema, int options); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchematronFreeValidCtxt (xmlSchematronValidCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchematronValidateDoc (xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance); diff --git a/include/libxml/threads.h b/include/libxml/threads.h index 6eedac1f374..8f4b6e174fb 100644 --- a/include/libxml/threads.h +++ b/include/libxml/threads.h @@ -29,59 +29,55 @@ typedef xmlMutex *xmlMutexPtr; typedef struct _xmlRMutex xmlRMutex; typedef xmlRMutex *xmlRMutexPtr; -#ifdef __cplusplus -} -#endif -#include -#ifdef __cplusplus -extern "C" { -#endif -XMLPUBFUN xmlMutexPtr XMLCALL +XMLPUBFUN int + xmlCheckThreadLocalStorage(void); + +XMLPUBFUN xmlMutexPtr xmlNewMutex (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlMutexLock (xmlMutexPtr tok); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlMutexUnlock (xmlMutexPtr tok); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeMutex (xmlMutexPtr tok); -XMLPUBFUN xmlRMutexPtr XMLCALL +XMLPUBFUN xmlRMutexPtr xmlNewRMutex (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRMutexLock (xmlRMutexPtr tok); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRMutexUnlock (xmlRMutexPtr tok); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeRMutex (xmlRMutexPtr tok); /* * Library wide APIs. */ XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlInitThreads (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlLockLibrary (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlUnlockLibrary(void); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlGetThreadId (void); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIsMainThread (void); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupThreads(void); -XMLPUBFUN xmlGlobalStatePtr XMLCALL - xmlGetGlobalState(void); -#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) -int XMLCALL +/** DOC_DISABLE */ +#if defined(LIBXML_THREAD_ENABLED) && defined(_WIN32) && \ + defined(LIBXML_STATIC_FOR_DLL) +int xmlDllMain(void *hinstDLL, unsigned long fdwReason, void *lpvReserved); #endif -#endif +/** DOC_ENABLE */ #ifdef __cplusplus } diff --git a/include/libxml/tree.h b/include/libxml/tree.h index 98e208745a9..f6b0b06301f 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -9,6 +9,15 @@ * Author: Daniel Veillard */ +#ifndef XML_TREE_INTERNALS + +/* + * Emulate circular dependency for backward compatibility + */ +#include + +#else /* XML_TREE_INTERNALS */ + #ifndef __XML_TREE_H__ #define __XML_TREE_H__ @@ -16,6 +25,8 @@ #include #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -74,7 +85,7 @@ typedef xmlEntity *xmlEntityPtr; 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_IMMUTABLE, /* immutable buffer, deprecated */ XML_BUFFER_ALLOC_IO, /* special allocation scheme used for I/O */ XML_BUFFER_ALLOC_HYBRID, /* exact up to a threshold, and doubleit thereafter */ XML_BUFFER_ALLOC_BOUNDED /* limit the upper size of the buffer */ @@ -117,10 +128,10 @@ typedef xmlBuf *xmlBufPtr; * A few public routines for xmlBuf. As those are expected to be used * mostly internally the bulk of the routines are internal in buf.h */ -XMLPUBFUN xmlChar* XMLCALL xmlBufContent (const xmlBuf* buf); -XMLPUBFUN xmlChar* XMLCALL xmlBufEnd (xmlBufPtr buf); -XMLPUBFUN size_t XMLCALL xmlBufUse (const xmlBufPtr buf); -XMLPUBFUN size_t XMLCALL xmlBufShrink (xmlBufPtr buf, size_t len); +XMLPUBFUN xmlChar* xmlBufContent (const xmlBuf* buf); +XMLPUBFUN xmlChar* xmlBufEnd (xmlBufPtr buf); +XMLPUBFUN size_t xmlBufUse (const xmlBufPtr buf); +XMLPUBFUN size_t xmlBufShrink (xmlBufPtr buf, size_t len); /* * LIBXML2_NEW_BUFFER: @@ -162,13 +173,13 @@ typedef enum { XML_TEXT_NODE= 3, XML_CDATA_SECTION_NODE= 4, XML_ENTITY_REF_NODE= 5, - XML_ENTITY_NODE= 6, + XML_ENTITY_NODE= 6, /* unused */ XML_PI_NODE= 7, XML_COMMENT_NODE= 8, XML_DOCUMENT_NODE= 9, - XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_TYPE_NODE= 10, /* unused */ XML_DOCUMENT_FRAG_NODE= 11, - XML_NOTATION_NODE= 12, + XML_NOTATION_NODE= 12, /* unused */ XML_HTML_DOCUMENT_NODE= 13, XML_DTD_NODE= 14, XML_ELEMENT_DECL= 15, @@ -180,8 +191,10 @@ typedef enum { /* XML_DOCB_DOCUMENT_NODE= 21 */ /* removed */ } xmlElementType; +/** DOC_DISABLE */ /* For backward compatibility */ #define XML_DOCB_DOCUMENT_NODE 21 +/** DOC_ENABLE */ /** * xmlNotation: @@ -327,14 +340,6 @@ typedef enum { XML_ELEMENT_TYPE_ELEMENT } xmlElementTypeVal; -#ifdef __cplusplus -} -#endif -#include -#ifdef __cplusplus -extern "C" { -#endif - /** * xmlElement: * @@ -444,6 +449,7 @@ struct _xmlAttr { xmlNs *ns; /* pointer to the associated namespace */ xmlAttributeType atype; /* the attribute type if validating */ void *psvi; /* for type/PSVI information */ + struct _xmlID *id; /* the ID struct */ }; /** @@ -571,12 +577,11 @@ struct _xmlDoc { 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 */ + const xmlChar *encoding; /* actual 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; /* Internal flag for charset handling, - actually an xmlCharEncoding */ + int charset; /* unused */ struct _xmlDict *dict; /* dict used to allocate names or NULL */ void *psvi; /* for type/PSVI information */ int parseFlags; /* set of xmlParserOption used to parse the @@ -628,6 +633,22 @@ struct _xmlDOMWrapCtxt { xmlDOMWrapAcquireNsFunction getNsForNodeFunc; }; +/** + * 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); + /** * xmlChildrenNode: * @@ -652,40 +673,61 @@ struct _xmlDOMWrapCtxt { * Variables. */ +/** DOC_DISABLE */ +#define XML_GLOBALS_TREE \ + XML_OP(xmlBufferAllocScheme, xmlBufferAllocationScheme, XML_DEPRECATED) \ + XML_OP(xmlDefaultBufferSize, int, XML_DEPRECATED) \ + XML_OP(xmlRegisterNodeDefaultValue, xmlRegisterNodeFunc, XML_DEPRECATED) \ + XML_OP(xmlDeregisterNodeDefaultValue, xmlDeregisterNodeFunc, \ + XML_DEPRECATED) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_TREE +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlBufferAllocScheme XML_GLOBAL_MACRO(xmlBufferAllocScheme) + #define xmlDefaultBufferSize XML_GLOBAL_MACRO(xmlDefaultBufferSize) + #define xmlRegisterNodeDefaultValue \ + XML_GLOBAL_MACRO(xmlRegisterNodeDefaultValue) + #define xmlDeregisterNodeDefaultValue \ + XML_GLOBAL_MACRO(xmlDeregisterNodeDefaultValue) +#else +#define xmlBufferAllocScheme vtklibxml2_xmlBufferAllocScheme +#define xmlDefaultBufferSize vtklibxml2_xmlDefaultBufferSize +#define xmlRegisterNodeDefaultValue vtklibxml2_xmlRegisterNodeDefaultValue +#define xmlDeregisterNodeDefaultValue vtklibxml2_xmlDeregisterNodeDefaultValue +#endif +/** DOC_ENABLE */ + /* * Some helper functions */ -#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ - defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || \ - defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || \ - defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || \ - defined(LIBXML_LEGACY_ENABLED) -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNCName (const xmlChar *value, int space); -#endif #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateQName (const xmlChar *value, int space); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateName (const xmlChar *value, int space); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNMToken (const xmlChar *value, int space); #endif -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlBuildQName (const xmlChar *ncname, const xmlChar *prefix, xmlChar *memory, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlSplitQName2 (const xmlChar *name, xmlChar **prefix); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlSplitQName3 (const xmlChar *name, int *len); @@ -693,318 +735,322 @@ XMLPUBFUN const xmlChar * XMLCALL * Handling Buffers, the old ones see @xmlBuf for the new ones. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme); -XMLPUBFUN xmlBufferAllocationScheme XMLCALL +XMLPUBFUN xmlBufferAllocationScheme xmlGetBufferAllocationScheme(void); -XMLPUBFUN xmlBufferPtr XMLCALL +XMLPUBFUN xmlBufferPtr xmlBufferCreate (void); -XMLPUBFUN xmlBufferPtr XMLCALL +XMLPUBFUN xmlBufferPtr xmlBufferCreateSize (size_t size); -XMLPUBFUN xmlBufferPtr XMLCALL +XMLPUBFUN xmlBufferPtr xmlBufferCreateStatic (void *mem, size_t size); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferResize (xmlBufferPtr buf, unsigned int size); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferFree (xmlBufferPtr buf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferDump (FILE *file, xmlBufferPtr buf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferAdd (xmlBufferPtr buf, const xmlChar *str, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferAddHead (xmlBufferPtr buf, const xmlChar *str, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferCat (xmlBufferPtr buf, const xmlChar *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferCCat (xmlBufferPtr buf, const char *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferShrink (xmlBufferPtr buf, unsigned int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferGrow (xmlBufferPtr buf, unsigned int len); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferEmpty (xmlBufferPtr buf); -XMLPUBFUN const xmlChar* XMLCALL +XMLPUBFUN const xmlChar* xmlBufferContent (const xmlBuffer *buf); -XMLPUBFUN xmlChar* XMLCALL +XMLPUBFUN xmlChar* xmlBufferDetach (xmlBufferPtr buf); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferSetAllocationScheme(xmlBufferPtr buf, xmlBufferAllocationScheme scheme); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufferLength (const xmlBuffer *buf); /* * Creating/freeing new structures. */ -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlCreateIntSubset (xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlNewDtd (xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlGetIntSubset (const xmlDoc *doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeDtd (xmlDtdPtr cur); #ifdef LIBXML_LEGACY_ENABLED XML_DEPRECATED -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlNewGlobalNs (xmlDocPtr doc, const xmlChar *href, const xmlChar *prefix); #endif /* LIBXML_LEGACY_ENABLED */ -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlNewNs (xmlNodePtr node, const xmlChar *href, const xmlChar *prefix); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeNs (xmlNsPtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeNsList (xmlNsPtr cur); -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlNewDoc (const xmlChar *version); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeDoc (xmlDocPtr cur); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlNewDocProp (xmlDocPtr doc, const xmlChar *name, const xmlChar *value); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlNewProp (xmlNodePtr node, const xmlChar *name, const xmlChar *value); #endif -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlNewNsProp (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlNewNsPropEatName (xmlNodePtr node, xmlNsPtr ns, xmlChar *name, const xmlChar *value); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreePropList (xmlAttrPtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeProp (xmlAttrPtr cur); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlCopyProp (xmlNodePtr target, xmlAttrPtr cur); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlCopyPropList (xmlNodePtr target, xmlAttrPtr cur); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlDtdPtr XMLCALL +XMLPUBFUN xmlDtdPtr xmlCopyDtd (xmlDtdPtr dtd); #endif /* LIBXML_TREE_ENABLED */ #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlCopyDoc (xmlDocPtr doc, int recursive); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ /* * Creating new nodes. */ -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocNode (xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocNodeEatName (xmlDocPtr doc, xmlNsPtr ns, xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewNode (xmlNsPtr ns, const xmlChar *name); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewNodeEatName (xmlNsPtr ns, xmlChar *name); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewChild (xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); #endif -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocText (const xmlDoc *doc, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewText (const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocPI (xmlDocPtr doc, const xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewPI (const xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocTextLen (xmlDocPtr doc, const xmlChar *content, int len); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewTextLen (const xmlChar *content, int len); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocComment (xmlDocPtr doc, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewComment (const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewCDataBlock (xmlDocPtr doc, const xmlChar *content, int len); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewCharRef (xmlDocPtr doc, const xmlChar *name); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewReference (const xmlDoc *doc, const xmlChar *name); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlCopyNode (xmlNodePtr node, int recursive); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlDocCopyNode (xmlNodePtr node, xmlDocPtr doc, int recursive); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlDocCopyNodeList (xmlDocPtr doc, xmlNodePtr node); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlCopyNodeList (xmlNodePtr node); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewTextChild (xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocRawNode (xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNewDocFragment (xmlDocPtr doc); #endif /* LIBXML_TREE_ENABLED */ /* * Navigating. */ -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlGetLineNo (const xmlNode *node); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlGetNodePath (const xmlNode *node); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) */ -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlDocGetRootElement (const xmlDoc *doc); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlGetLastChild (const xmlNode *parent); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNodeIsText (const xmlNode *node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsBlankNode (const xmlNode *node); /* * Changing the structure. */ #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlDocSetRootElement (xmlDocPtr doc, xmlNodePtr root); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNodeSetName (xmlNodePtr cur, const xmlChar *name); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlAddChild (xmlNodePtr parent, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlAddChildList (xmlNodePtr parent, xmlNodePtr cur); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlReplaceNode (xmlNodePtr old, xmlNodePtr cur); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlAddPrevSibling (xmlNodePtr cur, xmlNodePtr elem); #endif /* LIBXML_TREE_ENABLED || LIBXML_HTML_ENABLED || LIBXML_SCHEMAS_ENABLED */ -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlAddSibling (xmlNodePtr cur, xmlNodePtr elem); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlAddNextSibling (xmlNodePtr cur, xmlNodePtr elem); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlUnlinkNode (xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlTextMerge (xmlNodePtr first, xmlNodePtr second); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextConcat (xmlNodePtr node, const xmlChar *content, int len); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeNodeList (xmlNodePtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeNode (xmlNodePtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlSetTreeDoc (xmlNodePtr tree, xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlSetListDoc (xmlNodePtr list, xmlDocPtr doc); /* * Namespaces. */ -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlSearchNs (xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace); -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlSearchNsByHref (xmlDocPtr doc, xmlNodePtr node, const xmlChar *href); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN xmlNsPtr * XMLCALL +XMLPUBFUN int + xmlGetNsListSafe (const xmlDoc *doc, + const xmlNode *node, + xmlNsPtr **out); +XMLPUBFUN xmlNsPtr * xmlGetNsList (const xmlDoc *doc, const xmlNode *node); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetNs (xmlNodePtr node, xmlNsPtr ns); -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlCopyNamespace (xmlNsPtr cur); -XMLPUBFUN xmlNsPtr XMLCALL +XMLPUBFUN xmlNsPtr xmlCopyNamespaceList (xmlNsPtr cur); /* @@ -1012,94 +1058,103 @@ XMLPUBFUN xmlNsPtr XMLCALL */ #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlSetProp (xmlNodePtr node, const xmlChar *name, const xmlChar *value); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlSetNsProp (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN int + xmlNodeGetAttrValue (const xmlNode *node, + const xmlChar *name, + const xmlChar *nsUri, + xmlChar **out); +XMLPUBFUN xmlChar * xmlGetNoNsProp (const xmlNode *node, const xmlChar *name); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlGetProp (const xmlNode *node, const xmlChar *name); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlHasProp (const xmlNode *node, const xmlChar *name); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlHasNsProp (const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlGetNsProp (const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlStringGetNodeList (const xmlDoc *doc, const xmlChar *value); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlStringLenGetNodeList (const xmlDoc *doc, const xmlChar *value, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNodeListGetString (xmlDocPtr doc, const xmlNode *list, int inLine); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNodeListGetRawString (const xmlDoc *doc, const xmlNode *list, int inLine); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeSetContent (xmlNodePtr cur, const xmlChar *content); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeSetContentLen (xmlNodePtr cur, const xmlChar *content, int len); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeAddContent (xmlNodePtr cur, const xmlChar *content); -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeAddContentLen (xmlNodePtr cur, const xmlChar *content, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNodeGetContent (const xmlNode *cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNodeBufGetContent (xmlBufferPtr buffer, const xmlNode *cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlBufGetNodeContent (xmlBufPtr buf, const xmlNode *cur); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlNodeGetLang (const xmlNode *cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNodeGetSpacePreserve (const xmlNode *cur); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeSetLang (xmlNodePtr cur, const xmlChar *lang); -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeSetSpacePreserve (xmlNodePtr cur, int val); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN int + xmlNodeGetBaseSafe (const xmlDoc *doc, + const xmlNode *cur, + xmlChar **baseOut); +XMLPUBFUN xmlChar * xmlNodeGetBase (const xmlDoc *doc, const xmlNode *cur); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlNodeSetBase (xmlNodePtr cur, const xmlChar *uri); #endif @@ -1107,14 +1162,14 @@ XMLPUBFUN void XMLCALL /* * Removing content. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRemoveProp (xmlAttrPtr cur); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUnsetNsProp (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUnsetProp (xmlNodePtr node, const xmlChar *name); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ @@ -1122,13 +1177,13 @@ XMLPUBFUN int XMLCALL /* * Internal, don't use. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferWriteCHAR (xmlBufferPtr buf, const xmlChar *string); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferWriteChar (xmlBufferPtr buf, const char *string); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string); @@ -1143,7 +1198,7 @@ XMLPUBFUN void xmlAttrSerializeTxtContent(xmlBufferPtr buf, /* * Namespace handling. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReconciliateNs (xmlDocPtr doc, xmlNodePtr tree); #endif @@ -1152,67 +1207,67 @@ XMLPUBFUN int XMLCALL /* * Saving. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDocDumpFormatMemory (xmlDocPtr cur, xmlChar **mem, int *size, int format); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDocDumpMemory (xmlDocPtr cur, xmlChar **mem, int *size); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDocDumpMemoryEnc (xmlDocPtr out_doc, xmlChar **doc_txt_ptr, int * doc_txt_len, const char *txt_encoding); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, int * doc_txt_len, const char *txt_encoding, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDocFormatDump (FILE *f, xmlDocPtr cur, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDocDump (FILE *f, xmlDocPtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlElemDump (FILE *f, xmlDocPtr doc, xmlNodePtr cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFile (const char *filename, xmlDocPtr cur); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFormatFile (const char *filename, xmlDocPtr cur, int format); -XMLPUBFUN size_t XMLCALL +XMLPUBFUN size_t xmlBufNodeDump (xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNodeDump (xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFileTo (xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFormatFileTo (xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlNodeDumpOutput (xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, @@ -1220,13 +1275,13 @@ XMLPUBFUN void XMLCALL int format, const char *encoding); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFormatFileEnc (const char *filename, xmlDocPtr cur, const char *encoding, int format); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFileEnc (const char *filename, xmlDocPtr cur, const char *encoding); @@ -1235,47 +1290,49 @@ XMLPUBFUN int XMLCALL /* * XHTML */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsXHTML (const xmlChar *systemID, const xmlChar *publicID); /* * Compression. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGetDocCompressMode (const xmlDoc *doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetDocCompressMode (xmlDocPtr doc, int mode); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlGetCompressMode (void); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlSetCompressMode (int mode); /* * DOM-wrapper helper functions. */ -XMLPUBFUN xmlDOMWrapCtxtPtr XMLCALL +XMLPUBFUN xmlDOMWrapCtxtPtr xmlDOMWrapNewCtxt (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlDOMWrapFreeCtxt (xmlDOMWrapCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt, xmlNodePtr elem, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDOMWrapAdoptNode (xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlNodePtr node, xmlDocPtr destDoc, xmlNodePtr destParent, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDOMWrapRemoveNode (xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr node, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlDOMWrapCloneNode (xmlDOMWrapCtxtPtr ctxt, xmlDocPtr sourceDoc, xmlNodePtr node, @@ -1290,23 +1347,41 @@ XMLPUBFUN int XMLCALL * 5 interfaces from DOM ElementTraversal, but different in entities * traversal. */ -XMLPUBFUN unsigned long XMLCALL +XMLPUBFUN unsigned long xmlChildElementCount (xmlNodePtr parent); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlNextElementSibling (xmlNodePtr node); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlFirstElementChild (xmlNodePtr parent); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlLastElementChild (xmlNodePtr parent); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlPreviousElementSibling (xmlNodePtr node); #endif + +XML_DEPRECATED +XMLPUBFUN xmlRegisterNodeFunc + xmlRegisterNodeDefault (xmlRegisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlDeregisterNodeFunc + xmlDeregisterNodeDefault (xmlDeregisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlRegisterNodeFunc + xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlDeregisterNodeFunc + xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func); + +XML_DEPRECATED XMLPUBFUN xmlBufferAllocationScheme + xmlThrDefBufferAllocScheme (xmlBufferAllocationScheme v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefDefaultBufferSize (int v); + #ifdef __cplusplus } #endif -#ifndef __XML_PARSER_H__ -#include -#endif #endif /* __XML_TREE_H__ */ +#endif /* XML_TREE_INTERNALS */ + diff --git a/include/libxml/uri.h b/include/libxml/uri.h index db48262b136..19980b711c5 100644 --- a/include/libxml/uri.h +++ b/include/libxml/uri.h @@ -11,8 +11,9 @@ #ifndef __XML_URI_H__ #define __XML_URI_H__ +#include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -49,43 +50,54 @@ struct _xmlURI { * xmlChar * xmlNodeGetBase (xmlDocPtr doc, * xmlNodePtr cur); */ -XMLPUBFUN xmlURIPtr XMLCALL +XMLPUBFUN xmlURIPtr xmlCreateURI (void); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN int + xmlBuildURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); +XMLPUBFUN xmlChar * xmlBuildURI (const xmlChar *URI, const xmlChar *base); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN int + xmlBuildRelativeURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); +XMLPUBFUN xmlChar * xmlBuildRelativeURI (const xmlChar *URI, const xmlChar *base); -XMLPUBFUN xmlURIPtr XMLCALL +XMLPUBFUN xmlURIPtr xmlParseURI (const char *str); -XMLPUBFUN xmlURIPtr XMLCALL +XMLPUBFUN int + xmlParseURISafe (const char *str, + xmlURIPtr *uri); +XMLPUBFUN xmlURIPtr xmlParseURIRaw (const char *str, int raw); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParseURIReference (xmlURIPtr uri, const char *str); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlSaveUri (xmlURIPtr uri); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlPrintURI (FILE *stream, xmlURIPtr uri); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlURIEscapeStr (const xmlChar *str, const xmlChar *list); -XMLPUBFUN char * XMLCALL +XMLPUBFUN char * xmlURIUnescapeString (const char *str, int len, char *target); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlNormalizeURIPath (char *path); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlURIEscape (const xmlChar *str); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeURI (xmlURIPtr uri); -XMLPUBFUN xmlChar* XMLCALL +XMLPUBFUN xmlChar* xmlCanonicPath (const xmlChar *path); -XMLPUBFUN xmlChar* XMLCALL +XMLPUBFUN xmlChar* xmlPathToURI (const xmlChar *path); #ifdef __cplusplus diff --git a/include/libxml/valid.h b/include/libxml/valid.h index 3eaf84adcb4..e1698d7a340 100644 --- a/include/libxml/valid.h +++ b/include/libxml/valid.h @@ -11,12 +11,16 @@ #ifndef __XML_VALID_H__ #define __XML_VALID_H__ +/** DOC_DISABLE */ #include #include +#define XML_TREE_INTERNALS #include +#undef XML_TREE_INTERNALS #include #include #include +/** DOC_ENABLE */ #ifdef __cplusplus extern "C" { @@ -39,7 +43,7 @@ typedef xmlValidState *xmlValidStatePtr; * 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, +typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); @@ -54,25 +58,10 @@ typedef void (XMLCDECL *xmlValidityErrorFunc) (void *ctx, * 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, +typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); -#ifdef IN_LIBXML -/** - * XML_VCTXT_DTD_VALIDATED: - * - * Set after xmlValidateDtdFinal was called. - */ -#define XML_VCTXT_DTD_VALIDATED (1u << 0) -/** - * XML_VCTXT_USE_PCTXT: - * - * Set if the validation context is part of a parser context. - */ -#define XML_VCTXT_USE_PCTXT (1u << 1) -#endif - /* * xmlValidCtxt: * An xmlValidCtxt is used for error reporting when validating. @@ -150,95 +139,98 @@ typedef struct _xmlHashTable xmlRefTable; typedef xmlRefTable *xmlRefTablePtr; /* Notation */ -XMLPUBFUN xmlNotationPtr XMLCALL +XMLPUBFUN xmlNotationPtr xmlAddNotationDecl (xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, const xmlChar *PublicID, const xmlChar *SystemID); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlNotationTablePtr XMLCALL +XMLPUBFUN xmlNotationTablePtr xmlCopyNotationTable (xmlNotationTablePtr table); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeNotationTable (xmlNotationTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlDumpNotationDecl (xmlBufferPtr buf, xmlNotationPtr nota); -XMLPUBFUN void XMLCALL +/* XML_DEPRECATED, still used in lxml */ +XMLPUBFUN void xmlDumpNotationTable (xmlBufferPtr buf, xmlNotationTablePtr table); #endif /* LIBXML_OUTPUT_ENABLED */ /* Element Content */ /* the non Doc version are being deprecated */ -XMLPUBFUN xmlElementContentPtr XMLCALL +XMLPUBFUN xmlElementContentPtr xmlNewElementContent (const xmlChar *name, xmlElementContentType type); -XMLPUBFUN xmlElementContentPtr XMLCALL +XMLPUBFUN xmlElementContentPtr xmlCopyElementContent (xmlElementContentPtr content); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeElementContent (xmlElementContentPtr cur); /* the new versions with doc argument */ -XMLPUBFUN xmlElementContentPtr XMLCALL +XMLPUBFUN xmlElementContentPtr xmlNewDocElementContent (xmlDocPtr doc, const xmlChar *name, xmlElementContentType type); -XMLPUBFUN xmlElementContentPtr XMLCALL +XMLPUBFUN xmlElementContentPtr xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr content); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob); #ifdef LIBXML_OUTPUT_ENABLED -/* DEPRECATED */ -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int englob); #endif /* LIBXML_OUTPUT_ENABLED */ -/* DEPRECATED */ /* Element */ -XMLPUBFUN xmlElementPtr XMLCALL +XMLPUBFUN xmlElementPtr xmlAddElementDecl (xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, xmlElementTypeVal type, xmlElementContentPtr content); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlElementTablePtr XMLCALL +XMLPUBFUN xmlElementTablePtr xmlCopyElementTable (xmlElementTablePtr table); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeElementTable (xmlElementTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlDumpElementTable (xmlBufferPtr buf, xmlElementTablePtr table); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlDumpElementDecl (xmlBufferPtr buf, xmlElementPtr elem); #endif /* LIBXML_OUTPUT_ENABLED */ /* Enumeration */ -XMLPUBFUN xmlEnumerationPtr XMLCALL +XMLPUBFUN xmlEnumerationPtr xmlCreateEnumeration (const xmlChar *name); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeEnumeration (xmlEnumerationPtr cur); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlEnumerationPtr XMLCALL +XMLPUBFUN xmlEnumerationPtr xmlCopyEnumeration (xmlEnumerationPtr cur); #endif /* LIBXML_TREE_ENABLED */ /* Attribute */ -XMLPUBFUN xmlAttributePtr XMLCALL +XMLPUBFUN xmlAttributePtr xmlAddAttributeDecl (xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem, @@ -249,60 +241,65 @@ XMLPUBFUN xmlAttributePtr XMLCALL const xmlChar *defaultValue, xmlEnumerationPtr tree); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN xmlAttributeTablePtr XMLCALL +XMLPUBFUN xmlAttributeTablePtr xmlCopyAttributeTable (xmlAttributeTablePtr table); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeAttributeTable (xmlAttributeTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlDumpAttributeTable (xmlBufferPtr buf, xmlAttributeTablePtr table); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlDumpAttributeDecl (xmlBufferPtr buf, xmlAttributePtr attr); #endif /* LIBXML_OUTPUT_ENABLED */ /* IDs */ -XMLPUBFUN xmlIDPtr XMLCALL +XMLPUBFUN int + xmlAddIDSafe (xmlAttrPtr attr, + const xmlChar *value); +XMLPUBFUN xmlIDPtr xmlAddID (xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeIDTable (xmlIDTablePtr table); -XMLPUBFUN xmlAttrPtr XMLCALL +XMLPUBFUN xmlAttrPtr xmlGetID (xmlDocPtr doc, const xmlChar *ID); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsID (xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRemoveID (xmlDocPtr doc, xmlAttrPtr attr); /* IDREFs */ XML_DEPRECATED -XMLPUBFUN xmlRefPtr XMLCALL +XMLPUBFUN xmlRefPtr xmlAddRef (xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeRefTable (xmlRefTablePtr table); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsRef (xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr); XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRemoveRef (xmlDocPtr doc, xmlAttrPtr attr); XML_DEPRECATED -XMLPUBFUN xmlListPtr XMLCALL +XMLPUBFUN xmlListPtr xmlGetRefs (xmlDocPtr doc, const xmlChar *ID); @@ -311,146 +308,163 @@ XMLPUBFUN xmlListPtr XMLCALL */ #ifdef LIBXML_VALID_ENABLED /* Allocate/Release Validation Contexts */ -XMLPUBFUN xmlValidCtxtPtr XMLCALL +XMLPUBFUN xmlValidCtxtPtr xmlNewValidCtxt(void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeValidCtxt(xmlValidCtxtPtr); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateRoot (xmlValidCtxtPtr ctxt, xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateElementDecl (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlElementPtr elem); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value); -XMLPUBFUN xmlChar * XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlAttributePtr attr); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateNotationDecl (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNotationPtr nota); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateDtd (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateDtdFinal (xmlValidCtxtPtr ctxt, xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateDocument (xmlValidCtxtPtr ctxt, xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateOneElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateOneNamespace (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc); #endif /* LIBXML_VALID_ENABLED */ #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidateNotationUse (xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *notationName); #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlIsMixedElement (xmlDocPtr doc, const xmlChar *name); -XMLPUBFUN xmlAttributePtr XMLCALL +XMLPUBFUN xmlAttributePtr xmlGetDtdAttrDesc (xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name); -XMLPUBFUN xmlAttributePtr XMLCALL +XMLPUBFUN xmlAttributePtr xmlGetDtdQAttrDesc (xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, const xmlChar *prefix); -XMLPUBFUN xmlNotationPtr XMLCALL +XMLPUBFUN xmlNotationPtr xmlGetDtdNotationDesc (xmlDtdPtr dtd, const xmlChar *name); -XMLPUBFUN xmlElementPtr XMLCALL +XMLPUBFUN xmlElementPtr xmlGetDtdQElementDesc (xmlDtdPtr dtd, const xmlChar *name, const xmlChar *prefix); -XMLPUBFUN xmlElementPtr XMLCALL +XMLPUBFUN xmlElementPtr xmlGetDtdElementDesc (xmlDtdPtr dtd, const xmlChar *name); #ifdef LIBXML_VALID_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **names, int *len, int max); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, int max); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNameValue (const xmlChar *value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNamesValue (const xmlChar *value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNmtokenValue (const xmlChar *value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlValidateNmtokensValue(const xmlChar *value); #ifdef LIBXML_REGEXP_ENABLED /* * Validation based on the regexp support */ -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidatePushElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *qname); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidatePushCData (xmlValidCtxtPtr ctxt, const xmlChar *data, int len); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlValidatePopElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, diff --git a/include/libxml/vtk_libxml2_mangle.h b/include/libxml/vtk_libxml2_mangle.h index a84beeb23e0..a598b67f6fa 100644 --- a/include/libxml/vtk_libxml2_mangle.h +++ b/include/libxml/vtk_libxml2_mangle.h @@ -1,24 +1,20 @@ #ifndef vtk_libxml2_mangle_h #define vtk_libxml2_mangle_h -#define docbCreateFileParserCtxt vtklibxml2_docbCreateFileParserCtxt -#define docbCreatePushParserCtxt vtklibxml2_docbCreatePushParserCtxt -#define __docbDefaultSAXHandler vtklibxml2___docbDefaultSAXHandler -#define docbDefaultSAXHandler vtklibxml2_docbDefaultSAXHandler -#define docbDefaultSAXHandlerInit vtklibxml2_docbDefaultSAXHandlerInit -#define docbEncodeEntities vtklibxml2_docbEncodeEntities -#define docbFreeParserCtxt vtklibxml2_docbFreeParserCtxt -#define docbParseChunk vtklibxml2_docbParseChunk -#define docbParseDoc vtklibxml2_docbParseDoc -#define docbParseDocument vtklibxml2_docbParseDocument -#define docbParseFile vtklibxml2_docbParseFile -#define docbSAXParseDoc vtklibxml2_docbSAXParseDoc -#define docbSAXParseFile vtklibxml2_docbSAXParseFile +/** + * Generated using: + * + * nm -g lib/libvtklibxml2-9.3.so | grep -e ' [TDRSB] ' |\ + * cut -d' ' -f3 | grep -v -e 'vtklibxml2_' | \ + * sort | sed -e 's/\(.*\)/#define \1 vtklibxml2_\1/' > /tmp/vtk_libxml2_mangle.h + */ + #define htmlAttrAllowed vtklibxml2_htmlAttrAllowed #define htmlAutoCloseTag vtklibxml2_htmlAutoCloseTag #define htmlCreateFileParserCtxt vtklibxml2_htmlCreateFileParserCtxt #define htmlCreateMemoryParserCtxt vtklibxml2_htmlCreateMemoryParserCtxt #define htmlCreatePushParserCtxt vtklibxml2_htmlCreatePushParserCtxt +#define htmlCtxtParseDocument vtklibxml2_htmlCtxtParseDocument #define htmlCtxtReadDoc vtklibxml2_htmlCtxtReadDoc #define htmlCtxtReadFd vtklibxml2_htmlCtxtReadFd #define htmlCtxtReadFile vtklibxml2_htmlCtxtReadFile @@ -49,6 +45,7 @@ #define htmlNewDoc vtklibxml2_htmlNewDoc #define htmlNewDocNoDtD vtklibxml2_htmlNewDocNoDtD #define htmlNewParserCtxt vtklibxml2_htmlNewParserCtxt +#define htmlNewSAXParserCtxt vtklibxml2_htmlNewSAXParserCtxt #define htmlNodeDump vtklibxml2_htmlNodeDump #define htmlNodeDumpFile vtklibxml2_htmlNodeDumpFile #define htmlNodeDumpFileFormat vtklibxml2_htmlNodeDumpFileFormat @@ -57,7 +54,6 @@ #define htmlNodeStatus vtklibxml2_htmlNodeStatus #define htmlParseCharRef vtklibxml2_htmlParseCharRef #define htmlParseChunk vtklibxml2_htmlParseChunk -#define __htmlParseContent vtklibxml2___htmlParseContent #define htmlParseDoc vtklibxml2_htmlParseDoc #define htmlParseDocument vtklibxml2_htmlParseDocument #define htmlParseElement vtklibxml2_htmlParseElement @@ -110,14 +106,15 @@ #define xmlAddDtdEntity vtklibxml2_xmlAddDtdEntity #define xmlAddElementDecl vtklibxml2_xmlAddElementDecl #define xmlAddEncodingAlias vtklibxml2_xmlAddEncodingAlias +#define xmlAddEntity vtklibxml2_xmlAddEntity #define xmlAddID vtklibxml2_xmlAddID +#define xmlAddIDSafe vtklibxml2_xmlAddIDSafe #define xmlAddNextSibling vtklibxml2_xmlAddNextSibling #define xmlAddNotationDecl vtklibxml2_xmlAddNotationDecl #define xmlAddPrevSibling vtklibxml2_xmlAddPrevSibling #define xmlAddRef vtklibxml2_xmlAddRef #define xmlAddSibling vtklibxml2_xmlAddSibling #define xmlAllocOutputBuffer vtklibxml2_xmlAllocOutputBuffer -#define xmlAllocOutputBufferInternal vtklibxml2_xmlAllocOutputBufferInternal #define xmlAllocParserInputBuffer vtklibxml2_xmlAllocParserInputBuffer #define xmlAttrSerializeTxtContent vtklibxml2_xmlAttrSerializeTxtContent #define xmlAutomataCompile vtklibxml2_xmlAutomataCompile @@ -137,32 +134,10 @@ #define xmlAutomataNewTransition vtklibxml2_xmlAutomataNewTransition #define xmlAutomataNewTransition2 vtklibxml2_xmlAutomataNewTransition2 #define xmlAutomataSetFinalState vtklibxml2_xmlAutomataSetFinalState -#define xmlAutomataSetFlags vtklibxml2_xmlAutomataSetFlags -#define xmlBufAdd vtklibxml2_xmlBufAdd -#define xmlBufAddHead vtklibxml2_xmlBufAddHead -#define xmlBufAddLen vtklibxml2_xmlBufAddLen -#define xmlBufAttrSerializeTxtContent vtklibxml2_xmlBufAttrSerializeTxtContent -#define xmlBufAvail vtklibxml2_xmlBufAvail -#define xmlBufBackToBuffer vtklibxml2_xmlBufBackToBuffer -#define xmlBufCat vtklibxml2_xmlBufCat -#define xmlBufCCat vtklibxml2_xmlBufCCat #define xmlBufContent vtklibxml2_xmlBufContent -#define xmlBufCreate vtklibxml2_xmlBufCreate -#define xmlBufCreateSize vtklibxml2_xmlBufCreateSize -#define xmlBufCreateStatic vtklibxml2_xmlBufCreateStatic -#define xmlBufDetach vtklibxml2_xmlBufDetach -#define xmlBufDump vtklibxml2_xmlBufDump -#define xmlBufDumpAttributeDecl vtklibxml2_xmlBufDumpAttributeDecl -#define xmlBufDumpElementDecl vtklibxml2_xmlBufDumpElementDecl -#define xmlBufDumpEntityDecl vtklibxml2_xmlBufDumpEntityDecl -#define xmlBufDumpNotationTable vtklibxml2_xmlBufDumpNotationTable -#define xmlBufEmpty vtklibxml2_xmlBufEmpty #define xmlBufEnd vtklibxml2_xmlBufEnd -#define xmlBufErase vtklibxml2_xmlBufErase #define xmlBufferAdd vtklibxml2_xmlBufferAdd #define xmlBufferAddHead vtklibxml2_xmlBufferAddHead -#define __xmlBufferAllocScheme vtklibxml2___xmlBufferAllocScheme -#define xmlBufferAllocScheme vtklibxml2_xmlBufferAllocScheme #define xmlBufferCat vtklibxml2_xmlBufferCat #define xmlBufferCCat vtklibxml2_xmlBufferCCat #define xmlBufferContent vtklibxml2_xmlBufferContent @@ -181,29 +156,15 @@ #define xmlBufferWriteChar vtklibxml2_xmlBufferWriteChar #define xmlBufferWriteCHAR vtklibxml2_xmlBufferWriteCHAR #define xmlBufferWriteQuotedString vtklibxml2_xmlBufferWriteQuotedString -#define xmlBufFree vtklibxml2_xmlBufFree -#define xmlBufFromBuffer vtklibxml2_xmlBufFromBuffer -#define xmlBufGetAllocationScheme vtklibxml2_xmlBufGetAllocationScheme -#define xmlBufGetInputBase vtklibxml2_xmlBufGetInputBase #define xmlBufGetNodeContent vtklibxml2_xmlBufGetNodeContent -#define xmlBufGrow vtklibxml2_xmlBufGrow -#define xmlBufInflate vtklibxml2_xmlBufInflate -#define xmlBufIsEmpty vtklibxml2_xmlBufIsEmpty -#define xmlBufLength vtklibxml2_xmlBufLength -#define xmlBufMergeBuffer vtklibxml2_xmlBufMergeBuffer #define xmlBufNodeDump vtklibxml2_xmlBufNodeDump -#define xmlBufResetInput vtklibxml2_xmlBufResetInput -#define xmlBufResize vtklibxml2_xmlBufResize -#define xmlBufSetAllocationScheme vtklibxml2_xmlBufSetAllocationScheme -#define xmlBufSetInputBaseCur vtklibxml2_xmlBufSetInputBaseCur #define xmlBufShrink vtklibxml2_xmlBufShrink #define xmlBufUse vtklibxml2_xmlBufUse -#define xmlBufWriteChar vtklibxml2_xmlBufWriteChar -#define xmlBufWriteCHAR vtklibxml2_xmlBufWriteCHAR -#define xmlBufWriteQuotedString vtklibxml2_xmlBufWriteQuotedString #define xmlBuildQName vtklibxml2_xmlBuildQName #define xmlBuildRelativeURI vtklibxml2_xmlBuildRelativeURI +#define xmlBuildRelativeURISafe vtklibxml2_xmlBuildRelativeURISafe #define xmlBuildURI vtklibxml2_xmlBuildURI +#define xmlBuildURISafe vtklibxml2_xmlBuildURISafe #define xmlByteConsumed vtklibxml2_xmlByteConsumed #define xmlC14NDocDumpMemory vtklibxml2_xmlC14NDocDumpMemory #define xmlC14NDocSave vtklibxml2_xmlC14NDocSave @@ -232,18 +193,15 @@ #define xmlCatalogSetDefaults vtklibxml2_xmlCatalogSetDefaults #define xmlCharEncCloseFunc vtklibxml2_xmlCharEncCloseFunc #define xmlCharEncFirstLine vtklibxml2_xmlCharEncFirstLine -#define xmlCharEncFirstLineInput vtklibxml2_xmlCharEncFirstLineInput -#define xmlCharEncFirstLineInt vtklibxml2_xmlCharEncFirstLineInt #define xmlCharEncInFunc vtklibxml2_xmlCharEncInFunc -#define xmlCharEncInput vtklibxml2_xmlCharEncInput #define xmlCharEncOutFunc vtklibxml2_xmlCharEncOutFunc -#define xmlCharEncOutput vtklibxml2_xmlCharEncOutput #define xmlCharInRange vtklibxml2_xmlCharInRange #define xmlCharStrdup vtklibxml2_xmlCharStrdup #define xmlCharStrndup vtklibxml2_xmlCharStrndup #define xmlCheckFilename vtklibxml2_xmlCheckFilename #define xmlCheckHTTPInput vtklibxml2_xmlCheckHTTPInput #define xmlCheckLanguageID vtklibxml2_xmlCheckLanguageID +#define xmlCheckThreadLocalStorage vtklibxml2_xmlCheckThreadLocalStorage #define xmlCheckUTF8 vtklibxml2_xmlCheckUTF8 #define xmlCheckVersion vtklibxml2_xmlCheckVersion #define xmlChildElementCount vtklibxml2_xmlChildElementCount @@ -287,7 +245,9 @@ #define xmlCreatePushParserCtxt vtklibxml2_xmlCreatePushParserCtxt #define xmlCreateURI vtklibxml2_xmlCreateURI #define xmlCreateURLParserCtxt vtklibxml2_xmlCreateURLParserCtxt +#define xmlCtxtErrMemory vtklibxml2_xmlCtxtErrMemory #define xmlCtxtGetLastError vtklibxml2_xmlCtxtGetLastError +#define xmlCtxtParseDocument vtklibxml2_xmlCtxtParseDocument #define xmlCtxtReadDoc vtklibxml2_xmlCtxtReadDoc #define xmlCtxtReadFd vtklibxml2_xmlCtxtReadFd #define xmlCtxtReadFile vtklibxml2_xmlCtxtReadFile @@ -296,10 +256,11 @@ #define xmlCtxtReset vtklibxml2_xmlCtxtReset #define xmlCtxtResetLastError vtklibxml2_xmlCtxtResetLastError #define xmlCtxtResetPush vtklibxml2_xmlCtxtResetPush +#define xmlCtxtSetErrorHandler vtklibxml2_xmlCtxtSetErrorHandler +#define xmlCtxtSetMaxAmplification vtklibxml2_xmlCtxtSetMaxAmplification +#define xmlCtxtSetOptions vtklibxml2_xmlCtxtSetOptions #define xmlCtxtUseOptions vtklibxml2_xmlCtxtUseOptions #define xmlCurrentChar vtklibxml2_xmlCurrentChar -#define __xmlDefaultBufferSize vtklibxml2___xmlDefaultBufferSize -#define xmlDefaultBufferSize vtklibxml2_xmlDefaultBufferSize #define __xmlDefaultSAXHandler vtklibxml2___xmlDefaultSAXHandler #define xmlDefaultSAXHandler vtklibxml2_xmlDefaultSAXHandler #define xmlDefaultSAXHandlerInit vtklibxml2_xmlDefaultSAXHandlerInit @@ -307,8 +268,6 @@ #define xmlDefaultSAXLocator vtklibxml2_xmlDefaultSAXLocator #define xmlDelEncodingAlias vtklibxml2_xmlDelEncodingAlias #define xmlDeregisterNodeDefault vtklibxml2_xmlDeregisterNodeDefault -#define __xmlDeregisterNodeDefaultValue vtklibxml2___xmlDeregisterNodeDefaultValue -#define xmlDeregisterNodeDefaultValue vtklibxml2_xmlDeregisterNodeDefaultValue #define xmlDetectCharEncoding vtklibxml2_xmlDetectCharEncoding #define xmlDictCleanup vtklibxml2_xmlDictCleanup #define xmlDictCreate vtklibxml2_xmlDictCreate @@ -338,8 +297,6 @@ #define xmlDOMWrapNewCtxt vtklibxml2_xmlDOMWrapNewCtxt #define xmlDOMWrapReconcileNamespaces vtklibxml2_xmlDOMWrapReconcileNamespaces #define xmlDOMWrapRemoveNode vtklibxml2_xmlDOMWrapRemoveNode -#define __xmlDoValidityCheckingDefaultValue vtklibxml2___xmlDoValidityCheckingDefaultValue -#define xmlDoValidityCheckingDefaultValue vtklibxml2_xmlDoValidityCheckingDefaultValue #define xmlDumpAttributeDecl vtklibxml2_xmlDumpAttributeDecl #define xmlDumpAttributeTable vtklibxml2_xmlDumpAttributeTable #define xmlDumpElementDecl vtklibxml2_xmlDumpElementDecl @@ -349,20 +306,15 @@ #define xmlDumpNotationDecl vtklibxml2_xmlDumpNotationDecl #define xmlDumpNotationTable vtklibxml2_xmlDumpNotationTable #define xmlElemDump vtklibxml2_xmlElemDump -#define xmlEncodeAttributeEntities vtklibxml2_xmlEncodeAttributeEntities #define xmlEncodeEntitiesReentrant vtklibxml2_xmlEncodeEntitiesReentrant #define xmlEncodeSpecialChars vtklibxml2_xmlEncodeSpecialChars -#define __xmlErrEncoding vtklibxml2___xmlErrEncoding -#define xmlErrMemory vtklibxml2_xmlErrMemory -#define xmlEscapeFormatString vtklibxml2_xmlEscapeFormatString #define xmlFileClose vtklibxml2_xmlFileClose #define xmlFileMatch vtklibxml2_xmlFileMatch #define xmlFileOpen vtklibxml2_xmlFileOpen #define xmlFileRead vtklibxml2_xmlFileRead #define xmlFindCharEncodingHandler vtklibxml2_xmlFindCharEncodingHandler #define xmlFirstElementChild vtklibxml2_xmlFirstElementChild -#define __xmlFree vtklibxml2___xmlFree -#define xmlFree vtklibxml2_xmlFree +#define xmlFormatError vtklibxml2_xmlFormatError #define xmlFreeAttributeTable vtklibxml2_xmlFreeAttributeTable #define xmlFreeAutomata vtklibxml2_xmlFreeAutomata #define xmlFreeCatalog vtklibxml2_xmlFreeCatalog @@ -372,6 +324,7 @@ #define xmlFreeElementContent vtklibxml2_xmlFreeElementContent #define xmlFreeElementTable vtklibxml2_xmlFreeElementTable #define xmlFreeEntitiesTable vtklibxml2_xmlFreeEntitiesTable +#define xmlFreeEntity vtklibxml2_xmlFreeEntity #define xmlFreeEnumeration vtklibxml2_xmlFreeEnumeration #define xmlFreeIDTable vtklibxml2_xmlFreeIDTable #define xmlFreeInputStream vtklibxml2_xmlFreeInputStream @@ -396,11 +349,6 @@ #define xmlFreeValidCtxt vtklibxml2_xmlFreeValidCtxt #define xmlGcMemGet vtklibxml2_xmlGcMemGet #define xmlGcMemSetup vtklibxml2_xmlGcMemSetup -#define __xmlGenericError vtklibxml2___xmlGenericError -#define xmlGenericError vtklibxml2_xmlGenericError -#define __xmlGenericErrorContext vtklibxml2___xmlGenericErrorContext -#define xmlGenericErrorContext vtklibxml2_xmlGenericErrorContext -#define xmlGenericErrorDefaultFunc vtklibxml2_xmlGenericErrorDefaultFunc #define xmlGetBufferAllocationScheme vtklibxml2_xmlGetBufferAllocationScheme #define xmlGetCharEncodingHandler vtklibxml2_xmlGetCharEncodingHandler #define xmlGetCharEncodingName vtklibxml2_xmlGetCharEncodingName @@ -424,6 +372,7 @@ #define xmlGetNodePath vtklibxml2_xmlGetNodePath #define xmlGetNoNsProp vtklibxml2_xmlGetNoNsProp #define xmlGetNsList vtklibxml2_xmlGetNsList +#define xmlGetNsListSafe vtklibxml2_xmlGetNsListSafe #define xmlGetNsProp vtklibxml2_xmlGetNsProp #define xmlGetParameterEntity vtklibxml2_xmlGetParameterEntity #define xmlGetPredefinedEntity vtklibxml2_xmlGetPredefinedEntity @@ -431,16 +380,15 @@ #define xmlGetRefs vtklibxml2_xmlGetRefs #define xmlGetThreadId vtklibxml2_xmlGetThreadId #define xmlGetUTF8Char vtklibxml2_xmlGetUTF8Char -#define __xmlGetWarningsDefaultValue vtklibxml2___xmlGetWarningsDefaultValue -#define xmlGetWarningsDefaultValue vtklibxml2_xmlGetWarningsDefaultValue -#define __xmlGlobalInitMutexDestroy vtklibxml2___xmlGlobalInitMutexDestroy -#define __xmlGlobalInitMutexLock vtklibxml2___xmlGlobalInitMutexLock -#define __xmlGlobalInitMutexUnlock vtklibxml2___xmlGlobalInitMutexUnlock #define xmlHasFeature vtklibxml2_xmlHasFeature +#define xmlHashAdd vtklibxml2_xmlHashAdd +#define xmlHashAdd2 vtklibxml2_xmlHashAdd2 +#define xmlHashAdd3 vtklibxml2_xmlHashAdd3 #define xmlHashAddEntry vtklibxml2_xmlHashAddEntry #define xmlHashAddEntry2 vtklibxml2_xmlHashAddEntry2 #define xmlHashAddEntry3 vtklibxml2_xmlHashAddEntry3 #define xmlHashCopy vtklibxml2_xmlHashCopy +#define xmlHashCopySafe vtklibxml2_xmlHashCopySafe #define xmlHashCreate vtklibxml2_xmlHashCreate #define xmlHashCreateDict vtklibxml2_xmlHashCreateDict #define xmlHashDefaultDeallocator vtklibxml2_xmlHashDefaultDeallocator @@ -464,12 +412,9 @@ #define xmlHashUpdateEntry3 vtklibxml2_xmlHashUpdateEntry3 #define xmlHasNsProp vtklibxml2_xmlHasNsProp #define xmlHasProp vtklibxml2_xmlHasProp -#define __xmlIndentTreeOutput vtklibxml2___xmlIndentTreeOutput -#define xmlIndentTreeOutput vtklibxml2_xmlIndentTreeOutput #define xmlInitCharEncodingHandlers vtklibxml2_xmlInitCharEncodingHandlers #define xmlInitGlobals vtklibxml2_xmlInitGlobals #define xmlInitializeCatalog vtklibxml2_xmlInitializeCatalog -#define __xmlInitializeDict vtklibxml2___xmlInitializeDict #define xmlInitializeDict vtklibxml2_xmlInitializeDict #define xmlInitializeGlobalState vtklibxml2_xmlInitializeGlobalState #define xmlInitMemory vtklibxml2_xmlInitMemory @@ -477,8 +422,6 @@ #define xmlInitParser vtklibxml2_xmlInitParser #define xmlInitParserCtxt vtklibxml2_xmlInitParserCtxt #define xmlInitThreads vtklibxml2_xmlInitThreads -#define xmlInputReadCallbackNop vtklibxml2_xmlInputReadCallbackNop -#define __xmlIOErr vtklibxml2___xmlIOErr #define xmlIOParseDTD vtklibxml2_xmlIOParseDTD #define xmlIsBaseChar vtklibxml2_xmlIsBaseChar #define xmlIsBaseCharGroup vtklibxml2_xmlIsBaseCharGroup @@ -503,14 +446,8 @@ #define xmlIsRef vtklibxml2_xmlIsRef #define xmlIsXHTML vtklibxml2_xmlIsXHTML #define xmlKeepBlanksDefault vtklibxml2_xmlKeepBlanksDefault -#define __xmlKeepBlanksDefaultValue vtklibxml2___xmlKeepBlanksDefaultValue -#define xmlKeepBlanksDefaultValue vtklibxml2_xmlKeepBlanksDefaultValue #define xmlLastElementChild vtklibxml2_xmlLastElementChild -#define __xmlLastError vtklibxml2___xmlLastError -#define xmlLastError vtklibxml2_xmlLastError #define xmlLineNumbersDefault vtklibxml2_xmlLineNumbersDefault -#define __xmlLineNumbersDefaultValue vtklibxml2___xmlLineNumbersDefaultValue -#define xmlLineNumbersDefaultValue vtklibxml2_xmlLineNumbersDefaultValue #define xmlLinkGetData vtklibxml2_xmlLinkGetData #define xmlListAppend vtklibxml2_xmlListAppend #define xmlListClear vtklibxml2_xmlListClear @@ -540,18 +477,11 @@ #define xmlLoadACatalog vtklibxml2_xmlLoadACatalog #define xmlLoadCatalog vtklibxml2_xmlLoadCatalog #define xmlLoadCatalogs vtklibxml2_xmlLoadCatalogs -#define __xmlLoaderErr vtklibxml2___xmlLoaderErr -#define __xmlLoadExtDtdDefaultValue vtklibxml2___xmlLoadExtDtdDefaultValue -#define xmlLoadExtDtdDefaultValue vtklibxml2_xmlLoadExtDtdDefaultValue #define xmlLoadExternalEntity vtklibxml2_xmlLoadExternalEntity #define xmlLoadSGMLSuperCatalog vtklibxml2_xmlLoadSGMLSuperCatalog #define xmlLockLibrary vtklibxml2_xmlLockLibrary -#define __xmlMalloc vtklibxml2___xmlMalloc -#define xmlMalloc vtklibxml2_xmlMalloc -#define __xmlMallocAtomic vtklibxml2___xmlMallocAtomic -#define xmlMallocAtomic vtklibxml2_xmlMallocAtomic +#define xmlLookupCharEncodingHandler vtklibxml2_xmlLookupCharEncodingHandler #define xmlMallocAtomicLoc vtklibxml2_xmlMallocAtomicLoc -#define xmlMallocBreakpoint vtklibxml2_xmlMallocBreakpoint #define xmlMallocLoc vtklibxml2_xmlMallocLoc #define xmlMemBlocks vtklibxml2_xmlMemBlocks #define xmlMemDisplay vtklibxml2_xmlMemDisplay @@ -564,8 +494,7 @@ #define xmlMemRealloc vtklibxml2_xmlMemRealloc #define xmlMemSetup vtklibxml2_xmlMemSetup #define xmlMemShow vtklibxml2_xmlMemShow -#define __xmlMemStrdup vtklibxml2___xmlMemStrdup -#define xmlMemStrdup vtklibxml2_xmlMemStrdup +#define xmlMemSize vtklibxml2_xmlMemSize #define xmlMemStrdupLoc vtklibxml2_xmlMemStrdupLoc #define xmlMemUsed vtklibxml2_xmlMemUsed #define xmlModuleClose vtklibxml2_xmlModuleClose @@ -610,6 +539,7 @@ #define xmlNewProp vtklibxml2_xmlNewProp #define xmlNewReference vtklibxml2_xmlNewReference #define xmlNewRMutex vtklibxml2_xmlNewRMutex +#define xmlNewSAXParserCtxt vtklibxml2_xmlNewSAXParserCtxt #define xmlNewStringInputStream vtklibxml2_xmlNewStringInputStream #define xmlNewText vtklibxml2_xmlNewText #define xmlNewTextChild vtklibxml2_xmlNewTextChild @@ -630,7 +560,9 @@ #define xmlNodeBufGetContent vtklibxml2_xmlNodeBufGetContent #define xmlNodeDump vtklibxml2_xmlNodeDump #define xmlNodeDumpOutput vtklibxml2_xmlNodeDumpOutput +#define xmlNodeGetAttrValue vtklibxml2_xmlNodeGetAttrValue #define xmlNodeGetBase vtklibxml2_xmlNodeGetBase +#define xmlNodeGetBaseSafe vtklibxml2_xmlNodeGetBaseSafe #define xmlNodeGetContent vtklibxml2_xmlNodeGetContent #define xmlNodeGetLang vtklibxml2_xmlNodeGetLang #define xmlNodeGetSpacePreserve vtklibxml2_xmlNodeGetSpacePreserve @@ -646,7 +578,7 @@ #define xmlNoNetExternalEntityLoader vtklibxml2_xmlNoNetExternalEntityLoader #define xmlNormalizeURIPath vtklibxml2_xmlNormalizeURIPath #define xmlNormalizeWindowsPath vtklibxml2_xmlNormalizeWindowsPath -#define xmlNsListDumpOutput vtklibxml2_xmlNsListDumpOutput +#define xmlOpenCharEncodingHandler vtklibxml2_xmlOpenCharEncodingHandler #define xmlOutputBufferClose vtklibxml2_xmlOutputBufferClose #define xmlOutputBufferCreateBuffer vtklibxml2_xmlOutputBufferCreateBuffer #define xmlOutputBufferCreateFd vtklibxml2_xmlOutputBufferCreateFd @@ -654,8 +586,6 @@ #define __xmlOutputBufferCreateFilename vtklibxml2___xmlOutputBufferCreateFilename #define xmlOutputBufferCreateFilename vtklibxml2_xmlOutputBufferCreateFilename #define xmlOutputBufferCreateFilenameDefault vtklibxml2_xmlOutputBufferCreateFilenameDefault -#define __xmlOutputBufferCreateFilenameValue vtklibxml2___xmlOutputBufferCreateFilenameValue -#define xmlOutputBufferCreateFilenameValue vtklibxml2_xmlOutputBufferCreateFilenameValue #define xmlOutputBufferCreateIO vtklibxml2_xmlOutputBufferCreateIO #define xmlOutputBufferFlush vtklibxml2_xmlOutputBufferFlush #define xmlOutputBufferGetContent vtklibxml2_xmlOutputBufferGetContent @@ -728,8 +658,6 @@ #define __xmlParserInputBufferCreateFilename vtklibxml2___xmlParserInputBufferCreateFilename #define xmlParserInputBufferCreateFilename vtklibxml2_xmlParserInputBufferCreateFilename #define xmlParserInputBufferCreateFilenameDefault vtklibxml2_xmlParserInputBufferCreateFilenameDefault -#define __xmlParserInputBufferCreateFilenameValue vtklibxml2___xmlParserInputBufferCreateFilenameValue -#define xmlParserInputBufferCreateFilenameValue vtklibxml2_xmlParserInputBufferCreateFilenameValue #define xmlParserInputBufferCreateIO vtklibxml2_xmlParserInputBufferCreateIO #define xmlParserInputBufferCreateMem vtklibxml2_xmlParserInputBufferCreateMem #define xmlParserInputBufferCreateStatic vtklibxml2_xmlParserInputBufferCreateStatic @@ -754,11 +682,13 @@ #define xmlParseURI vtklibxml2_xmlParseURI #define xmlParseURIRaw vtklibxml2_xmlParseURIRaw #define xmlParseURIReference vtklibxml2_xmlParseURIReference +#define xmlParseURISafe vtklibxml2_xmlParseURISafe #define xmlParseVersionInfo vtklibxml2_xmlParseVersionInfo #define xmlParseVersionNum vtklibxml2_xmlParseVersionNum #define xmlParseXMLDecl vtklibxml2_xmlParseXMLDecl #define xmlPathToURI vtklibxml2_xmlPathToURI #define xmlPatterncompile vtklibxml2_xmlPatterncompile +#define xmlPatternCompileSafe vtklibxml2_xmlPatternCompileSafe #define xmlPatternFromRoot vtklibxml2_xmlPatternFromRoot #define xmlPatternGetStreamCtxt vtklibxml2_xmlPatternGetStreamCtxt #define xmlPatternMatch vtklibxml2_xmlPatternMatch @@ -766,16 +696,12 @@ #define xmlPatternMinDepth vtklibxml2_xmlPatternMinDepth #define xmlPatternStreamable vtklibxml2_xmlPatternStreamable #define xmlPedanticParserDefault vtklibxml2_xmlPedanticParserDefault -#define __xmlPedanticParserDefaultValue vtklibxml2___xmlPedanticParserDefaultValue -#define xmlPedanticParserDefaultValue vtklibxml2_xmlPedanticParserDefaultValue #define xmlPopInput vtklibxml2_xmlPopInput #define xmlPopInputCallbacks vtklibxml2_xmlPopInputCallbacks #define xmlPopOutputCallbacks vtklibxml2_xmlPopOutputCallbacks #define xmlPreviousElementSibling vtklibxml2_xmlPreviousElementSibling #define xmlPrintURI vtklibxml2_xmlPrintURI #define xmlPushInput vtklibxml2_xmlPushInput -#define __xmlRaiseError vtklibxml2___xmlRaiseError -#define __xmlRandom vtklibxml2___xmlRandom #define xmlReadDoc vtklibxml2_xmlReadDoc #define xmlReaderForDoc vtklibxml2_xmlReaderForDoc #define xmlReaderForFd vtklibxml2_xmlReaderForFd @@ -793,8 +719,6 @@ #define xmlReadFile vtklibxml2_xmlReadFile #define xmlReadIO vtklibxml2_xmlReadIO #define xmlReadMemory vtklibxml2_xmlReadMemory -#define __xmlRealloc vtklibxml2___xmlRealloc -#define xmlRealloc vtklibxml2_xmlRealloc #define xmlReallocLoc vtklibxml2_xmlReallocLoc #define xmlReconciliateNs vtklibxml2_xmlReconciliateNs #define xmlRecoverDoc vtklibxml2_xmlRecoverDoc @@ -810,14 +734,11 @@ #define xmlRegexpPrint vtklibxml2_xmlRegexpPrint #define xmlRegFreeExecCtxt vtklibxml2_xmlRegFreeExecCtxt #define xmlRegFreeRegexp vtklibxml2_xmlRegFreeRegexp -#define __xmlRegisterCallbacks vtklibxml2___xmlRegisterCallbacks #define xmlRegisterCharEncodingHandler vtklibxml2_xmlRegisterCharEncodingHandler #define xmlRegisterDefaultInputCallbacks vtklibxml2_xmlRegisterDefaultInputCallbacks #define xmlRegisterDefaultOutputCallbacks vtklibxml2_xmlRegisterDefaultOutputCallbacks #define xmlRegisterInputCallbacks vtklibxml2_xmlRegisterInputCallbacks #define xmlRegisterNodeDefault vtklibxml2_xmlRegisterNodeDefault -#define __xmlRegisterNodeDefaultValue vtklibxml2___xmlRegisterNodeDefaultValue -#define xmlRegisterNodeDefaultValue vtklibxml2_xmlRegisterNodeDefaultValue #define xmlRegisterOutputCallbacks vtklibxml2_xmlRegisterOutputCallbacks #define xmlRegNewExecCtxt vtklibxml2_xmlRegNewExecCtxt #define xmlRelaxNGCleanupTypes vtklibxml2_xmlRelaxNGCleanupTypes @@ -857,12 +778,11 @@ #define xmlSaveFile vtklibxml2_xmlSaveFile #define xmlSaveFileEnc vtklibxml2_xmlSaveFileEnc #define xmlSaveFileTo vtklibxml2_xmlSaveFileTo +#define xmlSaveFinish vtklibxml2_xmlSaveFinish #define xmlSaveFlush vtklibxml2_xmlSaveFlush #define xmlSaveFormatFile vtklibxml2_xmlSaveFormatFile #define xmlSaveFormatFileEnc vtklibxml2_xmlSaveFormatFileEnc #define xmlSaveFormatFileTo vtklibxml2_xmlSaveFormatFileTo -#define __xmlSaveNoEmptyTags vtklibxml2___xmlSaveNoEmptyTags -#define xmlSaveNoEmptyTags vtklibxml2_xmlSaveNoEmptyTags #define xmlSaveSetAttrEscape vtklibxml2_xmlSaveSetAttrEscape #define xmlSaveSetEscape vtklibxml2_xmlSaveSetEscape #define xmlSaveToBuffer vtklibxml2_xmlSaveToBuffer @@ -891,7 +811,6 @@ #define xmlSAX2HasInternalSubset vtklibxml2_xmlSAX2HasInternalSubset #define xmlSAX2IgnorableWhitespace vtklibxml2_xmlSAX2IgnorableWhitespace #define xmlSAX2InitDefaultSAXHandler vtklibxml2_xmlSAX2InitDefaultSAXHandler -#define xmlSAX2InitDocbDefaultSAXHandler vtklibxml2_xmlSAX2InitDocbDefaultSAXHandler #define xmlSAX2InitHtmlDefaultSAXHandler vtklibxml2_xmlSAX2InitHtmlDefaultSAXHandler #define xmlSAX2InternalSubset vtklibxml2_xmlSAX2InternalSubset #define xmlSAX2IsStandalone vtklibxml2_xmlSAX2IsStandalone @@ -1002,7 +921,6 @@ #define xmlSetStructuredErrorFunc vtklibxml2_xmlSetStructuredErrorFunc #define xmlSetTreeDoc vtklibxml2_xmlSetTreeDoc #define xmlSetupParserForBuffer vtklibxml2_xmlSetupParserForBuffer -#define __xmlSimpleError vtklibxml2___xmlSimpleError #define xmlSkipBlankChars vtklibxml2_xmlSkipBlankChars #define xmlSnprintfElementContent vtklibxml2_xmlSnprintfElementContent #define xmlSplitQName vtklibxml2_xmlSplitQName @@ -1040,15 +958,10 @@ #define xmlStrQEqual vtklibxml2_xmlStrQEqual #define xmlStrstr vtklibxml2_xmlStrstr #define xmlStrsub vtklibxml2_xmlStrsub -#define __xmlStructuredError vtklibxml2___xmlStructuredError -#define xmlStructuredError vtklibxml2_xmlStructuredError -#define __xmlStructuredErrorContext vtklibxml2___xmlStructuredErrorContext -#define xmlStructuredErrorContext vtklibxml2_xmlStructuredErrorContext #define xmlStrVPrintf vtklibxml2_xmlStrVPrintf #define xmlSubstituteEntitiesDefault vtklibxml2_xmlSubstituteEntitiesDefault -#define __xmlSubstituteEntitiesDefaultValue vtklibxml2___xmlSubstituteEntitiesDefaultValue -#define xmlSubstituteEntitiesDefaultValue vtklibxml2_xmlSubstituteEntitiesDefaultValue #define xmlSwitchEncoding vtklibxml2_xmlSwitchEncoding +#define xmlSwitchEncodingName vtklibxml2_xmlSwitchEncodingName #define xmlSwitchInputEncoding vtklibxml2_xmlSwitchInputEncoding #define xmlSwitchToEncoding vtklibxml2_xmlSwitchToEncoding #define xmlTextConcat vtklibxml2_xmlTextConcat @@ -1075,6 +988,7 @@ #define xmlTextReaderGetAttributeNo vtklibxml2_xmlTextReaderGetAttributeNo #define xmlTextReaderGetAttributeNs vtklibxml2_xmlTextReaderGetAttributeNs #define xmlTextReaderGetErrorHandler vtklibxml2_xmlTextReaderGetErrorHandler +#define xmlTextReaderGetLastError vtklibxml2_xmlTextReaderGetLastError #define xmlTextReaderGetParserColumnNumber vtklibxml2_xmlTextReaderGetParserColumnNumber #define xmlTextReaderGetParserLineNumber vtklibxml2_xmlTextReaderGetParserLineNumber #define xmlTextReaderGetParserProp vtklibxml2_xmlTextReaderGetParserProp @@ -1117,6 +1031,7 @@ #define xmlTextReaderSchemaValidate vtklibxml2_xmlTextReaderSchemaValidate #define xmlTextReaderSchemaValidateCtxt vtklibxml2_xmlTextReaderSchemaValidateCtxt #define xmlTextReaderSetErrorHandler vtklibxml2_xmlTextReaderSetErrorHandler +#define xmlTextReaderSetMaxAmplification vtklibxml2_xmlTextReaderSetMaxAmplification #define xmlTextReaderSetParserProp vtklibxml2_xmlTextReaderSetParserProp #define xmlTextReaderSetSchema vtklibxml2_xmlTextReaderSetSchema #define xmlTextReaderSetStructuredErrorHandler vtklibxml2_xmlTextReaderSetStructuredErrorHandler @@ -1124,6 +1039,7 @@ #define xmlTextReaderStandalone vtklibxml2_xmlTextReaderStandalone #define xmlTextReaderValue vtklibxml2_xmlTextReaderValue #define xmlTextReaderXmlLang vtklibxml2_xmlTextReaderXmlLang +#define xmlTextWriterClose vtklibxml2_xmlTextWriterClose #define xmlTextWriterEndAttribute vtklibxml2_xmlTextWriterEndAttribute #define xmlTextWriterEndCDATA vtklibxml2_xmlTextWriterEndCDATA #define xmlTextWriterEndComment vtklibxml2_xmlTextWriterEndComment @@ -1216,8 +1132,6 @@ #define xmlThrDefSetStructuredErrorFunc vtklibxml2_xmlThrDefSetStructuredErrorFunc #define xmlThrDefSubstituteEntitiesDefaultValue vtklibxml2_xmlThrDefSubstituteEntitiesDefaultValue #define xmlThrDefTreeIndentString vtklibxml2_xmlThrDefTreeIndentString -#define __xmlTreeIndentString vtklibxml2___xmlTreeIndentString -#define xmlTreeIndentString vtklibxml2_xmlTreeIndentString #define xmlUCSIsAegeanNumbers vtklibxml2_xmlUCSIsAegeanNumbers #define xmlUCSIsAlphabeticPresentationForms vtklibxml2_xmlUCSIsAlphabeticPresentationForms #define xmlUCSIsArabic vtklibxml2_xmlUCSIsArabic @@ -1430,6 +1344,7 @@ #define xmlValidGetValidElements vtklibxml2_xmlValidGetValidElements #define xmlValidNormalizeAttributeValue vtklibxml2_xmlValidNormalizeAttributeValue #define xmlXIncludeFreeContext vtklibxml2_xmlXIncludeFreeContext +#define xmlXIncludeGetLastError vtklibxml2_xmlXIncludeGetLastError #define xmlXIncludeNewContext vtklibxml2_xmlXIncludeNewContext #define xmlXIncludeProcess vtklibxml2_xmlXIncludeProcess #define xmlXIncludeProcessFlags vtklibxml2_xmlXIncludeProcessFlags @@ -1438,6 +1353,7 @@ #define xmlXIncludeProcessTree vtklibxml2_xmlXIncludeProcessTree #define xmlXIncludeProcessTreeFlags vtklibxml2_xmlXIncludeProcessTreeFlags #define xmlXIncludeProcessTreeFlagsData vtklibxml2_xmlXIncludeProcessTreeFlagsData +#define xmlXIncludeSetErrorHandler vtklibxml2_xmlXIncludeSetErrorHandler #define xmlXIncludeSetFlags vtklibxml2_xmlXIncludeSetFlags #define xmlXPathAddValues vtklibxml2_xmlXPathAddValues #define xmlXPathBooleanFunction vtklibxml2_xmlXPathBooleanFunction @@ -1575,6 +1491,7 @@ #define xmlXPathRoot vtklibxml2_xmlXPathRoot #define xmlXPathRoundFunction vtklibxml2_xmlXPathRoundFunction #define xmlXPathSetContextNode vtklibxml2_xmlXPathSetContextNode +#define xmlXPathSetErrorHandler vtklibxml2_xmlXPathSetErrorHandler #define xmlXPathStartsWithFunction vtklibxml2_xmlXPathStartsWithFunction #define xmlXPathStringEvalNumber vtklibxml2_xmlXPathStringEvalNumber #define xmlXPathStringFunction vtklibxml2_xmlXPathStringFunction @@ -1595,27 +1512,7 @@ #define xmlXPathWrapExternal vtklibxml2_xmlXPathWrapExternal #define xmlXPathWrapNodeSet vtklibxml2_xmlXPathWrapNodeSet #define xmlXPathWrapString vtklibxml2_xmlXPathWrapString -#define xmlXPtrAdvanceNode vtklibxml2_xmlXPtrAdvanceNode -#define xmlXPtrBuildNodeList vtklibxml2_xmlXPtrBuildNodeList #define xmlXPtrEval vtklibxml2_xmlXPtrEval -#define xmlXPtrEvalRangePredicate vtklibxml2_xmlXPtrEvalRangePredicate -#define xmlXPtrFreeLocationSet vtklibxml2_xmlXPtrFreeLocationSet -#define xmlXPtrLocationSetAdd vtklibxml2_xmlXPtrLocationSetAdd -#define xmlXPtrLocationSetCreate vtklibxml2_xmlXPtrLocationSetCreate -#define xmlXPtrLocationSetDel vtklibxml2_xmlXPtrLocationSetDel -#define xmlXPtrLocationSetMerge vtklibxml2_xmlXPtrLocationSetMerge -#define xmlXPtrLocationSetRemove vtklibxml2_xmlXPtrLocationSetRemove -#define xmlXPtrNewCollapsedRange vtklibxml2_xmlXPtrNewCollapsedRange #define xmlXPtrNewContext vtklibxml2_xmlXPtrNewContext -#define xmlXPtrNewLocationSetNodes vtklibxml2_xmlXPtrNewLocationSetNodes -#define xmlXPtrNewLocationSetNodeSet vtklibxml2_xmlXPtrNewLocationSetNodeSet -#define xmlXPtrNewRange vtklibxml2_xmlXPtrNewRange -#define xmlXPtrNewRangeNodeObject vtklibxml2_xmlXPtrNewRangeNodeObject -#define xmlXPtrNewRangeNodePoint vtklibxml2_xmlXPtrNewRangeNodePoint -#define xmlXPtrNewRangeNodes vtklibxml2_xmlXPtrNewRangeNodes -#define xmlXPtrNewRangePointNode vtklibxml2_xmlXPtrNewRangePointNode -#define xmlXPtrNewRangePoints vtklibxml2_xmlXPtrNewRangePoints -#define xmlXPtrRangeToFunction vtklibxml2_xmlXPtrRangeToFunction -#define xmlXPtrWrapLocationSet vtklibxml2_xmlXPtrWrapLocationSet #endif diff --git a/include/libxml/xinclude.h b/include/libxml/xinclude.h index 863ab25ad9f..71fa4c20dc2 100644 --- a/include/libxml/xinclude.h +++ b/include/libxml/xinclude.h @@ -14,6 +14,7 @@ #define __XML_XINCLUDE_H__ #include +#include #include #ifdef LIBXML_XINCLUDE_ENABLED @@ -89,35 +90,41 @@ typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr; /* * standalone processing */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcess (xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessFlags (xmlDocPtr doc, int flags); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessTree (xmlNodePtr tree); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags); /* * contextual processing */ -XMLPUBFUN xmlXIncludeCtxtPtr XMLCALL +XMLPUBFUN xmlXIncludeCtxtPtr xmlXIncludeNewContext (xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, int flags); -XMLPUBFUN void XMLCALL +XMLPUBFUN void + xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); +XMLPUBFUN int + xmlXIncludeGetLastError (xmlXIncludeCtxtPtr ctxt); +XMLPUBFUN void xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXIncludeProcessNode (xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree); #ifdef __cplusplus diff --git a/include/libxml/xlink.h b/include/libxml/xlink.h index 04e4b32c015..106573666ae 100644 --- a/include/libxml/xlink.h +++ b/include/libxml/xlink.h @@ -160,23 +160,23 @@ struct _xlinkHandler { * detection callbacks. */ -XMLPUBFUN xlinkNodeDetectFunc XMLCALL +XMLPUBFUN xlinkNodeDetectFunc xlinkGetDefaultDetect (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xlinkSetDefaultDetect (xlinkNodeDetectFunc func); /* * Routines to set/get the default handlers. */ -XMLPUBFUN xlinkHandlerPtr XMLCALL +XMLPUBFUN xlinkHandlerPtr xlinkGetDefaultHandler (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xlinkSetDefaultHandler (xlinkHandlerPtr handler); /* * Link detection module itself. */ -XMLPUBFUN xlinkType XMLCALL +XMLPUBFUN xlinkType xlinkIsLink (xmlDocPtr doc, xmlNodePtr node); diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h index 095b2f56d96..7810e42a86e 100644 --- a/include/libxml/xmlIO.h +++ b/include/libxml/xmlIO.h @@ -10,8 +10,14 @@ #ifndef __XML_IO_H__ #define __XML_IO_H__ +/** DOC_DISABLE */ #include #include +#include +#define XML_TREE_INTERNALS +#include +#undef XML_TREE_INTERNALS +/** DOC_ENABLE */ #ifdef __cplusplus extern "C" { @@ -31,7 +37,7 @@ extern "C" { * * Returns 1 if yes and 0 if another Input module should be used */ -typedef int (XMLCALL *xmlInputMatchCallback) (char const *filename); +typedef int (*xmlInputMatchCallback) (char const *filename); /** * xmlInputOpenCallback: * @filename: the filename or URI @@ -40,7 +46,7 @@ typedef int (XMLCALL *xmlInputMatchCallback) (char const *filename); * * Returns an Input context or NULL in case or error */ -typedef void * (XMLCALL *xmlInputOpenCallback) (char const *filename); +typedef void * (*xmlInputOpenCallback) (char const *filename); /** * xmlInputReadCallback: * @context: an Input context @@ -51,7 +57,7 @@ typedef void * (XMLCALL *xmlInputOpenCallback) (char const *filename); * * Returns the number of bytes read or -1 in case of error */ -typedef int (XMLCALL *xmlInputReadCallback) (void * context, char * buffer, int len); +typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); /** * xmlInputCloseCallback: * @context: an Input context @@ -60,7 +66,7 @@ typedef int (XMLCALL *xmlInputReadCallback) (void * context, char * buffer, int * * Returns 0 or -1 in case of error */ -typedef int (XMLCALL *xmlInputCloseCallback) (void * context); +typedef int (*xmlInputCloseCallback) (void * context); #ifdef LIBXML_OUTPUT_ENABLED /* @@ -77,7 +83,7 @@ typedef int (XMLCALL *xmlInputCloseCallback) (void * context); * * Returns 1 if yes and 0 if another Output module should be used */ -typedef int (XMLCALL *xmlOutputMatchCallback) (char const *filename); +typedef int (*xmlOutputMatchCallback) (char const *filename); /** * xmlOutputOpenCallback: * @filename: the filename or URI @@ -86,7 +92,7 @@ typedef int (XMLCALL *xmlOutputMatchCallback) (char const *filename); * * Returns an Output context or NULL in case or error */ -typedef void * (XMLCALL *xmlOutputOpenCallback) (char const *filename); +typedef void * (*xmlOutputOpenCallback) (char const *filename); /** * xmlOutputWriteCallback: * @context: an Output context @@ -97,7 +103,7 @@ typedef void * (XMLCALL *xmlOutputOpenCallback) (char const *filename); * * Returns the number of bytes written or -1 in case of error */ -typedef int (XMLCALL *xmlOutputWriteCallback) (void * context, const char * buffer, +typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, int len); /** * xmlOutputCloseCallback: @@ -107,21 +113,38 @@ typedef int (XMLCALL *xmlOutputWriteCallback) (void * context, const char * buff * * Returns 0 or -1 in case of error */ -typedef int (XMLCALL *xmlOutputCloseCallback) (void * context); +typedef int (*xmlOutputCloseCallback) (void * context); #endif /* LIBXML_OUTPUT_ENABLED */ -#ifdef __cplusplus -} -#endif +/** + * 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); -#include -#include -#include -#include +/** + * 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); -#ifdef __cplusplus -extern "C" { -#endif struct _xmlParserInputBuffer { void* context; xmlInputReadCallback readcallback; @@ -152,56 +175,78 @@ struct _xmlOutputBuffer { }; #endif /* LIBXML_OUTPUT_ENABLED */ +/** DOC_DISABLE */ +#define XML_GLOBALS_IO \ + XML_OP(xmlParserInputBufferCreateFilenameValue, \ + xmlParserInputBufferCreateFilenameFunc, XML_DEPRECATED) \ + XML_OP(xmlOutputBufferCreateFilenameValue, \ + xmlOutputBufferCreateFilenameFunc, XML_DEPRECATED) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_IO +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlParserInputBufferCreateFilenameValue \ + XML_GLOBAL_MACRO(xmlParserInputBufferCreateFilenameValue) + #define xmlOutputBufferCreateFilenameValue \ + XML_GLOBAL_MACRO(xmlOutputBufferCreateFilenameValue) +#else +#define xmlParserInputBufferCreateFilenameValue vtklibxml2_xmlParserInputBufferCreateFilenameValue +#define xmlOutputBufferCreateFilenameValue vtklibxml2_xmlOutputBufferCreateFilenameValue +#endif +/** DOC_ENABLE */ + /* * Interfaces for input */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupInputCallbacks (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPopInputCallbacks (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRegisterDefaultInputCallbacks (void); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlAllocParserInputBuffer (xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateFilename (const char *URI, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateFile (FILE *file, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateFd (int fd, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateMem (const char *mem, int size, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateStatic (const char *mem, int size, xmlCharEncoding enc); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlParserInputBufferCreateIO (xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParserInputBufferRead (xmlParserInputBufferPtr in, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParserInputBufferGrow (xmlParserInputBufferPtr in, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlParserInputBufferPush (xmlParserInputBufferPtr in, int len, const char *buf); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeParserInputBuffer (xmlParserInputBufferPtr in); -XMLPUBFUN char * XMLCALL +XMLPUBFUN char * xmlParserGetDirectory (const char *filename); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc, xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, @@ -215,62 +260,62 @@ xmlParserInputBufferPtr /* * Interfaces for output */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupOutputCallbacks (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlPopOutputCallbacks (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRegisterDefaultOutputCallbacks(void); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlAllocOutputBuffer (xmlCharEncodingHandlerPtr encoder); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlOutputBufferCreateFilename (const char *URI, xmlCharEncodingHandlerPtr encoder, int compression); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlOutputBufferCreateFile (FILE *file, xmlCharEncodingHandlerPtr encoder); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlOutputBufferCreateBuffer (xmlBufferPtr buffer, xmlCharEncodingHandlerPtr encoder); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlOutputBufferCreateFd (int fd, xmlCharEncodingHandlerPtr encoder); -XMLPUBFUN xmlOutputBufferPtr XMLCALL +XMLPUBFUN xmlOutputBufferPtr xmlOutputBufferCreateIO (xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose, void *ioctx, xmlCharEncodingHandlerPtr encoder); /* Couple of APIs to get the output without digging into the buffers */ -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlOutputBufferGetContent (xmlOutputBufferPtr out); -XMLPUBFUN size_t XMLCALL +XMLPUBFUN size_t xmlOutputBufferGetSize (xmlOutputBufferPtr out); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlOutputBufferWrite (xmlOutputBufferPtr out, int len, const char *buf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlOutputBufferWriteString (xmlOutputBufferPtr out, const char *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlOutputBufferWriteEscape (xmlOutputBufferPtr out, const xmlChar *str, xmlCharEncodingOutputFunc escaping); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlOutputBufferFlush (xmlOutputBufferPtr out); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlOutputBufferClose (xmlOutputBufferPtr out); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegisterOutputCallbacks (xmlOutputMatchCallback matchFunc, xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, @@ -283,83 +328,111 @@ xmlOutputBufferPtr #ifdef LIBXML_HTTP_ENABLED /* This function only exists if HTTP support built into the library */ -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlRegisterHTTPPostCallbacks (void ); #endif /* LIBXML_HTTP_ENABLED */ #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN xmlParserInputPtr XMLCALL +XML_DEPRECATED +XMLPUBFUN xmlParserInputPtr xmlCheckHTTPInput (xmlParserCtxtPtr ctxt, xmlParserInputPtr ret); /* * A predefined entity loader disabling network accesses */ -XMLPUBFUN xmlParserInputPtr XMLCALL +XMLPUBFUN xmlParserInputPtr 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 +XML_DEPRECATED +XMLPUBFUN xmlChar * xmlNormalizeWindowsPath (const xmlChar *path); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlCheckFilename (const char *path); /** * Default 'file://' protocol callbacks */ -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlFileMatch (const char *filename); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlFileOpen (const char *filename); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlFileRead (void * context, char * buffer, int len); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlFileClose (void * context); /** * Default 'http://' protocol callbacks */ #ifdef LIBXML_HTTP_ENABLED -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIOHTTPMatch (const char *filename); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlIOHTTPOpen (const char *filename); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlIOHTTPOpenW (const char * post_uri, int compression ); #endif /* LIBXML_OUTPUT_ENABLED */ -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIOHTTPRead (void * context, char * buffer, int len); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIOHTTPClose (void * context); #endif /* LIBXML_HTTP_ENABLED */ /** * Default 'ftp://' protocol callbacks */ -#ifdef LIBXML_FTP_ENABLED -XMLPUBFUN int XMLCALL +#if defined(LIBXML_FTP_ENABLED) +XML_DEPRECATED +XMLPUBFUN int xmlIOFTPMatch (const char *filename); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlIOFTPOpen (const char *filename); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIOFTPRead (void * context, char * buffer, int len); -XMLPUBFUN int XMLCALL +XML_DEPRECATED +XMLPUBFUN int xmlIOFTPClose (void * context); -#endif /* LIBXML_FTP_ENABLED */ +#endif /* defined(LIBXML_FTP_ENABLED) */ + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc + xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func); +XMLPUBFUN xmlOutputBufferCreateFilenameFunc + xmlOutputBufferCreateFilenameDefault( + xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED +XMLPUBFUN xmlOutputBufferCreateFilenameFunc + xmlThrDefOutputBufferCreateFilenameDefault( + xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc + xmlThrDefParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func); #ifdef __cplusplus } diff --git a/include/libxml/xmlautomata.h b/include/libxml/xmlautomata.h index bf1b131c653..ea38eb37f09 100644 --- a/include/libxml/xmlautomata.h +++ b/include/libxml/xmlautomata.h @@ -11,11 +11,11 @@ #define __XML_AUTOMATA_H__ #include -#include #ifdef LIBXML_REGEXP_ENABLED #ifdef LIBXML_AUTOMATA_ENABLED -#include + +#include #ifdef __cplusplus extern "C" { @@ -40,32 +40,32 @@ typedef xmlAutomataState *xmlAutomataStatePtr; /* * Building API */ -XMLPUBFUN xmlAutomataPtr XMLCALL +XMLPUBFUN xmlAutomataPtr xmlNewAutomata (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeAutomata (xmlAutomataPtr am); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataGetInitState (xmlAutomataPtr am); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlAutomataSetFinalState (xmlAutomataPtr am, xmlAutomataStatePtr state); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewState (xmlAutomataPtr am); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewTransition (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, const xmlChar *token, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewTransition2 (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, const xmlChar *token, const xmlChar *token2, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewNegTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, @@ -73,7 +73,7 @@ XMLPUBFUN xmlAutomataStatePtr XMLCALL const xmlChar *token2, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewCountTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, @@ -81,7 +81,7 @@ XMLPUBFUN xmlAutomataStatePtr XMLCALL int min, int max, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewCountTrans2 (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, @@ -90,7 +90,7 @@ XMLPUBFUN xmlAutomataStatePtr XMLCALL int min, int max, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewOnceTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, @@ -98,7 +98,7 @@ XMLPUBFUN xmlAutomataStatePtr XMLCALL int min, int max, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewOnceTrans2 (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, @@ -107,33 +107,33 @@ XMLPUBFUN xmlAutomataStatePtr XMLCALL int min, int max, void *data); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewAllTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, int lax); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewEpsilon (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewCountedTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, int counter); -XMLPUBFUN xmlAutomataStatePtr XMLCALL +XMLPUBFUN xmlAutomataStatePtr xmlAutomataNewCounterTrans (xmlAutomataPtr am, xmlAutomataStatePtr from, xmlAutomataStatePtr to, int counter); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlAutomataNewCounter (xmlAutomataPtr am, int min, int max); -XMLPUBFUN xmlRegexpPtr XMLCALL +XMLPUBFUN struct _xmlRegexp * xmlAutomataCompile (xmlAutomataPtr am); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlAutomataIsDeterminist (xmlAutomataPtr am); #ifdef __cplusplus diff --git a/include/libxml/xmlerror.h b/include/libxml/xmlerror.h index ee95be9c9c2..bd075b89c81 100644 --- a/include/libxml/xmlerror.h +++ b/include/libxml/xmlerror.h @@ -7,11 +7,11 @@ * Author: Daniel Veillard */ -#include - #ifndef __XML_ERROR_H__ #define __XML_ERROR_H__ +#include + #ifdef __cplusplus extern "C" { #endif @@ -210,6 +210,12 @@ typedef enum { XML_ERR_NAME_TOO_LONG, /* 110 */ XML_ERR_USER_STOP, /* 111 */ XML_ERR_COMMENT_ABRUPTLY_ENDED, /* 112 */ + XML_WAR_ENCODING_MISMATCH, /* 113 */ + XML_ERR_RESOURCE_LIMIT, /* 114 */ + XML_ERR_ARGUMENT, /* 115 */ + XML_ERR_SYSTEM, /* 116 */ + XML_ERR_REDECL_PREDEF_ENTITY, /* 117 */ + XML_ERR_INT_SUBSET_NOT_FINISHED, /* 118 */ XML_NS_ERR_XML_NAMESPACE = 200, XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */ XML_NS_ERR_QNAME, /* 202 */ @@ -472,6 +478,7 @@ typedef enum { XML_IO_EADDRINUSE, /* 1554 */ XML_IO_EALREADY, /* 1555 */ XML_IO_EAFNOSUPPORT, /* 1556 */ + XML_IO_UNSUPPORTED_PROTOCOL, /* 1557 */ XML_XINCLUDE_RECURSION=1600, XML_XINCLUDE_PARSE_VALUE, /* 1601 */ XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */ @@ -844,7 +851,7 @@ typedef enum { * Signature of the function to use when there is an error and * no parsing or validity context available . */ -typedef void (XMLCDECL *xmlGenericErrorFunc) (void *ctx, +typedef void (*xmlGenericErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** @@ -855,92 +862,106 @@ typedef void (XMLCDECL *xmlGenericErrorFunc) (void *ctx, * 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); +typedef void (*xmlStructuredErrorFunc) (void *userData, const xmlError *error); + +/** DOC_DISABLE */ +#define XML_GLOBALS_ERROR \ + XML_OP(xmlLastError, xmlError, XML_DEPRECATED) \ + XML_OP(xmlGenericError, xmlGenericErrorFunc, XML_NO_ATTR) \ + XML_OP(xmlGenericErrorContext, void *, XML_NO_ATTR) \ + XML_OP(xmlStructuredError, xmlStructuredErrorFunc, XML_NO_ATTR) \ + XML_OP(xmlStructuredErrorContext, void *, XML_NO_ATTR) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_ERROR +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlLastError XML_GLOBAL_MACRO(xmlLastError) + #define xmlGenericError XML_GLOBAL_MACRO(xmlGenericError) + #define xmlGenericErrorContext XML_GLOBAL_MACRO(xmlGenericErrorContext) + #define xmlStructuredError XML_GLOBAL_MACRO(xmlStructuredError) + #define xmlStructuredErrorContext XML_GLOBAL_MACRO(xmlStructuredErrorContext) +#else +#define xmlLastError vtklibxml2_xmlLastError +#define xmlGenericError vtklibxml2_xmlGenericError +#define xmlGenericErrorContext vtklibxml2_xmlGenericErrorContext +#define xmlStructuredError vtklibxml2_xmlStructuredError +#define xmlStructuredErrorContext vtklibxml2_xmlStructuredErrorContext +#endif +/** DOC_ENABLE */ /* * Use the following function to reset the two global variables * xmlGenericError and xmlGenericErrorContext. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetGenericErrorFunc (void *ctx, xmlGenericErrorFunc handler); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void + xmlThrDefSetGenericErrorFunc(void *ctx, + xmlGenericErrorFunc handler); +XML_DEPRECATED +XMLPUBFUN void initGenericErrorDefaultFunc (xmlGenericErrorFunc *handler); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSetStructuredErrorFunc (void *ctx, xmlStructuredErrorFunc handler); +XML_DEPRECATED +XMLPUBFUN void + xmlThrDefSetStructuredErrorFunc(void *ctx, + xmlStructuredErrorFunc handler); /* * Default message routines used by SAX and Valid context for error * and warning reporting. */ -XMLPUBFUN void XMLCDECL +XMLPUBFUN void xmlParserError (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); -XMLPUBFUN void XMLCDECL +XMLPUBFUN void xmlParserWarning (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); -XMLPUBFUN void XMLCDECL +XMLPUBFUN void xmlParserValidityError (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); -XMLPUBFUN void XMLCDECL +XMLPUBFUN void xmlParserValidityWarning (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); -XMLPUBFUN void XMLCALL - xmlParserPrintFileInfo (xmlParserInputPtr input); -XMLPUBFUN void XMLCALL - xmlParserPrintFileContext (xmlParserInputPtr input); +/** DOC_DISABLE */ +struct _xmlParserInput; +/** DOC_ENABLE */ +XMLPUBFUN void + xmlParserPrintFileInfo (struct _xmlParserInput *input); +XMLPUBFUN void + xmlParserPrintFileContext (struct _xmlParserInput *input); +XMLPUBFUN void +xmlFormatError (const xmlError *err, + xmlGenericErrorFunc channel, + void *data); /* * Extended error information routines */ -XMLPUBFUN xmlErrorPtr XMLCALL +XMLPUBFUN const xmlError * xmlGetLastError (void); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlResetLastError (void); -XMLPUBFUN xmlErrorPtr XMLCALL +XMLPUBFUN const xmlError * xmlCtxtGetLastError (void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCtxtResetLastError (void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlResetError (xmlErrorPtr err); -XMLPUBFUN int XMLCALL - xmlCopyError (xmlErrorPtr from, +XMLPUBFUN int + xmlCopyError (const xmlError *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) LIBXML_ATTR_FORMAT(4,0); -#endif #ifdef __cplusplus } #endif diff --git a/include/libxml/xmlexports.h b/include/libxml/xmlexports.h index 8831c54029e..cc121f2f6ea 100644 --- a/include/libxml/xmlexports.h +++ b/include/libxml/xmlexports.h @@ -10,68 +10,137 @@ #include "vtk_libxml2_mangle.h" -#if defined(_WIN32) || defined(__CYGWIN__) /** DOC_DISABLE */ -#ifdef LIBXML_STATIC +/* + * Symbol visibility + */ + +#if defined(_WIN32) || defined(__CYGWIN__) + #ifdef LIBXML_STATIC + #define XMLPUBLIC + #elif defined(IN_LIBXML) + #define XMLPUBLIC __declspec(dllexport) + #else + #define XMLPUBLIC __declspec(dllimport) + #endif +#else /* not Windows */ #define XMLPUBLIC -#elif defined(IN_LIBXML) - #define XMLPUBLIC __declspec(dllexport) +#endif /* platform switch */ + +#define XMLPUBFUN XMLPUBLIC + +#define XMLPUBVAR XMLPUBLIC extern + +/* Compatibility */ +#define XMLCALL +#define XMLCDECL +#ifndef LIBXML_DLL_IMPORT + #define LIBXML_DLL_IMPORT XMLPUBVAR +#endif + +/* + * Attributes + */ + +#ifndef ATTRIBUTE_UNUSED + #if __GNUC__ * 100 + __GNUC_MINOR__ >= 207 || defined(__clang__) + #define ATTRIBUTE_UNUSED __attribute__((unused)) + #else + #define ATTRIBUTE_UNUSED + #endif +#endif + +#if !defined(__clang__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) + #define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) #else - #define XMLPUBLIC __declspec(dllimport) + #define LIBXML_ATTR_ALLOC_SIZE(x) #endif -#if defined(LIBXML_FASTCALL) - #define XMLCALL __fastcall +#if __GNUC__ * 100 + __GNUC_MINOR__ >= 303 + #define LIBXML_ATTR_FORMAT(fmt,args) \ + __attribute__((__format__(__printf__,fmt,args))) #else - #define XMLCALL __cdecl + #define LIBXML_ATTR_FORMAT(fmt,args) #endif -#define XMLCDECL __cdecl -/** DOC_ENABLE */ -#else /* not Windows */ +#ifndef XML_DEPRECATED + #if defined(IN_LIBXML) + #define XML_DEPRECATED + #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 301 + #define XML_DEPRECATED __attribute__((deprecated)) + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + /* Available since Visual Studio 2005 */ + #define XML_DEPRECATED __declspec(deprecated) + #else + #define XML_DEPRECATED + #endif +#endif -/** - * XMLPUBLIC: - * - * Macro which declares a public symbol +/* + * Warnings pragmas, should be moved from public headers */ -#define XMLPUBLIC -/** - * XMLCALL: - * - * Macro which declares the calling convention for exported functions - */ -#define XMLCALL +#if defined(__LCC__) -/** - * XMLCDECL: - * - * Macro which declares the calling convention for exported functions that - * use '...'. - */ -#define XMLCDECL + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS \ + _Pragma("diag_default 1215") -#endif /* platform switch */ +#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) + + #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800) + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"") + #else + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + #endif + #define XML_POP_WARNINGS \ + _Pragma("GCC diagnostic pop") + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + + #define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push)) + #define XML_POP_WARNINGS __pragma(warning(pop)) + +#else + + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS + +#endif /* - * XMLPUBFUN: - * - * Macro which declares an exportable function + * Accessors for globals */ -#define XMLPUBFUN XMLPUBLIC -/** - * XMLPUBVAR: - * - * Macro which declares an exportable variable +#define XML_NO_ATTR + +#ifdef LIBXML_THREAD_ENABLED + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBFUN type *__vtklibxml2_##name(void); + #define XML_GLOBAL_MACRO(name) (*__vtklibxml2_##name()) +#else + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBVAR type vtklibxml2_##name; +#endif + +/* + * Originally declared in xmlversion.h which is generated */ -#define XMLPUBVAR XMLPUBLIC extern -/* Compatibility */ -#if !defined(LIBXML_DLL_IMPORT) -#define LIBXML_DLL_IMPORT XMLPUBVAR +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void xmlCheckVersion(int version); + +#ifdef __cplusplus +} #endif #endif /* __XML_EXPORTS_H__ */ diff --git a/include/libxml/xmlmemory.h b/include/libxml/xmlmemory.h index ae2a4275a3b..0743bf08173 100644 --- a/include/libxml/xmlmemory.h +++ b/include/libxml/xmlmemory.h @@ -15,32 +15,6 @@ #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 @@ -54,7 +28,7 @@ extern "C" { * * Signature for a free() implementation. */ -typedef void (XMLCALL *xmlFreeFunc)(void *mem); +typedef void (*xmlFreeFunc)(void *mem); /** * xmlMallocFunc: * @size: the size requested in bytes @@ -63,7 +37,7 @@ typedef void (XMLCALL *xmlFreeFunc)(void *mem); * * 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); +typedef void *(LIBXML_ATTR_ALLOC_SIZE(1) *xmlMallocFunc)(size_t size); /** * xmlReallocFunc: @@ -74,7 +48,7 @@ typedef void *(LIBXML_ATTR_ALLOC_SIZE(1) XMLCALL *xmlMallocFunc)(size_t size); * * Returns a pointer to the newly reallocated block or NULL in case of error. */ -typedef void *(XMLCALL *xmlReallocFunc)(void *mem, size_t size); +typedef void *(*xmlReallocFunc)(void *mem, size_t size); /** * xmlStrdupFunc: @@ -84,39 +58,80 @@ typedef void *(XMLCALL *xmlReallocFunc)(void *mem, size_t size); * * Returns the copy of the string or NULL in case of error. */ -typedef char *(XMLCALL *xmlStrdupFunc)(const char *str); +typedef char *(*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; - */ + * 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 + */ +/** DOC_DISABLE */ +#ifdef LIBXML_THREAD_ALLOC_ENABLED + #define XML_GLOBALS_ALLOC \ + XML_OP(xmlMalloc, xmlMallocFunc, XML_NO_ATTR) \ + XML_OP(xmlMallocAtomic, xmlMallocFunc, XML_NO_ATTR) \ + XML_OP(xmlRealloc, xmlReallocFunc, XML_NO_ATTR) \ + XML_OP(xmlFree, xmlFreeFunc, XML_NO_ATTR) \ + XML_OP(xmlMemStrdup, xmlStrdupFunc, XML_NO_ATTR) + #define XML_OP XML_DECLARE_GLOBAL + XML_GLOBALS_ALLOC + #undef XML_OP + #if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlMalloc XML_GLOBAL_MACRO(xmlMalloc) + #define xmlMallocAtomic XML_GLOBAL_MACRO(xmlMallocAtomic) + #define xmlRealloc XML_GLOBAL_MACRO(xmlRealloc) + #define xmlFree XML_GLOBAL_MACRO(xmlFree) + #define xmlMemStrdup XML_GLOBAL_MACRO(xmlMemStrdup) + #else + #define xmlMalloc vtklibxml2_xmlMalloc + #define xmlMallocAtomic vtklibxml2_xmlMallocAtomic + #define xmlRealloc vtklibxml2_xmlRealloc + #define xmlFree vtklibxml2_xmlFree + #define xmlMemStrdup vtklibxml2_xmlMemStrdup + #endif +#else + #define XML_GLOBALS_ALLOC + + #define xmlMalloc vtklibxml2_xmlMalloc + #define xmlMallocAtomic vtklibxml2_xmlMallocAtomic + #define xmlRealloc vtklibxml2_xmlRealloc + #define xmlFree vtklibxml2_xmlFree + #define xmlMemStrdup vtklibxml2_xmlMemStrdup + +/** DOC_ENABLE */ + XMLPUBVAR xmlMallocFunc xmlMalloc; + XMLPUBVAR xmlMallocFunc xmlMallocAtomic; + XMLPUBVAR xmlReallocFunc xmlRealloc; + XMLPUBVAR xmlFreeFunc xmlFree; + XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif /* * 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 +XMLPUBFUN int xmlMemSetup (xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlMemGet (xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGcMemSetup (xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGcMemGet (xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, xmlMallocFunc *mallocAtomicFunc, @@ -127,100 +142,60 @@ XMLPUBFUN int XMLCALL * Initialization of the memory layer. */ XML_DEPRECATED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlInitMemory (void); /* * Cleanup of the memory layer. */ XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlCleanupMemory (void); /* * These are specific to the XML debug memory wrapper. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN size_t + xmlMemSize (void *ptr); +XMLPUBFUN int xmlMemUsed (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlMemBlocks (void); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlMemDisplay (FILE *fp); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlMemDisplayLast(FILE *fp, long nbBytes); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlMemShow (FILE *fp, int nr); -XMLPUBFUN void XMLCALL +XML_DEPRECATED +XMLPUBFUN void xmlMemoryDump (void); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlMemMalloc (size_t size) LIBXML_ATTR_ALLOC_SIZE(1); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlMemRealloc (void *ptr,size_t size); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlMemFree (void *ptr); -XMLPUBFUN char * XMLCALL +XMLPUBFUN char * xmlMemoryStrdup (const char *str); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlMallocLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlReallocLoc (void *ptr, size_t size, const char *file, int line); -XMLPUBFUN void * XMLCALL +XML_DEPRECATED +XMLPUBFUN void * xmlMallocAtomicLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); -XMLPUBFUN char * XMLCALL +XML_DEPRECATED +XMLPUBFUN char * 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/include/libxml/xmlmodule.h b/include/libxml/xmlmodule.h index 9667820070a..279986c1a9f 100644 --- a/include/libxml/xmlmodule.h +++ b/include/libxml/xmlmodule.h @@ -37,16 +37,16 @@ typedef enum { XML_MODULE_LOCAL= 2 /* local binding */ } xmlModuleOption; -XMLPUBFUN xmlModulePtr XMLCALL xmlModuleOpen (const char *filename, +XMLPUBFUN xmlModulePtr xmlModuleOpen (const char *filename, int options); -XMLPUBFUN int XMLCALL xmlModuleSymbol (xmlModulePtr module, +XMLPUBFUN int xmlModuleSymbol (xmlModulePtr module, const char* name, void **result); -XMLPUBFUN int XMLCALL xmlModuleClose (xmlModulePtr module); +XMLPUBFUN int xmlModuleClose (xmlModulePtr module); -XMLPUBFUN int XMLCALL xmlModuleFree (xmlModulePtr module); +XMLPUBFUN int xmlModuleFree (xmlModulePtr module); #ifdef __cplusplus } diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h index e8a8bcc9aab..5d4fc5d5a17 100644 --- a/include/libxml/xmlreader.h +++ b/include/libxml/xmlreader.h @@ -12,11 +12,14 @@ #include #include +#include #include #ifdef LIBXML_SCHEMAS_ENABLED #include #include #endif +/* for compatibility */ +#include #ifdef __cplusplus extern "C" { @@ -108,239 +111,244 @@ typedef xmlTextReader *xmlTextReaderPtr; /* * Constructors & Destructor */ -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlNewTextReader (xmlParserInputBufferPtr input, const char *URI); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlNewTextReaderFilename(const char *URI); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlFreeTextReader (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderSetup(xmlTextReaderPtr reader, xmlParserInputBufferPtr input, const char *URL, const char *encoding, int options); +XMLPUBFUN void + xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, + unsigned maxAmpl); +XMLPUBFUN const xmlError * + xmlTextReaderGetLastError(xmlTextReaderPtr reader); /* * Iterators */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderRead (xmlTextReaderPtr reader); #ifdef LIBXML_WRITER_ENABLED -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderReadInnerXml(xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderReadOuterXml(xmlTextReaderPtr reader); #endif -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderReadString (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader); /* * Attributes of the node */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderAttributeCount(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderDepth (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderHasAttributes(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderHasValue(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderIsDefault (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderNodeType (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderQuoteChar (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderReadState (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstBaseUri (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstLocalName (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstName (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstPrefix (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstXmlLang (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstString (xmlTextReaderPtr reader, const xmlChar *str); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstValue (xmlTextReaderPtr reader); /* * use the Const version of the routine for * better performance and simpler code */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderBaseUri (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderLocalName (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderName (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderNamespaceUri(xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderPrefix (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderXmlLang (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderValue (xmlTextReaderPtr reader); /* * Methods of the XmlTextReader */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderClose (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderGetAttributeNo (xmlTextReaderPtr reader, int no); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderGetAttribute (xmlTextReaderPtr reader, const xmlChar *name); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderGetAttributeNs (xmlTextReaderPtr reader, const xmlChar *localName, const xmlChar *namespaceURI); -XMLPUBFUN xmlParserInputBufferPtr XMLCALL +XMLPUBFUN xmlParserInputBufferPtr xmlTextReaderGetRemainder (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, const xmlChar *namespaceURI); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderMoveToElement (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderNormalization (xmlTextReaderPtr reader); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstEncoding (xmlTextReaderPtr reader); /* * Extensions */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderSetParserProp (xmlTextReaderPtr reader, int prop, int value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderGetParserProp (xmlTextReaderPtr reader, int prop); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlTextReaderCurrentNode (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlTextReaderPreserve (xmlTextReaderPtr reader); #ifdef LIBXML_PATTERN_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, const xmlChar **namespaces); #endif /* LIBXML_PATTERN_ENABLED */ -XMLPUBFUN xmlDocPtr XMLCALL +XMLPUBFUN xmlDocPtr xmlTextReaderCurrentDoc (xmlTextReaderPtr reader); -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlTextReaderExpand (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderNext (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderNextSibling (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderIsValid (xmlTextReaderPtr reader); #ifdef LIBXML_SCHEMAS_ENABLED -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader, xmlRelaxNGValidCtxtPtr ctxt, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderSchemaValidate (xmlTextReaderPtr reader, const char *xsd); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader, xmlSchemaValidCtxtPtr ctxt, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderSetSchema (xmlTextReaderPtr reader, xmlSchemaPtr schema); #endif -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderStandalone (xmlTextReaderPtr reader); /* * Index lookup */ -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlTextReaderByteConsumed (xmlTextReaderPtr reader); /* * New more complete APIs for simpler creation and reuse of readers */ -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderWalker (xmlDocPtr doc); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderForDoc (const xmlChar * cur, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderForFile (const char *filename, const char *encoding, int options); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderForMemory (const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderForFd (int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN xmlTextReaderPtr XMLCALL +XMLPUBFUN xmlTextReaderPtr xmlReaderForIO (xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, @@ -348,34 +356,34 @@ XMLPUBFUN xmlTextReaderPtr XMLCALL const char *encoding, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewWalker (xmlTextReaderPtr reader, xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewDoc (xmlTextReaderPtr reader, const xmlChar * cur, const char *URL, const char *encoding, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewFile (xmlTextReaderPtr reader, const char *filename, const char *encoding, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewMemory (xmlTextReaderPtr reader, const char *buffer, int size, const char *URL, const char *encoding, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewFd (xmlTextReaderPtr reader, int fd, const char *URL, const char *encoding, int options); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlReaderNewIO (xmlTextReaderPtr reader, xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, @@ -397,23 +405,23 @@ typedef void * xmlTextReaderLocatorPtr; * * Signature of an error callback from a reader parser */ -typedef void (XMLCALL *xmlTextReaderErrorFunc)(void *arg, +typedef void (*xmlTextReaderErrorFunc)(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlTextReaderLocatorBaseURI (xmlTextReaderLocatorPtr locator); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, xmlTextReaderErrorFunc f, void *arg); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, xmlStructuredErrorFunc f, void *arg); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, xmlTextReaderErrorFunc *f, void **arg); diff --git a/include/libxml/xmlregexp.h b/include/libxml/xmlregexp.h index 7009645a925..2d66437a55b 100644 --- a/include/libxml/xmlregexp.h +++ b/include/libxml/xmlregexp.h @@ -11,7 +11,9 @@ #ifndef __XML_REGEXP_H__ #define __XML_REGEXP_H__ +#include #include +#include #ifdef LIBXML_REGEXP_ENABLED @@ -36,28 +38,19 @@ typedef xmlRegexp *xmlRegexpPtr; typedef struct _xmlRegExecCtxt xmlRegExecCtxt; typedef xmlRegExecCtxt *xmlRegExecCtxtPtr; -#ifdef __cplusplus -} -#endif -#include -#include -#ifdef __cplusplus -extern "C" { -#endif - /* * The POSIX like API */ -XMLPUBFUN xmlRegexpPtr XMLCALL +XMLPUBFUN xmlRegexpPtr xmlRegexpCompile (const xmlChar *regexp); -XMLPUBFUN void XMLCALL xmlRegFreeRegexp(xmlRegexpPtr regexp); -XMLPUBFUN int XMLCALL +XMLPUBFUN void xmlRegFreeRegexp(xmlRegexpPtr regexp); +XMLPUBFUN int xmlRegexpExec (xmlRegexpPtr comp, const xmlChar *value); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRegexpPrint (FILE *output, xmlRegexpPtr regexp); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegexpIsDeterminist(xmlRegexpPtr comp); /** @@ -77,29 +70,29 @@ typedef void (*xmlRegExecCallbacks) (xmlRegExecCtxtPtr exec, /* * The progressive API */ -XMLPUBFUN xmlRegExecCtxtPtr XMLCALL +XMLPUBFUN xmlRegExecCtxtPtr xmlRegNewExecCtxt (xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlRegFreeExecCtxt (xmlRegExecCtxtPtr exec); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value, const xmlChar *value2, void *data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegExecNextValues(xmlRegExecCtxtPtr exec, int *nbval, int *nbneg, xmlChar **values, int *terminal); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlRegExecErrInfo (xmlRegExecCtxtPtr exec, const xmlChar **string, int *nbval, @@ -116,15 +109,15 @@ XMLPUBFUN int XMLCALL typedef struct _xmlExpCtxt xmlExpCtxt; typedef xmlExpCtxt *xmlExpCtxtPtr; -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlExpFreeCtxt (xmlExpCtxtPtr ctxt); -XMLPUBFUN xmlExpCtxtPtr XMLCALL +XMLPUBFUN xmlExpCtxtPtr xmlExpNewCtxt (int maxNodes, xmlDictPtr dict); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt); /* Expressions are trees but the tree is opaque */ @@ -150,31 +143,31 @@ XMLPUBVAR xmlExpNodePtr emptyExp; /* * Expressions are reference counted internally */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlExpFree (xmlExpCtxtPtr ctxt, xmlExpNodePtr expr); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlExpRef (xmlExpNodePtr expr); /* * constructors can be either manual or from a string */ -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpParse (xmlExpCtxtPtr ctxt, const char *expr); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpNewAtom (xmlExpCtxtPtr ctxt, const xmlChar *name, int len); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpNewOr (xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpNewSeq (xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpNewRange (xmlExpCtxtPtr ctxt, xmlExpNodePtr subset, int min, @@ -182,34 +175,34 @@ XMLPUBFUN xmlExpNodePtr XMLCALL /* * The really interesting APIs */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpIsNillable(xmlExpNodePtr expr); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpMaxToken (xmlExpNodePtr expr); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpGetLanguage(xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, const xmlChar**langList, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpGetStart (xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, const xmlChar**tokList, int len); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpStringDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, const xmlChar *str, int len); -XMLPUBFUN xmlExpNodePtr XMLCALL +XMLPUBFUN xmlExpNodePtr xmlExpExpDerive (xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, xmlExpNodePtr sub); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlExpSubsume (xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, xmlExpNodePtr sub); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlExpDump (xmlBufferPtr buf, xmlExpNodePtr expr); #endif /* LIBXML_EXPR_ENABLED */ diff --git a/include/libxml/xmlsave.h b/include/libxml/xmlsave.h index fb329b22dbc..e266e467c24 100644 --- a/include/libxml/xmlsave.h +++ b/include/libxml/xmlsave.h @@ -41,47 +41,61 @@ typedef enum { typedef struct _xmlSaveCtxt xmlSaveCtxt; typedef xmlSaveCtxt *xmlSaveCtxtPtr; -XMLPUBFUN xmlSaveCtxtPtr XMLCALL +XMLPUBFUN xmlSaveCtxtPtr xmlSaveToFd (int fd, const char *encoding, int options); -XMLPUBFUN xmlSaveCtxtPtr XMLCALL +XMLPUBFUN xmlSaveCtxtPtr xmlSaveToFilename (const char *filename, const char *encoding, int options); -XMLPUBFUN xmlSaveCtxtPtr XMLCALL +XMLPUBFUN xmlSaveCtxtPtr xmlSaveToBuffer (xmlBufferPtr buffer, const char *encoding, int options); -XMLPUBFUN xmlSaveCtxtPtr XMLCALL +XMLPUBFUN xmlSaveCtxtPtr xmlSaveToIO (xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose, void *ioctx, const char *encoding, int options); -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlSaveDoc (xmlSaveCtxtPtr ctxt, xmlDocPtr doc); -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlSaveTree (xmlSaveCtxtPtr ctxt, xmlNodePtr node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveFlush (xmlSaveCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveClose (xmlSaveCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int + xmlSaveFinish (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int xmlSaveSetEscape (xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSaveSetAttrEscape (xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape); + +XML_DEPRECATED +XMLPUBFUN int + xmlThrDefIndentTreeOutput(int v); +XML_DEPRECATED +XMLPUBFUN const char * + xmlThrDefTreeIndentString(const char * v); +XML_DEPRECATED +XMLPUBFUN int + xmlThrDefSaveNoEmptyTags(int v); + #ifdef __cplusplus } #endif + #endif /* LIBXML_OUTPUT_ENABLED */ #endif /* __XML_XMLSAVE_H__ */ diff --git a/include/libxml/xmlschemas.h b/include/libxml/xmlschemas.h index b90e9d18c6e..c2af3d7098b 100644 --- a/include/libxml/xmlschemas.h +++ b/include/libxml/xmlschemas.h @@ -16,7 +16,10 @@ #ifdef LIBXML_SCHEMAS_ENABLED +#include +#include #include +#include #ifdef __cplusplus extern "C" { @@ -92,7 +95,7 @@ typedef xmlSchema *xmlSchemaPtr; * * Signature of an error callback from an XSD validation */ -typedef void (XMLCDECL *xmlSchemaValidityErrorFunc) +typedef void (*xmlSchemaValidityErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** @@ -103,7 +106,7 @@ typedef void (XMLCDECL *xmlSchemaValidityErrorFunc) * * Signature of a warning callback from an XSD validation */ -typedef void (XMLCDECL *xmlSchemaValidityWarningFunc) +typedef void (*xmlSchemaValidityWarningFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); /** @@ -128,95 +131,95 @@ typedef xmlSchemaValidCtxt *xmlSchemaValidCtxtPtr; * Returns: 0 in case of success and -1 in case of error */ -typedef int (XMLCDECL *xmlSchemaValidityLocatorFunc) (void *ctx, +typedef int (*xmlSchemaValidityLocatorFunc) (void *ctx, const char **file, unsigned long *line); /* * Interfaces for parsing. */ -XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchemaParserCtxtPtr xmlSchemaNewParserCtxt (const char *URL); -XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchemaParserCtxtPtr xmlSchemaNewMemParserCtxt (const char *buffer, int size); -XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL +XMLPUBFUN xmlSchemaParserCtxtPtr xmlSchemaNewDocParserCtxt (xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaFreeParserCtxt (xmlSchemaParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaSetParserErrors (xmlSchemaParserCtxtPtr ctxt, xmlSchemaValidityErrorFunc err, xmlSchemaValidityWarningFunc warn, void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt, xmlStructuredErrorFunc serror, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt, xmlSchemaValidityErrorFunc * err, xmlSchemaValidityWarningFunc * warn, void **ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaIsValid (xmlSchemaValidCtxtPtr ctxt); -XMLPUBFUN xmlSchemaPtr XMLCALL +XMLPUBFUN xmlSchemaPtr xmlSchemaParse (xmlSchemaParserCtxtPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaFree (xmlSchemaPtr schema); #ifdef LIBXML_OUTPUT_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaDump (FILE *output, xmlSchemaPtr schema); #endif /* LIBXML_OUTPUT_ENABLED */ /* * Interfaces for validating */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaSetValidErrors (xmlSchemaValidCtxtPtr ctxt, xmlSchemaValidityErrorFunc err, xmlSchemaValidityWarningFunc warn, void *ctx); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt, xmlStructuredErrorFunc serror, void *ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaGetValidErrors (xmlSchemaValidCtxtPtr ctxt, xmlSchemaValidityErrorFunc *err, xmlSchemaValidityWarningFunc *warn, void **ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaSetValidOptions (xmlSchemaValidCtxtPtr ctxt, int options); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt, const char *filename); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt); -XMLPUBFUN xmlSchemaValidCtxtPtr XMLCALL +XMLPUBFUN xmlSchemaValidCtxtPtr xmlSchemaNewValidCtxt (xmlSchemaPtr schema); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaFreeValidCtxt (xmlSchemaValidCtxtPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateDoc (xmlSchemaValidCtxtPtr ctxt, xmlDocPtr instance); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateOneElement (xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateStream (xmlSchemaValidCtxtPtr ctxt, xmlParserInputBufferPtr input, xmlCharEncoding enc, xmlSAXHandlerPtr sax, void *user_data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateFile (xmlSchemaValidCtxtPtr ctxt, const char * filename, int options); -XMLPUBFUN xmlParserCtxtPtr XMLCALL +XMLPUBFUN xmlParserCtxtPtr xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt); /* @@ -225,15 +228,15 @@ XMLPUBFUN xmlParserCtxtPtr XMLCALL typedef struct _xmlSchemaSAXPlug xmlSchemaSAXPlugStruct; typedef xmlSchemaSAXPlugStruct *xmlSchemaSAXPlugPtr; -XMLPUBFUN xmlSchemaSAXPlugPtr XMLCALL +XMLPUBFUN xmlSchemaSAXPlugPtr xmlSchemaSAXPlug (xmlSchemaValidCtxtPtr ctxt, xmlSAXHandlerPtr *sax, void **user_data); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaSAXUnplug (xmlSchemaSAXPlugPtr plug); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaValidateSetLocator (xmlSchemaValidCtxtPtr vctxt, xmlSchemaValidityLocatorFunc f, void *ctxt); diff --git a/include/libxml/xmlschemastypes.h b/include/libxml/xmlschemastypes.h index 5d588f92ea3..e2cde35707c 100644 --- a/include/libxml/xmlschemastypes.h +++ b/include/libxml/xmlschemastypes.h @@ -30,118 +30,118 @@ typedef enum { XML_SCHEMA_WHITESPACE_COLLAPSE = 3 } xmlSchemaWhitespaceValueType; -XMLPUBFUN void XMLCALL +XMLPUBFUN int xmlSchemaInitTypes (void); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaCleanupTypes (void); -XMLPUBFUN xmlSchemaTypePtr XMLCALL +XMLPUBFUN xmlSchemaTypePtr xmlSchemaGetPredefinedType (const xmlChar *name, const xmlChar *ns); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidatePredefinedType (xmlSchemaTypePtr type, const xmlChar *value, xmlSchemaValPtr *val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValPredefTypeNode (xmlSchemaTypePtr type, const xmlChar *value, xmlSchemaValPtr *val, xmlNodePtr node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateFacet (xmlSchemaTypePtr base, xmlSchemaFacetPtr facet, const xmlChar *value, xmlSchemaValPtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateFacetWhtsp (xmlSchemaFacetPtr facet, xmlSchemaWhitespaceValueType fws, xmlSchemaValType valType, const xmlChar *value, xmlSchemaValPtr val, xmlSchemaWhitespaceValueType ws); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaFreeValue (xmlSchemaValPtr val); -XMLPUBFUN xmlSchemaFacetPtr XMLCALL +XMLPUBFUN xmlSchemaFacetPtr xmlSchemaNewFacet (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaCheckFacet (xmlSchemaFacetPtr facet, xmlSchemaTypePtr typeDecl, xmlSchemaParserCtxtPtr ctxt, const xmlChar *name); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlSchemaFreeFacet (xmlSchemaFacetPtr facet); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaCompareValues (xmlSchemaValPtr x, xmlSchemaValPtr y); -XMLPUBFUN xmlSchemaTypePtr XMLCALL +XMLPUBFUN xmlSchemaTypePtr xmlSchemaGetBuiltInListSimpleTypeItemType (xmlSchemaTypePtr type); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateListSimpleTypeFacet (xmlSchemaFacetPtr facet, const xmlChar *value, unsigned long actualLen, unsigned long *expectedLen); -XMLPUBFUN xmlSchemaTypePtr XMLCALL +XMLPUBFUN xmlSchemaTypePtr xmlSchemaGetBuiltInType (xmlSchemaValType type); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaIsBuiltInTypeFacet (xmlSchemaTypePtr type, int facetType); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlSchemaCollapseString (const xmlChar *value); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlSchemaWhiteSpaceReplace (const xmlChar *value); -XMLPUBFUN unsigned long XMLCALL +XMLPUBFUN unsigned long xmlSchemaGetFacetValueAsULong (xmlSchemaFacetPtr facet); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateLengthFacet (xmlSchemaTypePtr type, xmlSchemaFacetPtr facet, const xmlChar *value, xmlSchemaValPtr val, unsigned long *length); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, xmlSchemaValType valType, const xmlChar *value, xmlSchemaValPtr val, unsigned long *length, xmlSchemaWhitespaceValueType ws); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value, xmlSchemaValPtr *val, xmlNodePtr node); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaGetCanonValue (xmlSchemaValPtr val, const xmlChar **retValue); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaGetCanonValueWhtsp (xmlSchemaValPtr val, const xmlChar **retValue, xmlSchemaWhitespaceValueType ws); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValueAppend (xmlSchemaValPtr prev, xmlSchemaValPtr cur); -XMLPUBFUN xmlSchemaValPtr XMLCALL +XMLPUBFUN xmlSchemaValPtr xmlSchemaValueGetNext (xmlSchemaValPtr cur); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlSchemaValueGetAsString (xmlSchemaValPtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaValueGetAsBoolean (xmlSchemaValPtr val); -XMLPUBFUN xmlSchemaValPtr XMLCALL +XMLPUBFUN xmlSchemaValPtr xmlSchemaNewStringValue (xmlSchemaValType type, const xmlChar *value); -XMLPUBFUN xmlSchemaValPtr XMLCALL +XMLPUBFUN xmlSchemaValPtr xmlSchemaNewNOTATIONValue (const xmlChar *name, const xmlChar *ns); -XMLPUBFUN xmlSchemaValPtr XMLCALL +XMLPUBFUN xmlSchemaValPtr xmlSchemaNewQNameValue (const xmlChar *namespaceName, const xmlChar *localName); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlSchemaCompareValuesWhtsp (xmlSchemaValPtr x, xmlSchemaWhitespaceValueType xws, xmlSchemaValPtr y, xmlSchemaWhitespaceValueType yws); -XMLPUBFUN xmlSchemaValPtr XMLCALL +XMLPUBFUN xmlSchemaValPtr xmlSchemaCopyValue (xmlSchemaValPtr val); -XMLPUBFUN xmlSchemaValType XMLCALL +XMLPUBFUN xmlSchemaValType xmlSchemaGetValType (xmlSchemaValPtr val); #ifdef __cplusplus diff --git a/include/libxml/xmlstring.h b/include/libxml/xmlstring.h index 2d0b2d1668e..db11a0b0e50 100644 --- a/include/libxml/xmlstring.h +++ b/include/libxml/xmlstring.h @@ -37,100 +37,100 @@ typedef unsigned char xmlChar; /* * xmlChar handling */ -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrdup (const xmlChar *cur); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrndup (const xmlChar *cur, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCharStrndup (const char *cur, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlCharStrdup (const char *cur); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrsub (const xmlChar *str, int start, int len); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlStrchr (const xmlChar *str, xmlChar val); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlStrstr (const xmlChar *str, const xmlChar *val); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlStrcasestr (const xmlChar *str, const xmlChar *val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrcmp (const xmlChar *str1, const xmlChar *str2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrncmp (const xmlChar *str1, const xmlChar *str2, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrcasecmp (const xmlChar *str1, const xmlChar *str2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrncasecmp (const xmlChar *str1, const xmlChar *str2, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrEqual (const xmlChar *str1, const xmlChar *str2); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrQEqual (const xmlChar *pref, const xmlChar *name, const xmlChar *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrlen (const xmlChar *str); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrcat (xmlChar *cur, const xmlChar *add); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrncat (xmlChar *cur, const xmlChar *add, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlStrncatNew (const xmlChar *str1, const xmlChar *str2, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrPrintf (xmlChar *buf, int len, const char *msg, ...) LIBXML_ATTR_FORMAT(3,4); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlStrVPrintf (xmlChar *buf, int len, const char *msg, va_list ap) LIBXML_ATTR_FORMAT(3,0); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlGetUTF8Char (const unsigned char *utf, int *len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlCheckUTF8 (const unsigned char *utf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUTF8Strsize (const xmlChar *utf, int len); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlUTF8Strndup (const xmlChar *utf, int len); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlUTF8Strpos (const xmlChar *utf, int pos); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUTF8Strloc (const xmlChar *utf, const xmlChar *utfchar); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlUTF8Strsub (const xmlChar *utf, int start, int len); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUTF8Strlen (const xmlChar *utf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUTF8Size (const xmlChar *utf); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlUTF8Charcmp (const xmlChar *utf1, const xmlChar *utf2); diff --git a/include/libxml/xmlunicode.h b/include/libxml/xmlunicode.h index 01ac8b61f56..b6d795b267d 100644 --- a/include/libxml/xmlunicode.h +++ b/include/libxml/xmlunicode.h @@ -7,7 +7,7 @@ * http://www.unicode.org/Public/4.0-Update1/UCD-4.0.1.html * using the genUnicode.py Python script. * - * Generation date: Mon Mar 27 11:09:52 2006 + * Generation date: Tue Apr 30 17:30:38 2024 * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt * Author: Daniel Veillard */ @@ -23,175 +23,339 @@ 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); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsAegeanNumbers (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsAlphabeticPresentationForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabicPresentationFormsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabicPresentationFormsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArmenian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArrows (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBasicLatin (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBengali (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBlockElements (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBopomofo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBopomofoExtended (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBoxDrawing (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBraillePatterns (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBuhid (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsByzantineMusicalSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibility (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKRadicalsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKSymbolsandPunctuation (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCherokee (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarks (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarksforSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningHalfMarks (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningMarksforSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsControlPictures (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCurrencySymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCypriotSyllabary (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCyrillic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCyrillicSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDeseret (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDevanagari (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDingbats (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEnclosedAlphanumerics (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEnclosedCJKLettersandMonths (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEthiopic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeneralPunctuation (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeometricShapes (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeorgian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGothic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreek (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreekExtended (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreekandCoptic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGujarati (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGurmukhi (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHalfwidthandFullwidthForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulCompatibilityJamo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulJamo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulSyllables (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHanunoo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHebrew (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHighPrivateUseSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHighSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHiragana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsIPAExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsIdeographicDescriptionCharacters (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKanbun (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKangxiRadicals (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKannada (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKatakana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKatakanaPhoneticExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKhmer (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKhmerSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLao (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatin1Supplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedAdditional (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLetterlikeSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLimbu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLinearBIdeograms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLinearBSyllabary (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLowSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMalayalam (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMathematicalAlphanumericSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMathematicalOperators (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousSymbolsandArrows (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousTechnical (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMongolian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMusicalSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMyanmar (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsNumberForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOgham (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOldItalic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOpticalCharacterRecognition (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOriya (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOsmanya (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPhoneticExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPrivateUse (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPrivateUseArea (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsRunic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsShavian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSinhala (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSmallFormVariants (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSpacingModifierLetters (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSpecials (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSuperscriptsandSubscripts (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalArrowsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalArrowsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalMathematicalOperators (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSyriac (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTagalog (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTagbanwa (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTags (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTaiLe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTaiXuanJingSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTamil (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTelugu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsThaana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsThai (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTibetan (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsUgaritic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsUnifiedCanadianAboriginalSyllabics (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsVariationSelectors (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsVariationSelectorsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYiRadicals (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYiSyllables (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYijingHexagramSymbols (int code); -XMLPUBFUN int XMLCALL xmlUCSIsBlock (int code, const char *block); +XMLPUBFUN int 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); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatC (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCf (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatL (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLm (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLt (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatM (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMn (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatN (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNd (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatP (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPd (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPf (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPi (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatS (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSk (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSm (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZ (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZp (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZs (int code); -XMLPUBFUN int XMLCALL xmlUCSIsCat (int code, const char *cat); +XMLPUBFUN int xmlUCSIsCat (int code, const char *cat); #ifdef __cplusplus } diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in index bdebfe3b0c9..f153a942f26 100644 --- a/include/libxml/xmlversion.h.in +++ b/include/libxml/xmlversion.h.in @@ -10,20 +10,6 @@ #ifndef __XML_VERSION_H__ #define __XML_VERSION_H__ -#include - -#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: * @@ -60,31 +46,6 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(int version); */ #define LIBXML_TEST_VERSION xmlCheckVersion(@LIBXML_VERSION_NUMBER@); -#ifndef VMS -#if @WITH_TRIO@ -/** - * 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: * @@ -301,24 +262,6 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(int version); #define LIBXML_DEBUG_ENABLED #endif -/** - * DEBUG_MEMORY_LOCATION: - * - * Whether the memory debugging is configured in - */ -#if @WITH_MEM_DEBUG@ -#define DEBUG_MEMORY_LOCATION -#endif - -/** - * LIBXML_DEBUG_RUNTIME: - * - * Whether the runtime debugging is configured in - */ -#if @WITH_RUN_DEBUG@ -#define LIBXML_DEBUG_RUNTIME -#endif - /** * LIBXML_UNICODE_ENABLED: * @@ -346,17 +289,6 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(int version); #define LIBXML_AUTOMATA_ENABLED #endif -/** - * LIBXML_EXPR_ENABLED: - * - * Whether the formal expressions interfaces are compiled in - * - * This code is unused and disabled unconditionally for now. - */ -#if 0 -#define LIBXML_EXPR_ENABLED -#endif - /** * LIBXML_SCHEMAS_ENABLED: * @@ -408,96 +340,8 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(int version); #define LIBXML_LZMA_ENABLED #endif -#ifdef __GNUC__ - -/** - * ATTRIBUTE_UNUSED: - * - * Macro used to signal to GCC unused function parameters - */ - -#ifndef ATTRIBUTE_UNUSED -# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) -# define ATTRIBUTE_UNUSED __attribute__((unused)) -# else -# define ATTRIBUTE_UNUSED -# endif -#endif - -/** - * LIBXML_ATTR_ALLOC_SIZE: - * - * Macro used to indicate to GCC this is an allocator function - */ - -#ifndef LIBXML_ATTR_ALLOC_SIZE -# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))) -# define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) -# else -# define LIBXML_ATTR_ALLOC_SIZE(x) -# endif -#else -# define LIBXML_ATTR_ALLOC_SIZE(x) -#endif - -/** - * 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 - -#ifndef XML_DEPRECATED -# ifdef IN_LIBXML -# define XML_DEPRECATED -# else -/* Available since at least GCC 3.1 */ -# define XML_DEPRECATED __attribute__((deprecated)) -# endif -#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) -/** - * XML_DEPRECATED: - * - * Macro used to indicate that a function, variable, type or struct member - * is deprecated. - */ -#ifndef XML_DEPRECATED -#define XML_DEPRECATED -#endif -#endif /* __GNUC__ */ +#include -#ifdef __cplusplus -} -#endif /* __cplusplus */ #endif diff --git a/include/libxml/xmlwriter.h b/include/libxml/xmlwriter.h index dd5add34166..55f88bc71f0 100644 --- a/include/libxml/xmlwriter.h +++ b/include/libxml/xmlwriter.h @@ -29,20 +29,20 @@ extern "C" { /* * Constructors & Destructor */ - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriter(xmlOutputBufferPtr out); - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriterFilename(const char *uri, int compression); - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriterMemory(xmlBufferPtr buf, int compression); - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, int compression); - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriterDoc(xmlDocPtr * doc, int compression); - XMLPUBFUN xmlTextWriterPtr XMLCALL + XMLPUBFUN xmlTextWriterPtr xmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, int compression); - XMLPUBFUN void XMLCALL xmlFreeTextWriter(xmlTextWriterPtr writer); + XMLPUBFUN void xmlFreeTextWriter(xmlTextWriterPtr writer); /* * Functions @@ -52,30 +52,30 @@ extern "C" { /* * Document */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version, const char *encoding, const char *standalone); - XMLPUBFUN int XMLCALL xmlTextWriterEndDocument(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndDocument(xmlTextWriterPtr writer); /* * Comments */ - XMLPUBFUN int XMLCALL xmlTextWriterStartComment(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterStartComment(xmlTextWriterPtr writer); - XMLPUBFUN int XMLCALL xmlTextWriterEndComment(xmlTextWriterPtr writer); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterEndComment(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, const char *format, ...) LIBXML_ATTR_FORMAT(2,3); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatComment(xmlTextWriterPtr writer, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(2,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteComment(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteComment(xmlTextWriterPtr writer, const xmlChar * content); @@ -83,47 +83,47 @@ extern "C" { /* * Elements */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartElement(xmlTextWriterPtr writer, const xmlChar * name); - XMLPUBFUN int XMLCALL xmlTextWriterStartElementNS(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterStartElementNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, const xmlChar * namespaceURI); - XMLPUBFUN int XMLCALL xmlTextWriterEndElement(xmlTextWriterPtr writer); - XMLPUBFUN int XMLCALL xmlTextWriterFullEndElement(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndElement(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterFullEndElement(xmlTextWriterPtr writer); /* * Elements conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) LIBXML_ATTR_FORMAT(3,4); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(3,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteElement(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteElement(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * content); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, const xmlChar * namespaceURI, const char *format, ...) LIBXML_ATTR_FORMAT(5,6); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatElementNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, @@ -131,7 +131,7 @@ extern "C" { const char *format, va_list argptr) LIBXML_ATTR_FORMAT(5,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteElementNS(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteElementNS(xmlTextWriterPtr writer, const xmlChar * prefix, @@ -144,48 +144,48 @@ extern "C" { /* * Text */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, const char *format, ...) LIBXML_ATTR_FORMAT(2,3); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatRaw(xmlTextWriterPtr writer, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(2,0); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteRawLen(xmlTextWriterPtr writer, const xmlChar * content, int len); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteRaw(xmlTextWriterPtr writer, const xmlChar * content); - XMLPUBFUN int XMLCALL xmlTextWriterWriteFormatString(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteFormatString(xmlTextWriterPtr writer, const char *format, ...) LIBXML_ATTR_FORMAT(2,3); - XMLPUBFUN int XMLCALL xmlTextWriterWriteVFormatString(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteVFormatString(xmlTextWriterPtr writer, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(2,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteString(xmlTextWriterPtr writer, + XMLPUBFUN int xmlTextWriterWriteString(xmlTextWriterPtr writer, const xmlChar * content); - XMLPUBFUN int XMLCALL xmlTextWriterWriteBase64(xmlTextWriterPtr writer, + XMLPUBFUN int xmlTextWriterWriteBase64(xmlTextWriterPtr writer, const char *data, int start, int len); - XMLPUBFUN int XMLCALL xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, + XMLPUBFUN int xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, const char *data, int start, int len); /* * Attributes */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartAttribute(xmlTextWriterPtr writer, const xmlChar * name); - XMLPUBFUN int XMLCALL xmlTextWriterStartAttributeNS(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterStartAttributeNS(xmlTextWriterPtr writer, const xmlChar * prefix, @@ -193,36 +193,36 @@ extern "C" { name, const xmlChar * namespaceURI); - XMLPUBFUN int XMLCALL xmlTextWriterEndAttribute(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndAttribute(xmlTextWriterPtr writer); /* * Attributes conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) LIBXML_ATTR_FORMAT(3,4); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatAttribute(xmlTextWriterPtr writer, const xmlChar * name, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(3,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteAttribute(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteAttribute(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * content); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, const xmlChar * namespaceURI, const char *format, ...) LIBXML_ATTR_FORMAT(5,6); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatAttributeNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, @@ -230,7 +230,7 @@ extern "C" { const char *format, va_list argptr) LIBXML_ATTR_FORMAT(5,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteAttributeNS(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteAttributeNS(xmlTextWriterPtr writer, const xmlChar * prefix, @@ -244,25 +244,25 @@ extern "C" { /* * PI's */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartPI(xmlTextWriterPtr writer, const xmlChar * target); - XMLPUBFUN int XMLCALL xmlTextWriterEndPI(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterEndPI(xmlTextWriterPtr writer); /* * PI conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, const xmlChar * target, const char *format, ...) LIBXML_ATTR_FORMAT(3,4); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatPI(xmlTextWriterPtr writer, const xmlChar * target, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(3,0); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWritePI(xmlTextWriterPtr writer, const xmlChar * target, const xmlChar * content); @@ -277,52 +277,52 @@ extern "C" { /* * CDATA */ - XMLPUBFUN int XMLCALL xmlTextWriterStartCDATA(xmlTextWriterPtr writer); - XMLPUBFUN int XMLCALL xmlTextWriterEndCDATA(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterStartCDATA(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterEndCDATA(xmlTextWriterPtr writer); /* * CDATA conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, const char *format, ...) LIBXML_ATTR_FORMAT(2,3); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatCDATA(xmlTextWriterPtr writer, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(2,0); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteCDATA(xmlTextWriterPtr writer, const xmlChar * content); /* * DTD */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartDTD(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * pubid, const xmlChar * sysid); - XMLPUBFUN int XMLCALL xmlTextWriterEndDTD(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterEndDTD(xmlTextWriterPtr writer); /* * DTD conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * pubid, const xmlChar * sysid, const char *format, ...) LIBXML_ATTR_FORMAT(5,6); - XMLPUBFUN int XMLCALL + XMLPUBFUN int 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 + XMLPUBFUN int xmlTextWriterWriteDTD(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * pubid, @@ -339,27 +339,27 @@ extern "C" { /* * DTD element definition */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartDTDElement(xmlTextWriterPtr writer, const xmlChar * name); - XMLPUBFUN int XMLCALL xmlTextWriterEndDTDElement(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndDTDElement(xmlTextWriterPtr writer); /* * DTD element definition conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) LIBXML_ATTR_FORMAT(3,4); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatDTDElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(3,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDElement(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteDTDElement(xmlTextWriterPtr writer, const xmlChar * name, @@ -369,27 +369,27 @@ extern "C" { /* * DTD attribute list definition */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name); - XMLPUBFUN int XMLCALL xmlTextWriterEndDTDAttlist(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndDTDAttlist(xmlTextWriterPtr writer); /* * DTD attribute list definition conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) LIBXML_ATTR_FORMAT(3,4); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(3,0); - XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name, @@ -399,48 +399,48 @@ extern "C" { /* * DTD entity definition */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterStartDTDEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name); - XMLPUBFUN int XMLCALL xmlTextWriterEndDTDEntity(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterEndDTDEntity(xmlTextWriterPtr writer); /* * DTD entity definition conveniency functions */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, const char *format, ...) LIBXML_ATTR_FORMAT(4,5); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteVFormatDTDInternalEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, const char *format, va_list argptr) LIBXML_ATTR_FORMAT(4,0); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteDTDInternalEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, const xmlChar * content); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteDTDExternalEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, const xmlChar * pubid, const xmlChar * sysid, const xmlChar * ndataid); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteDTDExternalEntityContents(xmlTextWriterPtr writer, const xmlChar * pubid, const xmlChar * sysid, const xmlChar * ndataid); - XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDEntity(xmlTextWriterPtr + XMLPUBFUN int xmlTextWriterWriteDTDEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, const xmlChar * @@ -455,7 +455,7 @@ extern "C" { /* * DTD notation definition */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterWriteDTDNotation(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * pubid, @@ -464,20 +464,21 @@ extern "C" { /* * Indentation */ - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterSetIndentString(xmlTextWriterPtr writer, const xmlChar * str); - XMLPUBFUN int XMLCALL + XMLPUBFUN int xmlTextWriterSetQuoteChar(xmlTextWriterPtr writer, xmlChar quotechar); /* * misc */ - XMLPUBFUN int XMLCALL xmlTextWriterFlush(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterFlush(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterClose(xmlTextWriterPtr writer); #ifdef __cplusplus } diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h index bfbc5d6d995..b89e105c08f 100644 --- a/include/libxml/xpath.h +++ b/include/libxml/xpath.h @@ -400,7 +400,7 @@ struct _xmlXPathParserContext { int xptr; /* it this an XPointer expression */ xmlNodePtr ancestor; /* used for walking preceding axis */ - int valueFrame; /* used to limit Pop on the stack */ + int valueFrame; /* always zero for compatibility */ }; /************************************************************************ @@ -454,68 +454,72 @@ XMLPUBVAR double xmlXPathNINF; (((ns) == NULL) || ((ns)->nodeNr == 0) || ((ns)->nodeTab == NULL)) -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeObject (xmlXPathObjectPtr obj); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeSetCreate (xmlNodePtr val); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeNodeSet (xmlNodeSetPtr obj); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathObjectCopy (xmlXPathObjectPtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCmpNodes (xmlNodePtr node1, xmlNodePtr node2); /** * Conversion functions to basic types. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCastNumberToBoolean (double val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCastStringToBoolean (const xmlChar * val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCastToBoolean (xmlXPathObjectPtr val); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathCastBooleanToNumber (int val); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathCastStringToNumber (const xmlChar * val); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathCastNodeToNumber (xmlNodePtr node); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathCastToNumber (xmlXPathObjectPtr val); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathCastBooleanToString (int val); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathCastNumberToString (double val); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathCastNodeToString (xmlNodePtr node); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathCastNodeSetToString (xmlNodeSetPtr ns); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathCastToString (xmlXPathObjectPtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathConvertBoolean (xmlXPathObjectPtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathConvertNumber (xmlXPathObjectPtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathConvertString (xmlXPathObjectPtr val); /** * Context handling. */ -XMLPUBFUN xmlXPathContextPtr XMLCALL +XMLPUBFUN xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeContext (xmlXPathContextPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN void + xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt, + xmlStructuredErrorFunc handler, + void *context); +XMLPUBFUN int xmlXPathContextSetCache(xmlXPathContextPtr ctxt, int active, int value, @@ -523,48 +527,48 @@ XMLPUBFUN int XMLCALL /** * Evaluation functions. */ -XMLPUBFUN long XMLCALL +XMLPUBFUN long xmlXPathOrderDocElems (xmlDocPtr doc); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathSetContextNode (xmlNodePtr node, xmlXPathContextPtr ctx); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNodeEval (xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathEval (const xmlChar *str, xmlXPathContextPtr ctx); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathEvalExpression (const xmlChar *str, xmlXPathContextPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathEvalPredicate (xmlXPathContextPtr ctxt, xmlXPathObjectPtr res); /** * Separate compilation/evaluation entry points. */ -XMLPUBFUN xmlXPathCompExprPtr XMLCALL +XMLPUBFUN xmlXPathCompExprPtr xmlXPathCompile (const xmlChar *str); -XMLPUBFUN xmlXPathCompExprPtr XMLCALL +XMLPUBFUN xmlXPathCompExprPtr xmlXPathCtxtCompile (xmlXPathContextPtr ctxt, const xmlChar *str); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathCompiledEval (xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeCompExpr (xmlXPathCompExprPtr comp); #endif /* LIBXML_XPATH_ENABLED */ #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathInit (void); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathIsNaN (double val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathIsInf (double val); #ifdef __cplusplus diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h index 76a6b481572..d1c90dff2aa 100644 --- a/include/libxml/xpathInternals.h +++ b/include/libxml/xpathInternals.h @@ -12,6 +12,7 @@ #ifndef __XML_XPATH_INTERNALS_H__ #define __XML_XPATH_INTERNALS_H__ +#include #include #include @@ -100,15 +101,15 @@ extern "C" { */ #define xmlXPathGetContextNode(ctxt) ((ctxt)->context->node) -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt); -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathPopNumber (xmlXPathParserContextPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathPopString (xmlXPathParserContextPtr ctxt); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt); -XMLPUBFUN void * XMLCALL +XMLPUBFUN void * xmlXPathPopExternal (xmlXPathParserContextPtr ctxt); /** @@ -297,7 +298,7 @@ XMLPUBFUN void * XMLCALL if (ctxt == NULL) return; \ if (nargs != (x)) \ XP_ERROR(XPATH_INVALID_ARITY); \ - if (ctxt->valueNr < ctxt->valueFrame + (x)) \ + if (ctxt->valueNr < (x)) \ XP_ERROR(XPATH_STACK_ERROR); /** @@ -331,7 +332,7 @@ XMLPUBFUN void * XMLCALL * Variable Lookup forwarding. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisterVariableLookup (xmlXPathContextPtr ctxt, xmlXPathVariableLookupFunc f, void *data); @@ -340,7 +341,7 @@ XMLPUBFUN void XMLCALL * Function Lookup forwarding. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, xmlXPathFuncLookupFunc f, void *funcCtxt); @@ -348,22 +349,22 @@ XMLPUBFUN void XMLCALL /* * Error reporting. */ -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPatherror (xmlXPathParserContextPtr ctxt, const char *file, int line, int no); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathErr (xmlXPathParserContextPtr ctxt, int error); #ifdef LIBXML_DEBUG_ENABLED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathDebugDumpObject (FILE *output, xmlXPathObjectPtr cur, int depth); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, int depth); @@ -371,48 +372,48 @@ XMLPUBFUN void XMLCALL /** * NodeSet handling. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathDistinctSorted (xmlNodeSetPtr nodes); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathDistinct (xmlNodeSetPtr nodes); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2); @@ -421,208 +422,208 @@ XMLPUBFUN xmlNodeSetPtr XMLCALL * Extending a context. */ -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathRegisterNs (xmlXPathContextPtr ctxt, const xmlChar *prefix, const xmlChar *ns_uri); -XMLPUBFUN const xmlChar * XMLCALL +XMLPUBFUN const xmlChar * xmlXPathNsLookup (xmlXPathContextPtr ctxt, const xmlChar *prefix); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisteredNsCleanup (xmlXPathContextPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathFunction f); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri, xmlXPathFunction f); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathObjectPtr value); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri, xmlXPathObjectPtr value); -XMLPUBFUN xmlXPathFunction XMLCALL +XMLPUBFUN xmlXPathFunction xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, const xmlChar *name); -XMLPUBFUN xmlXPathFunction XMLCALL +XMLPUBFUN xmlXPathFunction xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisteredFuncsCleanup (xmlXPathContextPtr ctxt); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathVariableLookup (xmlXPathContextPtr ctxt, const xmlChar *name); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); /** * Utilities to extend XPath. */ -XMLPUBFUN xmlXPathParserContextPtr XMLCALL +XMLPUBFUN xmlXPathParserContextPtr xmlXPathNewParserContext (const xmlChar *str, xmlXPathContextPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathFreeParserContext (xmlXPathParserContextPtr ctxt); /* TODO: remap to xmlXPathValuePop and Push. */ -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr valuePop (xmlXPathParserContextPtr ctxt); -XMLPUBFUN int XMLCALL +XMLPUBFUN int valuePush (xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewString (const xmlChar *val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewCString (const char *val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathWrapString (xmlChar *val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathWrapCString (char * val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewFloat (double val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewBoolean (int val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewNodeSet (xmlNodePtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewValueTree (xmlNodePtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathNodeSetAdd (xmlNodeSetPtr cur, xmlNodePtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathNodeSetAddUnique (xmlNodeSetPtr cur, xmlNodePtr val); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathNodeSetAddNs (xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathNodeSetSort (xmlNodeSetPtr set); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRoot (xmlXPathParserContextPtr ctxt); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathParseName (xmlXPathParserContextPtr ctxt); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * xmlXPathParseNCName (xmlXPathParserContextPtr ctxt); /* * Existing functions. */ -XMLPUBFUN double XMLCALL +XMLPUBFUN double xmlXPathStringEvalNumber (const xmlChar *str); -XMLPUBFUN int XMLCALL +XMLPUBFUN int xmlXPathEvaluatePredicateResult (xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr res); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathRegisterAllFunctions (xmlXPathContextPtr ctxt); -XMLPUBFUN xmlNodeSetPtr XMLCALL +XMLPUBFUN xmlNodeSetPtr xmlXPathNodeSetMerge (xmlNodeSetPtr val1, xmlNodeSetPtr val2); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathNodeSetDel (xmlNodeSetPtr cur, xmlNodePtr val); -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPathNodeSetRemove (xmlNodeSetPtr cur, int val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathNewNodeSetList (xmlNodeSetPtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPathWrapNodeSet (xmlNodeSetPtr val); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr 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 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict); +XMLPUBFUN void xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathAddValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathSubValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathMultValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathDivValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathModValues(xmlXPathParserContextPtr ctxt); -XMLPUBFUN int XMLCALL xmlXPathIsNodeType(const xmlChar *name); +XMLPUBFUN int xmlXPathIsNodeType(const xmlChar *name); /* * Some of the axis navigation routines. */ -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextChild(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextParent(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur); -XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, +XMLPUBFUN xmlNodePtr 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); +XMLPUBFUN void xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); /** * Really internal functions */ -XMLPUBFUN void XMLCALL xmlXPathNodeSetFreeNs(xmlNsPtr ns); +XMLPUBFUN void xmlXPathNodeSetFreeNs(xmlNsPtr ns); #ifdef __cplusplus } diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h index ca7bdbe085f..a5260008fc0 100644 --- a/include/libxml/xpointer.h +++ b/include/libxml/xpointer.h @@ -28,7 +28,7 @@ extern "C" { #endif -#ifdef LIBXML_XPTR_LOCS_ENABLED +#if defined(LIBXML_XPTR_LOCS_ENABLED) /* * A Location Set */ @@ -45,90 +45,91 @@ struct _xmlLocationSet { */ XML_DEPRECATED -XMLPUBFUN xmlLocationSetPtr XMLCALL +XMLPUBFUN xmlLocationSetPtr xmlXPtrLocationSetCreate (xmlXPathObjectPtr val); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); XML_DEPRECATED -XMLPUBFUN xmlLocationSetPtr XMLCALL +XMLPUBFUN xmlLocationSetPtr xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, xmlLocationSetPtr val2); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRange (xmlNodePtr start, int startindex, xmlNodePtr end, int endindex); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRangePoints (xmlXPathObjectPtr start, xmlXPathObjectPtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRangeNodePoint (xmlNodePtr start, xmlXPathObjectPtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRangePointNode (xmlXPathObjectPtr start, xmlNodePtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRangeNodes (xmlNodePtr start, xmlNodePtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewLocationSetNodes (xmlNodePtr start, xmlNodePtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewRangeNodeObject (xmlNodePtr start, xmlXPathObjectPtr end); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrNewCollapsedRange (xmlNodePtr start); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrLocationSetAdd (xmlLocationSetPtr cur, xmlXPathObjectPtr val); XML_DEPRECATED -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrWrapLocationSet (xmlLocationSetPtr val); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrLocationSetDel (xmlLocationSetPtr cur, xmlXPathObjectPtr val); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrLocationSetRemove (xmlLocationSetPtr cur, int val); -#endif /* LIBXML_XPTR_LOCS_ENABLED */ +#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) */ /* * Functions. */ -XMLPUBFUN xmlXPathContextPtr XMLCALL +XMLPUBFUN xmlXPathContextPtr xmlXPtrNewContext (xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin); -XMLPUBFUN xmlXPathObjectPtr XMLCALL +XMLPUBFUN xmlXPathObjectPtr xmlXPtrEval (const xmlChar *str, xmlXPathContextPtr ctx); -#ifdef LIBXML_XPTR_LOCS_ENABLED + +#if defined(LIBXML_XPTR_LOCS_ENABLED) XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, int nargs); XML_DEPRECATED -XMLPUBFUN xmlNodePtr XMLCALL +XMLPUBFUN xmlNodePtr xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); XML_DEPRECATED -XMLPUBFUN void XMLCALL +XMLPUBFUN void xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); -#endif /* LIBXML_XPTR_LOCS_ENABLED */ +#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) */ #ifdef __cplusplus } #endif diff --git a/include/private/buf.h b/include/private/buf.h new file mode 100644 index 00000000000..982b9eea00b --- /dev/null +++ b/include/private/buf.h @@ -0,0 +1,61 @@ +#ifndef XML_BUF_H_PRIVATE__ +#define XML_BUF_H_PRIVATE__ + +#include + +XML_HIDDEN xmlBufPtr +xmlBufCreate(void); +XML_HIDDEN xmlBufPtr +xmlBufCreateSize(size_t size); + +XML_HIDDEN int +xmlBufSetAllocationScheme(xmlBufPtr buf, xmlBufferAllocationScheme scheme); +XML_HIDDEN int +xmlBufGetAllocationScheme(xmlBufPtr buf); + +XML_HIDDEN void +xmlBufFree(xmlBufPtr buf); +XML_HIDDEN void +xmlBufEmpty(xmlBufPtr buf); + +/* size_t xmlBufShrink(xmlBufPtr buf, size_t len); */ +XML_HIDDEN int +xmlBufGrow(xmlBufPtr buf, int len); +XML_HIDDEN int +xmlBufResize(xmlBufPtr buf, size_t len); + +XML_HIDDEN int +xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len); +XML_HIDDEN int +xmlBufCat(xmlBufPtr buf, const xmlChar *str); + +XML_HIDDEN size_t +xmlBufAvail(const xmlBufPtr buf); +XML_HIDDEN size_t +xmlBufLength(const xmlBufPtr buf); +/* size_t xmlBufUse(const xmlBufPtr buf); */ +XML_HIDDEN int +xmlBufIsEmpty(const xmlBufPtr buf); +XML_HIDDEN int +xmlBufAddLen(xmlBufPtr buf, size_t len); + +/* const xmlChar * xmlBufContent(const xmlBuf *buf); */ +/* const xmlChar * xmlBufEnd(xmlBufPtr buf); */ + +XML_HIDDEN xmlChar * +xmlBufDetach(xmlBufPtr buf); + +XML_HIDDEN size_t +xmlBufDump(FILE *file, xmlBufPtr buf); + +XML_HIDDEN xmlBufPtr +xmlBufFromBuffer(xmlBufferPtr buffer); +XML_HIDDEN xmlBufferPtr +xmlBufBackToBuffer(xmlBufPtr buf); + +XML_HIDDEN int +xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input); +XML_HIDDEN int +xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos); + +#endif /* XML_BUF_H_PRIVATE__ */ diff --git a/include/private/dict.h b/include/private/dict.h new file mode 100644 index 00000000000..826ac54a51f --- /dev/null +++ b/include/private/dict.h @@ -0,0 +1,74 @@ +#ifndef XML_DICT_H_PRIVATE__ +#define XML_DICT_H_PRIVATE__ + +#include + +/* + * Values are ANDed with 0xFFFFFFFF to support platforms where + * unsigned is larger than 32 bits. With 32-bit unsigned values, + * modern compilers should optimize the operation away. + */ + +#define HASH_ROL(x,n) ((x) << (n) | ((x) & 0xFFFFFFFF) >> (32 - (n))) +#define HASH_ROR(x,n) (((x) & 0xFFFFFFFF) >> (n) | (x) << (32 - (n))) + +/* + * GoodOAAT: One of a smallest non-multiplicative One-At-a-Time functions + * that passes SMHasher. + * + * Author: Sokolov Yura aka funny-falcon + */ + +#define HASH_INIT(h1, h2, seed) \ + do { \ + h1 = seed ^ 0x3b00; \ + h2 = HASH_ROL(seed, 15); \ + } while (0) + +#define HASH_UPDATE(h1, h2, ch) \ + do { \ + h1 += ch; \ + h1 += h1 << 3; \ + h2 += h1; \ + h2 = HASH_ROL(h2, 7); \ + h2 += h2 << 2; \ + } while (0) + +/* Result is in h2 */ +#define HASH_FINISH(h1, h2) \ + do { \ + h1 ^= h2; \ + h1 += HASH_ROL(h2, 14); \ + h2 ^= h1; h2 += HASH_ROR(h1, 6); \ + h1 ^= h2; h1 += HASH_ROL(h2, 5); \ + h2 ^= h1; h2 += HASH_ROR(h1, 8); \ + h2 &= 0xFFFFFFFF; \ + } while (0) + +typedef struct { + unsigned hashValue; + const xmlChar *name; +} xmlHashedString; + +XML_HIDDEN void +xmlInitDictInternal(void); +XML_HIDDEN void +xmlCleanupDictInternal(void); + +XML_HIDDEN unsigned +xmlDictComputeHash(const xmlDict *dict, const xmlChar *string); +XML_HIDDEN unsigned +xmlDictCombineHash(unsigned v1, unsigned v2); +XML_HIDDEN xmlHashedString +xmlDictLookupHashed(xmlDictPtr dict, const xmlChar *name, int len); + +XML_HIDDEN void +xmlInitRandom(void); +XML_HIDDEN void +xmlCleanupRandom(void); +XML_HIDDEN unsigned +xmlGlobalRandom(void); +XML_HIDDEN unsigned +xmlRandom(void); + +#endif /* XML_DICT_H_PRIVATE__ */ diff --git a/include/private/enc.h b/include/private/enc.h new file mode 100644 index 00000000000..cd549145eb2 --- /dev/null +++ b/include/private/enc.h @@ -0,0 +1,18 @@ +#ifndef XML_ENC_H_PRIVATE__ +#define XML_ENC_H_PRIVATE__ + +#include +#include + +XML_HIDDEN void +xmlInitEncodingInternal(void); + +XML_HIDDEN int +xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out, + int *outlen, const unsigned char *in, int *inlen); +XML_HIDDEN int +xmlCharEncInput(xmlParserInputBufferPtr input); +XML_HIDDEN int +xmlCharEncOutput(xmlOutputBufferPtr output, int init); + +#endif /* XML_ENC_H_PRIVATE__ */ diff --git a/include/private/entities.h b/include/private/entities.h new file mode 100644 index 00000000000..d262ef47f65 --- /dev/null +++ b/include/private/entities.h @@ -0,0 +1,27 @@ +#ifndef XML_ENTITIES_H_PRIVATE__ +#define XML_ENTITIES_H_PRIVATE__ + +#include +#include + +/* + * Entity flags + * + * XML_ENT_PARSED: The entity was parsed and `children` points to the + * content. + * + * XML_ENT_CHECKED: The entity was checked for loops and amplification. + * expandedSize was set. + * + * XML_ENT_VALIDATED: The entity contains a valid attribute value. + * Only used when entities aren't substituted. + */ +#define XML_ENT_PARSED (1u << 0) +#define XML_ENT_CHECKED (1u << 1) +#define XML_ENT_VALIDATED (1u << 2) +#define XML_ENT_EXPANDING (1u << 3) + +XML_HIDDEN xmlChar * +xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input); + +#endif /* XML_ENTITIES_H_PRIVATE__ */ diff --git a/include/private/error.h b/include/private/error.h new file mode 100644 index 00000000000..506405a1f06 --- /dev/null +++ b/include/private/error.h @@ -0,0 +1,34 @@ +#ifndef XML_ERROR_H_PRIVATE__ +#define XML_ERROR_H_PRIVATE__ + +#include +#include + +#define MAX_ERR_MSG_SIZE 64000 + +struct _xmlNode; + +XML_HIDDEN void +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error); +XML_HIDDEN int +xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, va_list ap); +XML_HIDDEN int +__xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, ...) LIBXML_ATTR_FORMAT(16,17); +XML_HIDDEN void +xmlGenericErrorDefaultFunc(void *ctx, const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XML_HIDDEN const char * +xmlErrString(xmlParserErrors code); + +#endif /* XML_ERROR_H_PRIVATE__ */ diff --git a/include/private/globals.h b/include/private/globals.h new file mode 100644 index 00000000000..828b6d50fe7 --- /dev/null +++ b/include/private/globals.h @@ -0,0 +1,14 @@ +#ifndef XML_GLOBALS_H_PRIVATE__ +#define XML_GLOBALS_H_PRIVATE__ + +XML_HIDDEN void +xmlInitGlobalsInternal(void); +XML_HIDDEN void +xmlCleanupGlobalsInternal(void); + +#ifdef LIBXML_THREAD_ENABLED +XML_HIDDEN unsigned * +xmlGetLocalRngState(void); +#endif + +#endif /* XML_GLOBALS_H_PRIVATE__ */ diff --git a/include/private/html.h b/include/private/html.h new file mode 100644 index 00000000000..6b499296a6b --- /dev/null +++ b/include/private/html.h @@ -0,0 +1,14 @@ +#ifndef XML_HTML_H_PRIVATE__ +#define XML_HTML_H_PRIVATE__ + +#include + +#ifdef LIBXML_HTML_ENABLED + +XML_HIDDEN void +__htmlParseContent(void *ctx); + +#endif /* LIBXML_HTML_ENABLED */ + +#endif /* XML_HTML_H_PRIVATE__ */ + diff --git a/include/private/io.h b/include/private/io.h new file mode 100644 index 00000000000..a2535ae1961 --- /dev/null +++ b/include/private/io.h @@ -0,0 +1,35 @@ +#ifndef XML_IO_H_PRIVATE__ +#define XML_IO_H_PRIVATE__ + +#include +#include +#include + +XML_HIDDEN void +xmlInitIOCallbacks(void); + +XML_HIDDEN int +__xmlIOErr(int domain, int code, const char *extra); + +XML_HIDDEN int +xmlNoNetExists(const char *filename); + +XML_HIDDEN int +xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out); + +XML_HIDDEN xmlParserInputBufferPtr +xmlNewInputBufferString(const char *str, int flags); +XML_HIDDEN xmlParserInputBufferPtr +xmlNewInputBufferMemory(const void *mem, size_t size, int flags, + xmlCharEncoding enc); + +#ifdef LIBXML_OUTPUT_ENABLED +XML_HIDDEN xmlOutputBufferPtr +xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); +XML_HIDDEN void +xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf, + const xmlChar *string); +#endif + +#endif /* XML_IO_H_PRIVATE__ */ diff --git a/include/private/memory.h b/include/private/memory.h new file mode 100644 index 00000000000..ef0497c65cf --- /dev/null +++ b/include/private/memory.h @@ -0,0 +1,9 @@ +#ifndef XML_MEMORY_H_PRIVATE__ +#define XML_MEMORY_H_PRIVATE__ + +XML_HIDDEN void +xmlInitMemoryInternal(void); +XML_HIDDEN void +xmlCleanupMemoryInternal(void); + +#endif /* XML_MEMORY_H_PRIVATE__ */ diff --git a/include/private/parser.h b/include/private/parser.h new file mode 100644 index 00000000000..b14bebf918e --- /dev/null +++ b/include/private/parser.h @@ -0,0 +1,121 @@ +#ifndef XML_PARSER_H_PRIVATE__ +#define XML_PARSER_H_PRIVATE__ + +#include +#include + +/** + * XML_VCTXT_DTD_VALIDATED: + * + * Set after xmlValidateDtdFinal was called. + */ +#define XML_VCTXT_DTD_VALIDATED (1u << 0) +/** + * XML_VCTXT_USE_PCTXT: + * + * Set if the validation context is part of a parser context. + */ +#define XML_VCTXT_USE_PCTXT (1u << 1) + +#define XML_INPUT_HAS_ENCODING (1u << 0) +#define XML_INPUT_AUTO_ENCODING (7u << 1) +#define XML_INPUT_AUTO_UTF8 (1u << 1) +#define XML_INPUT_AUTO_UTF16LE (2u << 1) +#define XML_INPUT_AUTO_UTF16BE (3u << 1) +#define XML_INPUT_AUTO_OTHER (4u << 1) +#define XML_INPUT_USES_ENC_DECL (1u << 4) +#define XML_INPUT_ENCODING_ERROR (1u << 5) +#define XML_INPUT_PROGRESSIVE (1u << 6) + +#define PARSER_STOPPED(ctxt) ((ctxt)->disableSAX > 1) + +#define PARSER_PROGRESSIVE(ctxt) \ + ((ctxt)->input->flags & XML_INPUT_PROGRESSIVE) + +#define PARSER_IN_PE(ctxt) \ + (((ctxt)->input->entity != NULL) && \ + (((ctxt)->input->entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || \ + ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY))) + +#define PARSER_EXTERNAL(ctxt) \ + (((ctxt)->inSubset == 2) || \ + (((ctxt)->input->entity != NULL) && \ + ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY))) + +XML_HIDDEN void +xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, va_list ap); +XML_HIDDEN void +xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, ...); +XML_HIDDEN void +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); +XML_HIDDEN void LIBXML_ATTR_FORMAT(3,0) +xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1, const xmlChar *str2); +XML_HIDDEN void +xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri); + +XML_HIDDEN void +xmlHaltParser(xmlParserCtxtPtr ctxt); +XML_HIDDEN int +xmlParserGrow(xmlParserCtxtPtr ctxt); +XML_HIDDEN void +xmlParserShrink(xmlParserCtxtPtr ctxt); + +XML_HIDDEN void +xmlDetectEncoding(xmlParserCtxtPtr ctxt); +XML_HIDDEN void +xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding); +XML_HIDDEN const xmlChar * +xmlGetActualEncoding(xmlParserCtxtPtr ctxt); + +XML_HIDDEN xmlParserNsData * +xmlParserNsCreate(void); +XML_HIDDEN void +xmlParserNsFree(xmlParserNsData *nsdb); +/* + * These functions allow SAX handlers to attach extra data to namespaces + * efficiently and should be made public. + */ +XML_HIDDEN int +xmlParserNsUpdateSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix, + void *saxData); +XML_HIDDEN void * +xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix); + +#define XML_INPUT_BUF_STATIC (1u << 1) +#define XML_INPUT_BUF_ZERO_TERMINATED (1u << 2) + +XML_HIDDEN xmlParserInputPtr +xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url, + const void *mem, size_t size, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url, const char *str, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *filename, int fd, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url, + xmlInputReadCallback ioRead, + xmlInputCloseCallback ioClose, + void *ioCtxt, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url, + const char *chunk, int size, const char *encoding); + +XML_HIDDEN xmlChar * +xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str, + int normalize); + +#endif /* XML_PARSER_H_PRIVATE__ */ diff --git a/include/private/regexp.h b/include/private/regexp.h new file mode 100644 index 00000000000..b55c932bc0e --- /dev/null +++ b/include/private/regexp.h @@ -0,0 +1,23 @@ +#ifndef XML_REGEXP_H_PRIVATE__ +#define XML_REGEXP_H_PRIVATE__ + +#include + +#ifdef LIBXML_REGEXP_ENABLED + +/* + * -2 and -3 are used by xmlValidateElementType for other things. + */ +#define XML_REGEXP_OK 0 +#define XML_REGEXP_NOT_FOUND (-1) +#define XML_REGEXP_INTERNAL_ERROR (-4) +#define XML_REGEXP_OUT_OF_MEMORY (-5) +#define XML_REGEXP_INTERNAL_LIMIT (-6) +#define XML_REGEXP_INVALID_UTF8 (-7) + +XML_HIDDEN void +xmlAutomataSetFlags(xmlAutomataPtr am, int flags); + +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /* XML_REGEXP_H_PRIVATE__ */ diff --git a/include/private/save.h b/include/private/save.h new file mode 100644 index 00000000000..5d4a753f1ac --- /dev/null +++ b/include/private/save.h @@ -0,0 +1,24 @@ +#ifndef XML_SAVE_H_PRIVATE__ +#define XML_SAVE_H_PRIVATE__ + +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED + +XML_HIDDEN int +xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur); +XML_HIDDEN int +xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur); + +XML_HIDDEN void +xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc, + const xmlChar *string); +XML_HIDDEN void +xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); + +#endif /* LIBXML_OUTPUT_ENABLED */ + +#endif /* XML_SAVE_H_PRIVATE__ */ + diff --git a/include/private/string.h b/include/private/string.h new file mode 100644 index 00000000000..34f4c96cb20 --- /dev/null +++ b/include/private/string.h @@ -0,0 +1,13 @@ +#ifndef XML_STRING_H_PRIVATE__ +#define XML_STRING_H_PRIVATE__ + +#include + +XML_HIDDEN int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap); +XML_HIDDEN int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...); +XML_HIDDEN xmlChar * +xmlEscapeFormatString(xmlChar **msg); + +#endif /* XML_STRING_H_PRIVATE__ */ diff --git a/include/private/threads.h b/include/private/threads.h new file mode 100644 index 00000000000..473bc7c0bcb --- /dev/null +++ b/include/private/threads.h @@ -0,0 +1,35 @@ +#ifndef XML_THREADS_H_PRIVATE__ +#define XML_THREADS_H_PRIVATE__ + +#include + +#ifdef LIBXML_THREAD_ENABLED + #ifdef HAVE_PTHREAD_H + #include + #define HAVE_POSIX_THREADS + #elif defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include + #define HAVE_WIN32_THREADS + #endif +#endif + +/* + * xmlMutex are a simple mutual exception locks + */ +struct _xmlMutex { +#ifdef HAVE_POSIX_THREADS + pthread_mutex_t lock; +#elif defined HAVE_WIN32_THREADS + CRITICAL_SECTION cs; +#else + int empty; +#endif +}; + +XML_HIDDEN void +xmlInitMutex(xmlMutexPtr mutex); +XML_HIDDEN void +xmlCleanupMutex(xmlMutexPtr mutex); + +#endif /* XML_THREADS_H_PRIVATE__ */ diff --git a/include/private/tree.h b/include/private/tree.h new file mode 100644 index 00000000000..2d651d53f4b --- /dev/null +++ b/include/private/tree.h @@ -0,0 +1,27 @@ +#ifndef XML_TREE_H_PRIVATE__ +#define XML_TREE_H_PRIVATE__ + +/* + * 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. + */ +XML_HIDDEN extern int +__xmlRegisterCallbacks; + +XML_HIDDEN int +xmlSearchNsSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out); +XML_HIDDEN int +xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out); + +XML_HIDDEN int +xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len); +XML_HIDDEN xmlNodePtr +xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, + int extended); +XML_HIDDEN xmlNodePtr +xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); +XML_HIDDEN const xmlChar * +xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr); + +#endif /* XML_TREE_H_PRIVATE__ */ diff --git a/include/private/xinclude.h b/include/private/xinclude.h new file mode 100644 index 00000000000..43c77e50618 --- /dev/null +++ b/include/private/xinclude.h @@ -0,0 +1,9 @@ +#ifndef XML_INCLUDE_H_PRIVATE__ +#define XML_INCLUDE_H_PRIVATE__ + +#include + +XML_HIDDEN int +xmlXIncludeSetStreamingMode(xmlXIncludeCtxtPtr ctxt, int mode); + +#endif /* XML_INCLUDE_H_PRIVATE__ */ diff --git a/include/private/xpath.h b/include/private/xpath.h new file mode 100644 index 00000000000..72a69720332 --- /dev/null +++ b/include/private/xpath.h @@ -0,0 +1,16 @@ +#ifndef XML_XPATH_H_PRIVATE__ +#define XML_XPATH_H_PRIVATE__ + +#include + +XML_HIDDEN void +xmlInitXPathInternal(void); + +#ifdef LIBXML_XPATH_ENABLED +XML_HIDDEN void +xmlXPathErrMemory(xmlXPathContextPtr ctxt); +XML_HIDDEN void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt); +#endif + +#endif /* XML_XPATH_H_PRIVATE__ */ diff --git a/include/private/xzlib.h b/include/private/xzlib.h new file mode 100644 index 00000000000..8505ef329e8 --- /dev/null +++ b/include/private/xzlib.h @@ -0,0 +1,32 @@ +/** + * xzlib.h: header for the front end for the transparent support of lzma + * compression at the I/O layer + * + * See Copyright for the status of this software. + * + * Anders F Bjorklund + */ + +#ifndef LIBXML2_XZLIB_H +#define LIBXML2_XZLIB_H + +#include + +#ifdef LIBXML_LZMA_ENABLED + +typedef void *xzFile; /* opaque lzma file descriptor */ + +XML_HIDDEN xzFile +__libxml2_xzopen(const char *path, const char *mode); +XML_HIDDEN xzFile +__libxml2_xzdopen(const char *path, int fd, const char *mode); +XML_HIDDEN int +__libxml2_xzread(xzFile file, void *buf, unsigned len); +XML_HIDDEN int +__libxml2_xzclose(xzFile file); +XML_HIDDEN int +__libxml2_xzcompressed(xzFile f); + +#endif /* LIBXML_LZMA_ENABLED */ + +#endif /* LIBXML2_XZLIB_H */ diff --git a/include/win32config.h b/include/win32config.h index 4f99ae0b2ea..a25e0385024 100644 --- a/include/win32config.h +++ b/include/win32config.h @@ -1,20 +1,21 @@ #ifndef __LIBXML_WIN32_CONFIG__ #define __LIBXML_WIN32_CONFIG__ -#define SEND_ARG2_CAST -#define GETHOSTBYNAME_ARG_CAST - #define HAVE_SYS_STAT_H #define HAVE_STAT #define HAVE_FCNTL_H #if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1600) -#define HAVE_STDINT_H + #define HAVE_STDINT_H #endif -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#define vsnprintf _vsnprintf +#if defined(_MSC_VER) + #if _MSC_VER < 1900 + #define snprintf _snprintf + #endif + #if _MSC_VER < 1500 + #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) + #endif #endif #endif /* __LIBXML_WIN32_CONFIG__ */ diff --git a/include/wsockcompat.h b/include/wsockcompat.h new file mode 100644 index 00000000000..141de0c6405 --- /dev/null +++ b/include/wsockcompat.h @@ -0,0 +1,53 @@ +/* include/wsockcompat.h + * Windows -> Berkeley Sockets compatibility things. + */ + +#if !defined __XML_WSOCKCOMPAT_H__ +#define __XML_WSOCKCOMPAT_H__ + +#include +#include + +/* Fix for old MinGW. */ +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ +#endif + +/* the following is a workaround a problem for 'inline' keyword in said + header when compiled with Borland C++ 6 */ +#if defined(__BORLANDC__) && !defined(__cplusplus) +#define inline __inline +#define _inline __inline +#endif + +#include + +/* Check if ws2tcpip.h is a recent version which provides getaddrinfo() */ +#if defined(GetAddrInfo) +#include +#ifndef SUPPORT_IP6 + #define SUPPORT_IP6 +#endif +#endif + +#ifndef XML_SOCKLEN_T +#define XML_SOCKLEN_T int +#endif + +#ifndef ECONNRESET +#define ECONNRESET WSAECONNRESET +#endif +#ifndef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#endif +#ifndef EINTR +#define EINTR WSAEINTR +#endif +#ifndef ESHUTDOWN +#define ESHUTDOWN WSAESHUTDOWN +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +#endif /* __XML_WSOCKCOMPAT_H__ */ diff --git a/legacy.c b/legacy.c index bde3854d92b..ac80c0e4df9 100644 --- a/legacy.c +++ b/legacy.c @@ -11,6 +11,7 @@ #include "libxml.h" #ifdef LIBXML_LEGACY_ENABLED +#include #include #include @@ -55,7 +56,7 @@ htmlDecodeEntities(htmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "htmlDecodeEntities() deprecated function reached\n"); deprecated = 1; } @@ -416,7 +417,7 @@ xmlDecodeEntities(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlDecodeEntities() deprecated function reached\n"); deprecated = 1; } @@ -446,7 +447,7 @@ xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlNamespaceParseNCName() deprecated function reached\n"); deprecated = 1; } @@ -481,7 +482,7 @@ xmlNamespaceParseQName(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlNamespaceParseQName() deprecated function reached\n"); deprecated = 1; } @@ -510,7 +511,7 @@ xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlNamespaceParseNSDef() deprecated function reached\n"); deprecated = 1; } @@ -533,7 +534,7 @@ xmlParseQuotedString(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlParseQuotedString() deprecated function reached\n"); deprecated = 1; } @@ -561,7 +562,7 @@ xmlParseNamespace(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlParseNamespace() deprecated function reached\n"); deprecated = 1; } @@ -593,7 +594,7 @@ xmlScanName(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlScanName() deprecated function reached\n"); deprecated = 1; } @@ -633,7 +634,7 @@ xmlParserHandleReference(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlParserHandleReference() deprecated function reached\n"); deprecated = 1; } @@ -659,7 +660,7 @@ xmlHandleEntity(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlHandleEntity() deprecated function reached\n"); deprecated = 1; } @@ -683,7 +684,7 @@ xmlNewGlobalNs(xmlDocPtr doc ATTRIBUTE_UNUSED, static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlNewGlobalNs() deprecated function reached\n"); deprecated = 1; } @@ -703,7 +704,7 @@ xmlUpgradeOldNs(xmlDocPtr doc ATTRIBUTE_UNUSED) static int deprecated = 0; if (!deprecated) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "xmlUpgradeOldNs() deprecated function reached\n"); deprecated = 1; } @@ -729,15 +730,26 @@ xmlEncodeEntities(xmlDocPtr doc ATTRIBUTE_UNUSED, static int warning = 1; if (warning) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n"); - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n"); warning = 0; } return (NULL); } +/** + * xmlSetEntityReferenceFunc: + * @func: A valid function + * + * Set the function to call call back when a xml reference has been made + */ +void +xmlSetEntityReferenceFunc(xmlEntityReferenceFunc func ATTRIBUTE_UNUSED) +{ +} + /************************************************************************ * * * Old set of SAXv1 functions * @@ -747,7 +759,7 @@ static int deprecated_v1_msg = 0; #define DEPRECATED(n) \ if (deprecated_v1_msg == 0) \ - xmlGenericError(xmlGenericErrorContext, \ + fprintf(stderr, \ "Use of deprecated SAXv1 function %s\n", n); \ deprecated_v1_msg++; @@ -1338,5 +1350,427 @@ cdataBlock(void *ctx, const xmlChar * value, int len) xmlSAX2CDataBlock(ctx, value, len); } +/* + * nanoftp.h + */ + +#ifndef LIBXML_FTP_ENABLED + +#include + +/** DOC_DISABLE */ + +#ifdef _WIN32 + #include +#else + #define SOCKET int +#endif + +typedef void +(*ftpListCallback)(void *userData, const char *filename, const char *attrib, + const char *owner, const char *group, unsigned long size, + int links, int year, const char *month, int day, int hour, + int minute); + +typedef void +(*ftpDataCallback) (void *userData, const char *data, int len); + +XMLPUBFUN void +xmlNanoFTPInit(void); + +void +xmlNanoFTPInit(void) { +} + +XMLPUBFUN void +xmlNanoFTPCleanup(void); + +void +xmlNanoFTPCleanup(void) { +} + +XMLPUBFUN void +xmlNanoFTPProxy(const char *host, int port, const char *user, + const char *passwd, int type); + +void +xmlNanoFTPProxy(const char *host ATTRIBUTE_UNUSED, int port ATTRIBUTE_UNUSED, + const char *user ATTRIBUTE_UNUSED, + const char *passwd ATTRIBUTE_UNUSED, int type ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN int +xmlNanoFTPUpdateURL(void *ctx, const char *URL); + +int +xmlNanoFTPUpdateURL(void *ctx ATTRIBUTE_UNUSED, + const char *URL ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN void +xmlNanoFTPScanProxy(const char *URL); + +void +xmlNanoFTPScanProxy(const char *URL ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN void * +xmlNanoFTPNewCtxt(const char *URL); + +void* +xmlNanoFTPNewCtxt(const char *URL ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN void +xmlNanoFTPFreeCtxt(void *ctx); + +void +xmlNanoFTPFreeCtxt(void * ctx ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN int +xmlNanoFTPGetResponse(void *ctx); + +int +xmlNanoFTPGetResponse(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPCheckResponse(void *ctx); + +int +xmlNanoFTPCheckResponse(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPQuit(void *ctx); + +int +xmlNanoFTPQuit(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPConnect(void *ctx); + +int +xmlNanoFTPConnect(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN void * +xmlNanoFTPConnectTo(const char *server, int port); + +void* +xmlNanoFTPConnectTo(const char *server ATTRIBUTE_UNUSED, + int port ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN int +xmlNanoFTPCwd(void *ctx, const char *directory); + +int +xmlNanoFTPCwd(void *ctx ATTRIBUTE_UNUSED, + const char *directory ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPDele(void *ctx, const char *file); + +int +xmlNanoFTPDele(void *ctx ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN SOCKET +xmlNanoFTPGetConnection(void *ctx); + +SOCKET +xmlNanoFTPGetConnection(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPCloseConnection(void *ctx); + +int +xmlNanoFTPCloseConnection(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, + const char *filename); + +int +xmlNanoFTPList(void *ctx ATTRIBUTE_UNUSED, + ftpListCallback callback ATTRIBUTE_UNUSED, + void *userData ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN SOCKET +xmlNanoFTPGetSocket(void *ctx, const char *filename); + +SOCKET +xmlNanoFTPGetSocket(void *ctx ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData, + const char *filename); + +int +xmlNanoFTPGet(void *ctx ATTRIBUTE_UNUSED, + ftpDataCallback callback ATTRIBUTE_UNUSED, + void *userData ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlNanoFTPRead(void *ctx, void *dest, int len); + +int +xmlNanoFTPRead(void *ctx ATTRIBUTE_UNUSED, void *dest ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN void * +xmlNanoFTPOpen(const char *URL); + +void* +xmlNanoFTPOpen(const char *URL ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN int +xmlNanoFTPClose(void *ctx); + +int +xmlNanoFTPClose(void *ctx ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlIOFTPMatch(const char *filename); + +int +xmlIOFTPMatch(const char *filename ATTRIBUTE_UNUSED) { + return(0); +} + +XMLPUBFUN void * +xmlIOFTPOpen(const char *filename); + +void * +xmlIOFTPOpen(const char *filename ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN int +xmlIOFTPRead(void *context, char *buffer, int len); + +int +xmlIOFTPRead(void *context ATTRIBUTE_UNUSED, char *buffer ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) { + return(-1); +} + +XMLPUBFUN int +xmlIOFTPClose(void *context); + +int +xmlIOFTPClose(void *context ATTRIBUTE_UNUSED) { + return(-1); +} + +/** DOC_ENABLE */ + +#endif /* #ifndef LIBXML_FTP_ENABLED */ + +/* + * xpointer.h + */ + +#ifndef LIBXML_XPTR_LOCS_ENABLED + +#include +#include +#include + +/** DOC_DISABLE */ + +typedef struct _xmlLocationSet *xmlLocationSetPtr; + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRange(xmlNodePtr start, int startindex, + xmlNodePtr end, int endindex); + +xmlXPathObjectPtr +xmlXPtrNewRange(xmlNodePtr start ATTRIBUTE_UNUSED, + int startindex ATTRIBUTE_UNUSED, + xmlNodePtr end ATTRIBUTE_UNUSED, + int endindex ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end); + +xmlXPathObjectPtr +xmlXPtrNewRangePoints(xmlXPathObjectPtr start ATTRIBUTE_UNUSED, + xmlXPathObjectPtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end); + +xmlXPathObjectPtr +xmlXPtrNewRangePointNode(xmlXPathObjectPtr start ATTRIBUTE_UNUSED, + xmlNodePtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end); + +xmlXPathObjectPtr +xmlXPtrNewRangeNodePoint(xmlNodePtr start ATTRIBUTE_UNUSED, + xmlXPathObjectPtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end); + +xmlXPathObjectPtr +xmlXPtrNewRangeNodes(xmlNodePtr start ATTRIBUTE_UNUSED, + xmlNodePtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewCollapsedRange(xmlNodePtr start); + +xmlXPathObjectPtr +xmlXPtrNewCollapsedRange(xmlNodePtr start ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end); + +xmlXPathObjectPtr +xmlXPtrNewRangeNodeObject(xmlNodePtr start ATTRIBUTE_UNUSED, + xmlXPathObjectPtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlLocationSetPtr +xmlXPtrLocationSetCreate(xmlXPathObjectPtr val); + +xmlLocationSetPtr +xmlXPtrLocationSetCreate(xmlXPathObjectPtr val ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN void +xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val); + +void +xmlXPtrLocationSetAdd(xmlLocationSetPtr cur ATTRIBUTE_UNUSED, + xmlXPathObjectPtr val ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN xmlLocationSetPtr +xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2); + +xmlLocationSetPtr +xmlXPtrLocationSetMerge(xmlLocationSetPtr val1 ATTRIBUTE_UNUSED, + xmlLocationSetPtr val2 ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN void +xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val); + +void +xmlXPtrLocationSetDel(xmlLocationSetPtr cur ATTRIBUTE_UNUSED, + xmlXPathObjectPtr val ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN void +xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val); + +void +xmlXPtrLocationSetRemove(xmlLocationSetPtr cur ATTRIBUTE_UNUSED, + int val ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN void +xmlXPtrFreeLocationSet(xmlLocationSetPtr obj); + +void +xmlXPtrFreeLocationSet(xmlLocationSetPtr obj ATTRIBUTE_UNUSED) { +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end); + +xmlXPathObjectPtr +xmlXPtrNewLocationSetNodes(xmlNodePtr start ATTRIBUTE_UNUSED, + xmlNodePtr end ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set); + +xmlXPathObjectPtr +xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlXPathObjectPtr +xmlXPtrWrapLocationSet(xmlLocationSetPtr val); + +xmlXPathObjectPtr +xmlXPtrWrapLocationSet(xmlLocationSetPtr val ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN xmlNodePtr +xmlXPtrBuildNodeList(xmlXPathObjectPtr obj); + +xmlNodePtr +xmlXPtrBuildNodeList(xmlXPathObjectPtr obj ATTRIBUTE_UNUSED) { + return(NULL); +} + +XMLPUBFUN void +xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs); + +void +xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, + int nargs ATTRIBUTE_UNUSED) { + XP_ERROR(XPATH_EXPR_ERROR); +} + +/** DOC_ENABLE */ + +#endif /* #ifndef LIBXML_XPTR_LOCS_ENABLED */ + #endif /* LIBXML_LEGACY_ENABLED */ diff --git a/libxml.h b/libxml.h index 66f164d544b..d94677b5669 100644 --- a/libxml.h +++ b/libxml.h @@ -14,103 +14,57 @@ * Do not add any #include directives above this block. */ #ifndef NO_LARGEFILE_SOURCE -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE -#endif -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif + #ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE + #endif + #ifndef _FILE_OFFSET_BITS + #define _FILE_OFFSET_BITS 64 + #endif #endif /* - * Currently supported platforms use either autoconf or - * copy to config.h own "preset" configuration file. - * As result ifdef HAVE_CONFIG_H is omitted here. + * These files are generated by the build system and contain private + * and public build configuration. */ #include "config.h" #include -#include +/* + * Due to some Autotools limitations, this variable must be passed as + * compiler flag. Define a default value if the macro wasn't set by the + * build system. + */ #ifndef SYSCONFDIR #define SYSCONFDIR "/etc" #endif -#if defined(__Lynx__) -#include /* pull definition of size_t */ -#include -int snprintf(char *, size_t, const char *, ...); -int vfprintf(FILE *, const char *, va_list); -#endif - -#ifndef WITH_TRIO -#include +#if !defined(_WIN32) && \ + !defined(__CYGWIN__) && \ + (defined(__clang__) || \ + (defined(__GNUC__) && (__GNUC__ >= 4))) + #define XML_HIDDEN __attribute__((visibility("hidden"))) #else -/** - * TRIO_REPLACE_STDIO: - * - * This macro is defined if the trio string formatting functions are to - * be used instead of the default stdio ones. - */ -#define TRIO_REPLACE_STDIO -#include "trio.h" + #define XML_HIDDEN #endif #if defined(__clang__) || \ - (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) -#define XML_IGNORE_PEDANTIC_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wpedantic\"") -#define XML_POP_WARNINGS \ - _Pragma("GCC diagnostic pop") + (defined(__GNUC__) && (__GNUC__ >= 8) && !defined(__EDG__)) + #define ATTRIBUTE_NO_SANITIZE(arg) __attribute__((no_sanitize(arg))) #else -#define XML_IGNORE_PEDANTIC_WARNINGS -#define XML_POP_WARNINGS + #define ATTRIBUTE_NO_SANITIZE(arg) #endif -#if defined(__clang__) || \ - (defined(__GNUC__) && (__GNUC__ >= 8)) -#define ATTRIBUTE_NO_SANITIZE(arg) __attribute__((no_sanitize(arg))) +#ifdef __clang__ + #if __clang_major__ >= 12 + #define ATTRIBUTE_NO_SANITIZE_INTEGER \ + ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") \ + ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") + #else + #define ATTRIBUTE_NO_SANITIZE_INTEGER \ + ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") + #endif #else -#define ATTRIBUTE_NO_SANITIZE(arg) -#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 part of the API. - */ -void __xmlIOErr(int domain, int code, const char *extra); -void __xmlLoaderErr(void *ctx, const char *msg, const char *filename) LIBXML_ATTR_FORMAT(2,0); -#ifdef LIBXML_HTML_ENABLED -/* - * internal function of HTML parser needed for xmlParseInNodeContext - * but not part of the API - */ -void __htmlParseContent(void *ctx); + #define ATTRIBUTE_NO_SANITIZE_INTEGER #endif -/* - * internal global initialization critical section routines. - */ -void __xmlGlobalInitMutexLock(void); -void __xmlGlobalInitMutexUnlock(void); -void __xmlGlobalInitMutexDestroy(void); - -int __xmlInitializeDict(void); - -/* - * internal thread safe random function - */ -int __xmlRandom(void); - -XMLPUBFUN xmlChar * XMLCALL xmlEscapeFormatString(xmlChar **msg); -int xmlInputReadCallbackNop(void *context, char *buffer, int len); - -#if !defined(PIC) && !defined(NOLIBTOOL) && !defined(LIBXML_STATIC) -# define LIBXML_STATIC -#endif #endif /* ! __XML_LIBXML_H__ */ diff --git a/list.c b/list.c index 12a7c009277..20df26c87c7 100644 --- a/list.c +++ b/list.c @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include /* * Type definition are kept internal @@ -188,18 +188,13 @@ xmlListPtr xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare) { xmlListPtr l; - if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for list"); + if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) return (NULL); - } /* Initialize the list to NULL */ memset(l, 0, sizeof(xmlList)); /* Add the sentinel */ if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for sentinel"); xmlFree(l); return (NULL); } @@ -279,11 +274,8 @@ xmlListInsert(xmlListPtr l, void *data) lkPlace = xmlListLowerSearch(l, data); /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (1); - } lkNew->data = data; lkPlace = lkPlace->prev; lkNew->next = lkPlace->next; @@ -311,11 +303,8 @@ int xmlListAppend(xmlListPtr l, void *data) lkPlace = xmlListHigherSearch(l, data); /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (1); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -548,11 +537,8 @@ xmlListPushFront(xmlListPtr l, void *data) lkPlace = l->sentinel; /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (0); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -579,11 +565,8 @@ xmlListPushBack(xmlListPtr l, void *data) return(0); lkPlace = l->sentinel->prev; /* Add the new link */ - if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) return (0); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -729,7 +712,7 @@ xmlListMerge(xmlListPtr l1, xmlListPtr l2) * Returns a new copy of the list or NULL in case of error */ xmlListPtr -xmlListDup(const xmlListPtr old) +xmlListDup(xmlListPtr old) { xmlListPtr cur; @@ -758,7 +741,7 @@ xmlListDup(const xmlListPtr old) * Returns 0 in case of success 1 in case of error */ int -xmlListCopy(xmlListPtr cur, const xmlListPtr old) +xmlListCopy(xmlListPtr cur, xmlListPtr old) { /* Walk the old tree and insert the data into the new one */ xmlLinkPtr lk; diff --git a/nanoftp.c b/nanoftp.c index 6de7d300a3a..fc8f8d75145 100644 --- a/nanoftp.c +++ b/nanoftp.c @@ -23,6 +23,8 @@ #ifdef HAVE_UNISTD_H #include +#elif defined (_WIN32) +#include #endif #ifdef HAVE_SYS_SOCKET_H #include @@ -48,24 +50,15 @@ #ifdef HAVE_SYS_SOCKET_H #include #endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif #include #include #include #include #include -#include - -/* #define DEBUG_FTP 1 */ -#ifdef STANDALONE -#ifndef DEBUG_FTP -#define DEBUG_FTP 1 -#endif -#endif +#include "private/error.h" +#include "private/io.h" #if defined(_WIN32) #include @@ -75,27 +68,16 @@ * A couple portability macros */ #ifndef _WINSOCKAPI_ -#if !defined(__BEOS__) || defined(__HAIKU__) #define closesocket(s) close(s) #endif -#endif - -#ifdef __BEOS__ -#ifndef PF_INET -#define PF_INET AF_INET -#endif -#endif - -#ifdef _AIX -#ifdef HAVE_BROKEN_SS_FAMILY -#define ss_family __ss_family -#endif -#endif #ifndef XML_SOCKLEN_T #define XML_SOCKLEN_T unsigned int #endif +#define GETHOSTBYNAME_ARG_CAST (char *) +#define SEND_ARG2_CAST (char *) + #define FTP_COMMAND_OK 200 #define FTP_SYNTAX_ERROR 500 #define FTP_GET_PASSWD 331 @@ -155,9 +137,9 @@ int have_ipv6(void) { * Handle an out of memory condition */ static void -xmlFTPErrMemory(const char *extra) +xmlFTPErrMemory(const char *extra ATTRIBUTE_UNUSED) { - __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_FTP, NULL); } /** @@ -417,14 +399,6 @@ xmlNanoFTPScanProxy(const char *URL) { } proxyPort = 0; -#ifdef DEBUG_FTP - if (URL == NULL) - xmlGenericError(xmlGenericErrorContext, - "Removing FTP proxy info\n"); - else - xmlGenericError(xmlGenericErrorContext, - "Using FTP proxy %s\n", URL); -#endif if (URL == NULL) return; uri = xmlParseURIRaw(URL, 1); @@ -557,28 +531,13 @@ xmlNanoFTPGetMore(void *ctx) { if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) { -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPGetMore : controlBufIndex = %d\n", - ctxt->controlBufIndex); -#endif return(-1); } if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) { -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPGetMore : controlBufUsed = %d\n", - ctxt->controlBufUsed); -#endif return(-1); } if (ctxt->controlBufIndex > ctxt->controlBufUsed) { -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n", - ctxt->controlBufIndex, ctxt->controlBufUsed); -#endif return(-1); } @@ -593,10 +552,6 @@ xmlNanoFTPGetMore(void *ctx) { } size = FTP_BUF_SIZE - ctxt->controlBufUsed; if (size == 0) { -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed); -#endif return(0); } @@ -610,11 +565,6 @@ xmlNanoFTPGetMore(void *ctx) { ctxt->controlFd = INVALID_SOCKET; return(-1); } -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPGetMore : read %d [%d - %d]\n", len, - ctxt->controlBufUsed, ctxt->controlBufUsed + len); -#endif ctxt->controlBufUsed += len; ctxt->controlBuf[ctxt->controlBufUsed] = 0; @@ -652,10 +602,6 @@ get_more: ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; end = &ctxt->controlBuf[ctxt->controlBufUsed]; -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "\n<<<\n%s\n--\n", ptr); -#endif while (ptr < end) { cur = xmlNanoFTPParseResponse(ptr, end - ptr); if (cur > 0) { @@ -682,14 +628,7 @@ get_more: if (res < 0) goto get_more; ctxt->controlBufIndex = ptr - ctxt->controlBuf; -#ifdef DEBUG_FTP - ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; - xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr); -#endif -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "Got %d\n", res); -#endif return(res / 100); } @@ -758,9 +697,6 @@ xmlNanoFTPSendUser(void *ctx) { snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -786,9 +722,6 @@ xmlNanoFTPSendPasswd(void *ctx) { snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -817,9 +750,6 @@ xmlNanoFTPQuit(void *ctx) { snprintf(buf, sizeof(buf), "QUIT\r\n"); len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */ -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1013,9 +943,6 @@ xmlNanoFTPConnect(void *ctx) { snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1036,9 +963,6 @@ xmlNanoFTPConnect(void *ctx) { snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1077,9 +1001,6 @@ xmlNanoFTPConnect(void *ctx) { snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1109,9 +1030,6 @@ xmlNanoFTPConnect(void *ctx) { ctxt->user, ctxt->hostname); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1131,9 +1049,6 @@ xmlNanoFTPConnect(void *ctx) { snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1282,9 +1197,6 @@ xmlNanoFTPCwd(void *ctx, const char *directory) { snprintf(buf, sizeof(buf), "CWD %s\r\n", directory); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1333,9 +1245,6 @@ xmlNanoFTPDele(void *ctx, const char *file) { snprintf(buf, sizeof(buf), "DELE %s\r\n", file); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1405,9 +1314,6 @@ xmlNanoFTPGetConnection(void *ctx) { #endif snprintf (buf, sizeof(buf), "PASV\r\n"); len = strlen (buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1505,9 +1411,6 @@ xmlNanoFTPGetConnection(void *ctx) { buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { @@ -1552,17 +1455,10 @@ xmlNanoFTPCloseConnection(void *ctx) { FD_SET(ctxt->controlFd, &efd); res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv); if (res < 0) { -#ifdef DEBUG_FTP - perror("select"); -#endif closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; return(-1); } if (res == 0) { -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoFTPCloseConnection: timeout\n"); -#endif closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; } else { res = xmlNanoFTPGetResponse(ctxt); @@ -1743,9 +1639,6 @@ xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, } buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1767,9 +1660,6 @@ xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, FD_SET(ctxt->dataFd, &efd); res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv); if (res < 0) { -#ifdef DEBUG_FTP - perror("select"); -#endif closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; return(-1); } @@ -1794,9 +1684,6 @@ xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, ctxt->dataFd = INVALID_SOCKET; return(-1); } -#ifdef DEBUG_FTP - write(1, &buf[indx], len); -#endif indx += len; buf[indx] = 0; base = 0; @@ -1838,9 +1725,6 @@ xmlNanoFTPGetSocket(void *ctx, const char *filename) { snprintf(buf, sizeof(buf), "TYPE I\r\n"); len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1858,9 +1742,6 @@ xmlNanoFTPGetSocket(void *ctx, const char *filename) { snprintf(buf, sizeof(buf), "RETR %s\r\n", filename); buf[sizeof(buf) - 1] = 0; len = strlen(buf); -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "%s", buf); -#endif res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); @@ -1912,9 +1793,6 @@ xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData, FD_SET(ctxt->dataFd, &rfd); res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv); if (res < 0) { -#ifdef DEBUG_FTP - perror("select"); -#endif closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; return(-1); } @@ -1971,9 +1849,6 @@ xmlNanoFTPRead(void *ctx, void *dest, int len) { __xmlIOErr(XML_FROM_FTP, 0, "recv failed"); xmlNanoFTPCloseConnection(ctxt); } -#ifdef DEBUG_FTP - xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len); -#endif return(len); } @@ -2048,7 +1923,7 @@ static void ftpList(void *userData, const char *filename, const char* attrib, const char *owner, const char *group, unsigned long size, int links, int year, const char *month, int day, int hour, int minute) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s %s %s %ld %s\n", attrib, owner, group, size, filename); } static @@ -2070,7 +1945,7 @@ int main(int argc, char **argv) { if (argc > 1) { ctxt = xmlNanoFTPNewCtxt(argv[1]); if (xmlNanoFTPConnect(ctxt) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Couldn't connect to %s\n", argv[1]); exit(1); } @@ -2079,7 +1954,7 @@ int main(int argc, char **argv) { } else ctxt = xmlNanoFTPConnectTo("localhost", 0); if (ctxt == NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Couldn't connect to localhost\n"); exit(1); } @@ -2087,12 +1962,11 @@ int main(int argc, char **argv) { output = fopen("/tmp/tstdata", "w"); if (output != NULL) { if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Failed to get file\n"); } xmlNanoFTPClose(ctxt); - xmlMemoryDump(); exit(0); } #endif /* STANDALONE */ @@ -2100,7 +1974,7 @@ int main(int argc, char **argv) { #ifdef STANDALONE #include int main(int argc, char **argv) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s : FTP support not compiled in\n", argv[0]); return(0); } diff --git a/nanohttp.c b/nanohttp.c index 2eafd3f4910..5c678930584 100644 --- a/nanohttp.c +++ b/nanohttp.c @@ -16,14 +16,14 @@ #ifdef LIBXML_HTTP_ENABLED #include +#include #include #include #ifdef HAVE_UNISTD_H #include -#endif -#ifdef HAVE_SYS_TYPES_H -#include +#elif defined (_WIN32) +#include #endif #ifdef HAVE_SYS_SOCKET_H #include @@ -37,12 +37,6 @@ #ifdef HAVE_NETDB_H #include #endif -#ifdef HAVE_RESOLV_H -#ifdef HAVE_ARPA_NAMESER_H -#include -#endif -#include -#endif #ifdef HAVE_FCNTL_H #include #endif @@ -70,37 +64,32 @@ #include #endif -#include #include #include #include /* for xmlStr(n)casecmp() */ #include -#include #include +#include "private/error.h" +#include "private/io.h" + /** * A couple portability macros */ #ifndef _WINSOCKAPI_ -#if !defined(__BEOS__) || defined(__HAIKU__) #define closesocket(s) close(s) -#endif #define SOCKET int #define INVALID_SOCKET (-1) #endif -#ifdef __BEOS__ -#ifndef PF_INET -#define PF_INET AF_INET -#endif -#endif - #ifndef XML_SOCKLEN_T #define XML_SOCKLEN_T unsigned int #endif +#define GETHOSTBYNAME_ARG_CAST (char *) +#define SEND_ARG2_CAST (char *) + #ifdef STANDALONE -#define DEBUG_HTTP #define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n) #define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b) #endif @@ -158,9 +147,9 @@ static int xmlNanoHTTPFetchContent( void * ctx, char ** ptr, int * len ); * Handle an out of memory condition */ static void -xmlHTTPErrMemory(const char *extra) +xmlHTTPErrMemory(void) { - __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_HTTP, NULL); } /** @@ -188,20 +177,6 @@ static int socket_errno(void) { #endif } -#ifdef SUPPORT_IP6 -static -int have_ipv6(void) { - SOCKET s; - - s = socket (AF_INET6, SOCK_STREAM, 0); - if (s != INVALID_SOCKET) { - close (s); - return (1); - } - return (0); -} -#endif - /** * xmlNanoHTTPInit: * @@ -350,14 +325,6 @@ xmlNanoHTTPScanProxy(const char *URL) { } proxyPort = 0; -#ifdef DEBUG_HTTP - if (URL == NULL) - xmlGenericError(xmlGenericErrorContext, - "Removing HTTP proxy info\n"); - else - xmlGenericError(xmlGenericErrorContext, - "Using HTTP proxy %s\n", URL); -#endif if (URL == NULL) return; uri = xmlParseURIRaw(URL, 1); @@ -391,7 +358,7 @@ xmlNanoHTTPNewCtxt(const char *URL) { ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt)); if (ret == NULL) { - xmlHTTPErrMemory("allocating context"); + xmlHTTPErrMemory(); return(NULL); } @@ -535,9 +502,9 @@ xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) while (ctxt->state & XML_NANO_HTTP_READ) { if (ctxt->in == NULL) { - ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char)); + ctxt->in = (char *) xmlMallocAtomic(65000); if (ctxt->in == NULL) { - xmlHTTPErrMemory("allocating input"); + xmlHTTPErrMemory(); ctxt->last = -1; return (-1); } @@ -562,7 +529,7 @@ xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) ctxt->inlen *= 2; ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen); if (ctxt->in == NULL) { - xmlHTTPErrMemory("allocating input buffer"); + xmlHTTPErrMemory(); xmlFree(tmp_ptr); ctxt->last = -1; return (-1); @@ -876,9 +843,6 @@ xmlNanoHTTPConnectAttempt(struct sockaddr *addr) addrlen = sizeof(struct sockaddr_in); } if (s == INVALID_SOCKET) { -#ifdef DEBUG_HTTP - perror("socket"); -#endif __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n"); return INVALID_SOCKET; } @@ -896,15 +860,6 @@ xmlNanoHTTPConnectAttempt(struct sockaddr *addr) status = ioctl(s, FIONBIO, &enable); } #else /* VMS */ -#if defined(__BEOS__) && !defined(__HAIKU__) - { - bool noblock = true; - - status = - setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock, - sizeof(noblock)); - } -#else /* __BEOS__ */ if ((status = fcntl(s, F_GETFL, 0)) != -1) { #ifdef O_NONBLOCK status |= O_NONBLOCK; @@ -916,14 +871,10 @@ xmlNanoHTTPConnectAttempt(struct sockaddr *addr) status = fcntl(s, F_SETFL, status); } if (status < 0) { -#ifdef DEBUG_HTTP - perror("nonblocking"); -#endif __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n"); closesocket(s); return INVALID_SOCKET; } -#endif /* !__BEOS__ */ #endif /* !VMS */ #endif /* !_WINSOCKAPI_ */ @@ -1042,33 +993,19 @@ xmlNanoHTTPConnectHost(const char *host, int port) struct sockaddr_in sockin; #ifdef SUPPORT_IP6 - struct in6_addr ia6; struct sockaddr_in6 sockin6; #endif SOCKET s; memset (&sockin, 0, sizeof(sockin)); -#ifdef SUPPORT_IP6 - memset (&sockin6, 0, sizeof(sockin6)); -#endif - -#if !defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && defined(RES_USE_INET6) - if (have_ipv6 ()) - { - if (!(_res.options & RES_INIT)) - res_init(); - _res.options |= RES_USE_INET6; - } -#endif -#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) - if (have_ipv6 ()) -#endif -#if defined(HAVE_GETADDRINFO) && (defined(SUPPORT_IP6) || defined(_WIN32)) +#if defined(SUPPORT_IP6) { int status; struct addrinfo hints, *res, *result; + memset (&sockin6, 0, sizeof(sockin6)); + result = NULL; memset (&hints, 0,sizeof(hints)); hints.ai_socktype = SOCK_STREAM; @@ -1089,8 +1026,7 @@ xmlNanoHTTPConnectHost(const char *host, int port) memcpy (&sockin, res->ai_addr, res->ai_addrlen); sockin.sin_port = htons (port); addr = (struct sockaddr *)&sockin; -#ifdef SUPPORT_IP6 - } else if (have_ipv6 () && (res->ai_family == AF_INET6)) { + } else if (res->ai_family == AF_INET6) { if ((size_t)res->ai_addrlen > sizeof(sockin6)) { __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); freeaddrinfo (result); @@ -1099,7 +1035,6 @@ xmlNanoHTTPConnectHost(const char *host, int port) memcpy (&sockin6, res->ai_addr, res->ai_addrlen); sockin6.sin6_port = htons (port); addr = (struct sockaddr *)&sockin6; -#endif } else continue; /* for */ @@ -1113,11 +1048,7 @@ xmlNanoHTTPConnectHost(const char *host, int port) if (result) freeaddrinfo (result); } -#endif -#if defined(HAVE_GETADDRINFO) && defined(SUPPORT_IP6) && !defined(_WIN32) - else -#endif -#if !defined(HAVE_GETADDRINFO) || !defined(_WIN32) +#else { struct hostent *h; struct in_addr ia; @@ -1179,19 +1110,6 @@ xmlNanoHTTPConnectHost(const char *host, int port) sockin.sin_addr = ia; sockin.sin_port = (unsigned short)htons ((unsigned short)port); addr = (struct sockaddr *) &sockin; -#ifdef SUPPORT_IP6 - } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) { - /* AAAA records (IPv6) */ - if ((unsigned int) h->h_length > sizeof(ia6)) { - __xmlIOErr(XML_FROM_HTTP, 0, "address size mismatch\n"); - return INVALID_SOCKET; - } - memcpy (&ia6, h->h_addr_list[i], h->h_length); - sockin6.sin6_family = h->h_addrtype; - sockin6.sin6_addr = ia6; - sockin6.sin6_port = htons (port); - addr = (struct sockaddr *) &sockin6; -#endif } else break; /* for */ @@ -1202,11 +1120,6 @@ xmlNanoHTTPConnectHost(const char *host, int port) } #endif -#ifdef DEBUG_HTTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoHTTPConnectHost: unable to connect to '%s'.\n", - host); -#endif return INVALID_SOCKET; } @@ -1306,8 +1219,10 @@ xmlNanoHTTPRead(void *ctx, void *dest, int len) { } if (ctxt->inptr - ctxt->inrptr < len) len = ctxt->inptr - ctxt->inrptr; - memcpy(dest, ctxt->inrptr, len); - ctxt->inrptr += len; + if (len > 0) { + memcpy(dest, ctxt->inrptr, len); + ctxt->inrptr += len; + } return(len); } @@ -1327,6 +1242,107 @@ xmlNanoHTTPClose(void *ctx) { xmlNanoHTTPFreeCtxt(ctxt); } + +/** + * xmlNanoHTTPHostnameMatch: + * @pattern: The pattern as it appears in no_proxy environment variable + * @hostname: The hostname to test as it appears in the URL + * + * This function tests whether a given hostname matches a pattern. The pattern + * usually is a token from the no_proxy environment variable. Wildcards in the + * pattern are not supported. + * + * Returns true, iff hostname matches the pattern. + */ + +static int +xmlNanoHTTPHostnameMatch(const char *pattern, const char *hostname) { + int idx_pattern, idx_hostname; + const char * pattern_start; + + if (!pattern || *pattern == '\0' || !hostname) + return 0; + + /* Ignore trailing '.' */ + if (*pattern == '.') { + idx_pattern = strlen(pattern) -1; + pattern_start = pattern + 1; + } + else { + idx_pattern = strlen(pattern); + pattern_start = pattern; + } + idx_hostname = strlen(hostname); + + for (; idx_pattern >= 0 && idx_hostname >= 0; + --idx_pattern, --idx_hostname) { + if (tolower(pattern_start[idx_pattern]) != tolower(hostname[idx_hostname])) + break; + } + + return idx_pattern == -1 && (idx_hostname == -1|| hostname[idx_hostname] == '.'); +} + + +/** + * xmlNanoHTTPBypassProxy: + * @hostname: The hostname as it appears in the URL + * + * This function evaluates the no_proxy environment variable and returns + * whether the proxy server should be bypassed for a given host. + * + * Returns true, iff a proxy server should be bypassed for the given hostname. + */ + +static int +xmlNanoHTTPBypassProxy(const char *hostname) { + size_t envlen; + char *env = getenv("no_proxy"), *cpy=NULL, *p=NULL; + if (!env) + return 0; + + /* (Avoid strdup because it's not portable.) */ + envlen = strlen(env) + 1; + cpy = xmlMalloc(envlen); + memcpy(cpy, env, envlen); + env = cpy; + + /* The remainder of the function is basically a tokenizing: */ + while (isspace(*env)) + ++env; + if (*env == '\0') { + xmlFree(cpy); + return 0; + } + + p = env; + while (*env) { + + if (*env != ',') { + ++env; + continue; + } + + *(env++) = '\0'; + if (xmlNanoHTTPHostnameMatch(p, hostname)) { + xmlFree(cpy); + return 1; + } + + while (isspace(*env)) + ++env; + p = env; + } + if (xmlNanoHTTPHostnameMatch(p, hostname)) { + xmlFree(cpy); + return 1; + } + + xmlFree(cpy); + return 0; +} + + /** * xmlNanoHTTPMethodRedir: * @URL: The URL to load @@ -1354,10 +1370,8 @@ xmlNanoHTTPMethodRedir(const char *URL, const char *method, const char *input, int blen; SOCKET ret; int nbRedirects = 0; + int use_proxy; char *redirURL = NULL; -#ifdef DEBUG_HTTP - int xmt_bytes; -#endif if (URL == NULL) return(NULL); if (method == NULL) method = "GET"; @@ -1376,7 +1390,7 @@ retry: } if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { - __xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI"); + __xmlIOErr(XML_FROM_IO, XML_IO_UNSUPPORTED_PROTOCOL, ctxt->protocol); xmlNanoHTTPFreeCtxt(ctxt); if (redirURL != NULL) xmlFree(redirURL); return(NULL); @@ -1388,7 +1402,8 @@ retry: if (redirURL != NULL) xmlFree(redirURL); return(NULL); } - if (proxy) { + use_proxy = proxy && !xmlNanoHTTPBypassProxy(ctxt->hostname); + if (use_proxy) { blen = strlen(ctxt->hostname) * 2 + 16; ret = xmlNanoHTTPConnectHost(proxy, proxyPort); } @@ -1423,7 +1438,7 @@ retry: #endif if (ctxt->port != 80) { /* reserve space for ':xxxxx', incl. potential proxy */ - if (proxy) + if (use_proxy) blen += 17; else blen += 11; @@ -1431,13 +1446,13 @@ retry: bp = (char*)xmlMallocAtomic(blen); if ( bp == NULL ) { xmlNanoHTTPFreeCtxt( ctxt ); - xmlHTTPErrMemory("allocating header buffer"); + xmlHTTPErrMemory(); return ( NULL ); } p = bp; - if (proxy) { + if (use_proxy) { if (ctxt->port != 80) { p += snprintf( p, blen - (p - bp), "%s http://%s:%d%s", method, ctxt->hostname, @@ -1476,41 +1491,13 @@ retry: else snprintf(p, blen - (p - bp), "\r\n"); -#ifdef DEBUG_HTTP - xmlGenericError(xmlGenericErrorContext, - "-> %s%s", proxy? "(Proxy) " : "", bp); - if ((blen -= strlen(bp)+1) < 0) - xmlGenericError(xmlGenericErrorContext, - "ERROR: overflowed buffer by %d bytes\n", -blen); -#endif ctxt->outptr = ctxt->out = bp; ctxt->state = XML_NANO_HTTP_WRITE; blen = strlen( ctxt->out ); -#ifdef DEBUG_HTTP - xmt_bytes = xmlNanoHTTPSend(ctxt, ctxt->out, blen ); - if ( xmt_bytes != blen ) - xmlGenericError( xmlGenericErrorContext, - "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", - xmt_bytes, blen, - "bytes of HTTP headers sent to host", - ctxt->hostname ); -#else xmlNanoHTTPSend(ctxt, ctxt->out, blen ); -#endif if ( input != NULL ) { -#ifdef DEBUG_HTTP - xmt_bytes = xmlNanoHTTPSend( ctxt, input, ilen ); - - if ( xmt_bytes != ilen ) - xmlGenericError( xmlGenericErrorContext, - "xmlNanoHTTPMethodRedir: Only %d of %d %s %s\n", - xmt_bytes, ilen, - "bytes of HTTP content sent to host", - ctxt->hostname ); -#else xmlNanoHTTPSend( ctxt, input, ilen ); -#endif } ctxt->state = XML_NANO_HTTP_READ; @@ -1523,18 +1510,11 @@ retry: } xmlNanoHTTPScanAnswer(ctxt, p); -#ifdef DEBUG_HTTP - xmlGenericError(xmlGenericErrorContext, "<- %s\n", p); -#endif xmlFree(p); } if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && (ctxt->returnValue < 400)) { -#ifdef DEBUG_HTTP - xmlGenericError(xmlGenericErrorContext, - "\nRedirect to: %s\n", ctxt->location); -#endif while ( xmlNanoHTTPRecv(ctxt) > 0 ) ; if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { @@ -1547,10 +1527,6 @@ retry: } xmlNanoHTTPFreeCtxt(ctxt); if (redirURL != NULL) xmlFree(redirURL); -#ifdef DEBUG_HTTP - xmlGenericError(xmlGenericErrorContext, - "xmlNanoHTTPMethodRedir: Too many redirects, aborting ...\n"); -#endif return(NULL); } @@ -1570,17 +1546,6 @@ retry: *redir = NULL; } -#ifdef DEBUG_HTTP - if (ctxt->contentType != NULL) - xmlGenericError(xmlGenericErrorContext, - "\nCode %d, content-type '%s'\n\n", - ctxt->returnValue, ctxt->contentType); - else - xmlGenericError(xmlGenericErrorContext, - "\nCode %d, no content-type\n\n", - ctxt->returnValue); -#endif - return((void *) ctxt); } @@ -1868,13 +1833,12 @@ int main(int argc, char **argv) { xmlNanoHTTPFetch(argv[1], "-", &contentType); if (contentType != NULL) xmlFree(contentType); } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s: minimal HTTP GET implementation\n", argv[0]); - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "\tusage %s [ URL [ filename ] ]\n", argv[0]); } xmlNanoHTTPCleanup(); - xmlMemoryDump(); return(0); } #endif /* STANDALONE */ @@ -1882,7 +1846,7 @@ int main(int argc, char **argv) { #ifdef STANDALONE #include int main(int argc, char **argv) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s : HTTP support not compiled in\n", argv[0]); return(0); } diff --git a/parser.c b/parser.c index 93f031be863..365025c5eb9 100644 --- a/parser.c +++ b/parser.c @@ -51,11 +51,9 @@ #include #include #include +#include #include -#include -#include #include -#include #include #include #include @@ -63,16 +61,27 @@ #include #include #include +#include #ifdef LIBXML_CATALOG_ENABLED #include #endif -#ifdef LIBXML_SCHEMAS_ENABLED -#include -#include -#endif -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/dict.h" +#include "private/entities.h" +#include "private/error.h" +#include "private/html.h" +#include "private/io.h" +#include "private/parser.h" + +#define NS_INDEX_EMPTY INT_MAX +#define NS_INDEX_XML (INT_MAX - 1) +#define URI_HASH_EMPTY 0xD943A04E +#define URI_HASH_XML 0xF0451F02 + +#ifndef STDIN_FILENO + #define STDIN_FILENO 0 +#endif struct _xmlStartTag { const xmlChar *prefix; @@ -81,14 +90,34 @@ struct _xmlStartTag { int nsNr; }; -static void -xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); - -static xmlParserCtxtPtr -xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, - const xmlChar *base, xmlParserCtxtPtr pctx); +typedef struct { + void *saxData; + unsigned prefixHashValue; + unsigned uriHashValue; + unsigned elementId; + int oldIndex; +} xmlParserNsExtra; + +typedef struct { + unsigned hashValue; + int index; +} xmlParserNsBucket; + +struct _xmlParserNsData { + xmlParserNsExtra *extra; + + unsigned hashSize; + unsigned hashElems; + xmlParserNsBucket *hash; + + unsigned elementId; + int defaultNsIndex; + int minNsIndex; +}; -static void xmlHaltParser(xmlParserCtxtPtr ctxt); +struct _xmlAttrHashBucket { + int index; +}; static int xmlParseElementStart(xmlParserCtxtPtr ctxt); @@ -96,6 +125,12 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt); static void xmlParseElementEnd(xmlParserCtxtPtr ctxt); +static xmlEntityPtr +xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr); + +static const xmlChar * +xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt); + /************************************************************************ * * * Arbitrary limits set in the parser. See XML_PARSE_HUGE * @@ -106,156 +141,21 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt); #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 exponential behaviour. A value of 10 correspond to at least 3 entity - * replacement per byte of input. + * Constants for protection against abusive entity expansion + * ("billion laughs"). */ -#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. + * A certain amount of entity expansion which is always allowed. */ -static int -xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, - xmlEntityPtr ent, size_t replacement) -{ - size_t consumed = 0; - int i; - - if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE)) - return (0); - if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) - return (1); - - /* - * This may look absurd but is needed to detect - * entities problems - */ - if ((ent != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && - (ent->content != NULL) && (ent->checked == 0) && - (ctxt->errNo != XML_ERR_ENTITY_LOOP)) { - unsigned long oldnbent = ctxt->nbentities, diff; - xmlChar *rep; - - ent->checked = 1; - - ++ctxt->depth; - rep = xmlStringDecodeEntities(ctxt, ent->content, - XML_SUBSTITUTE_REF, 0, 0, 0); - --ctxt->depth; - if ((rep == NULL) || (ctxt->errNo == XML_ERR_ENTITY_LOOP)) { - ent->content[0] = 0; - } - - diff = ctxt->nbentities - oldnbent + 1; - if (diff > INT_MAX / 2) - diff = INT_MAX / 2; - ent->checked = diff * 2; - if (rep != NULL) { - if (xmlStrchr(rep, '<')) - ent->checked |= 1; - xmlFree(rep); - rep = NULL; - } - } - - /* - * Prevent entity exponential check, not just replacement while - * parsing the DTD - * The check is potentially costly so do that only once in a thousand - */ - if ((ctxt->instate == XML_PARSER_DTD) && (ctxt->nbentities > 10000) && - (ctxt->nbentities % 1024 == 0)) { - for (i = 0;i < ctxt->inputNr;i++) { - consumed += ctxt->inputTab[i]->consumed + - (ctxt->inputTab[i]->cur - ctxt->inputTab[i]->base); - } - if (ctxt->nbentities > consumed * XML_PARSER_NON_LINEAR) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - ctxt->instate = XML_PARSER_EOF; - return (1); - } - consumed = 0; - } - - - - if (replacement != 0) { - if (replacement < XML_MAX_TEXT_LENGTH) - return(0); - - /* - * If the volume of entity copy reaches 10 times the - * amount of parsed data and over the large text threshold - * then that's very likely to be an abuse. - */ - if (ctxt->input != NULL) { - consumed = ctxt->input->consumed + - (ctxt->input->cur - ctxt->input->base); - } - consumed += ctxt->sizeentities; - - if (replacement < XML_PARSER_NON_LINEAR * consumed) - return(0); - } else 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 / 2; +#define XML_PARSER_ALLOWED_EXPANSION 1000000 - /* - * 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 - */ - if (((ctxt->lastError.code != XML_ERR_UNDECLARED_ENTITY) && - (ctxt->lastError.code != XML_WAR_UNDECLARED_ENTITY)) || - (ctxt->nbentities <= 10000)) - return (0); - } - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - return (1); -} +/* + * Fixed cost for each entity reference. This crudely models processing time + * as well to protect, for example, against exponential expansion of empty + * or very short entities. + */ +#define XML_ENT_FIXED_COST 20 /** * xmlParserMaxDepth: @@ -265,11 +165,10 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, * boundary feature. It can be disabled with the XML_PARSE_HUGE * parser option. */ -unsigned int xmlParserMaxDepth = 256; +const 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" @@ -285,6 +184,14 @@ unsigned int xmlParserMaxDepth = 256; */ #define XML_PARSER_CHUNK_SIZE 100 +/** + * xmlParserVersion: + * + * Constant string describing the internal version of the library + */ +const char *const +xmlParserVersion = LIBXML_VERSION_STRING LIBXML_VERSION_EXTRA; + /* * List of XML prefixed PI allowed by W3C specs */ @@ -300,24 +207,8 @@ static const char* const xmlW3CPIs[] = { static xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str); -static xmlParserErrors -xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, - xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *URL, - const xmlChar *ID, xmlNodePtr *list); - -static int -xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, - 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); +xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent); static int xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); @@ -328,6 +219,11 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); * * ************************************************************************/ +static void +xmlErrMemory(xmlParserCtxtPtr ctxt) { + xmlCtxtErrMemory(ctxt); +} + /** * xmlErrAttributeDup: * @ctxt: an XML parser context @@ -340,244 +236,14 @@ static void xmlErrAttributeDup(xmlParserCtxtPtr ctxt, const xmlChar * prefix, const xmlChar * localname) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED; - if (prefix == NULL) - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0, - (const char *) localname, NULL, NULL, 0, 0, - "Attribute %s redefined\n", localname); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, + XML_ERR_FATAL, localname, NULL, NULL, 0, + "Attribute %s redefined\n", localname); else - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0, - (const char *) prefix, (const char *) localname, - NULL, 0, 0, "Attribute %s:%s redefined\n", prefix, - localname); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } -} - -/** - * 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"; - break; - case XML_ERR_INVALID_DEC_CHARREF: - errmsg = "CharRef: invalid decimal value"; - break; - case XML_ERR_INVALID_CHARREF: - errmsg = "CharRef: invalid value"; - break; - case XML_ERR_INTERNAL_ERROR: - errmsg = "internal error"; - break; - case XML_ERR_PEREF_AT_EOF: - errmsg = "PEReference at end of document"; - break; - case XML_ERR_PEREF_IN_PROLOG: - errmsg = "PEReference in prolog"; - break; - case XML_ERR_PEREF_IN_EPILOG: - errmsg = "PEReference in epilog"; - break; - case XML_ERR_PEREF_NO_NAME: - errmsg = "PEReference: no name"; - break; - case XML_ERR_PEREF_SEMICOL_MISSING: - errmsg = "PEReference: expecting ';'"; - break; - case XML_ERR_ENTITY_LOOP: - errmsg = "Detected an entity reference loop"; - break; - case XML_ERR_ENTITY_NOT_STARTED: - errmsg = "EntityValue: \" or ' expected"; - break; - case XML_ERR_ENTITY_PE_INTERNAL: - errmsg = "PEReferences forbidden in internal subset"; - break; - case XML_ERR_ENTITY_NOT_FINISHED: - errmsg = "EntityValue: \" or ' expected"; - break; - case XML_ERR_ATTRIBUTE_NOT_STARTED: - errmsg = "AttValue: \" or ' expected"; - break; - case XML_ERR_LT_IN_ATTRIBUTE: - errmsg = "Unescaped '<' not allowed in attributes values"; - break; - case XML_ERR_LITERAL_NOT_STARTED: - errmsg = "SystemLiteral \" or ' expected"; - break; - case XML_ERR_LITERAL_NOT_FINISHED: - errmsg = "Unfinished System or Public ID \" or ' expected"; - break; - case XML_ERR_MISPLACED_CDATA_END: - errmsg = "Sequence ']]>' not allowed in content"; - break; - case XML_ERR_URI_REQUIRED: - errmsg = "SYSTEM or PUBLIC, the URI is missing"; - break; - case XML_ERR_PUBID_REQUIRED: - errmsg = "PUBLIC, the Public Identifier is missing"; - break; - case XML_ERR_HYPHEN_IN_COMMENT: - errmsg = "Comment must not contain '--' (double-hyphen)"; - break; - case XML_ERR_PI_NOT_STARTED: - errmsg = "xmlParsePI : no target name"; - break; - case XML_ERR_RESERVED_XML_NAME: - errmsg = "Invalid PI name"; - break; - case XML_ERR_NOTATION_NOT_STARTED: - errmsg = "NOTATION: Name expected here"; - break; - case XML_ERR_NOTATION_NOT_FINISHED: - errmsg = "'>' required to close NOTATION declaration"; - break; - case XML_ERR_VALUE_REQUIRED: - errmsg = "Entity value required"; - break; - case XML_ERR_URI_FRAGMENT: - errmsg = "Fragment not allowed"; - break; - case XML_ERR_ATTLIST_NOT_STARTED: - errmsg = "'(' required to start ATTLIST enumeration"; - break; - case XML_ERR_NMTOKEN_REQUIRED: - errmsg = "NmToken expected in ATTLIST enumeration"; - break; - case XML_ERR_ATTLIST_NOT_FINISHED: - errmsg = "')' required to finish ATTLIST enumeration"; - break; - case XML_ERR_MIXED_NOT_STARTED: - errmsg = "MixedContentDecl : '|' or ')*' expected"; - break; - case XML_ERR_PCDATA_REQUIRED: - errmsg = "MixedContentDecl : '#PCDATA' expected"; - break; - case XML_ERR_ELEMCONTENT_NOT_STARTED: - errmsg = "ContentDecl : Name or '(' expected"; - break; - case XML_ERR_ELEMCONTENT_NOT_FINISHED: - errmsg = "ContentDecl : ',' '|' or ')' expected"; - break; - case XML_ERR_PEREF_IN_INT_SUBSET: - errmsg = - "PEReference: forbidden within markup decl in internal subset"; - break; - case XML_ERR_GT_REQUIRED: - errmsg = "expected '>'"; - break; - case XML_ERR_CONDSEC_INVALID: - errmsg = "XML conditional section '[' expected"; - break; - case XML_ERR_EXT_SUBSET_NOT_FINISHED: - errmsg = "Content error in the external subset"; - break; - case XML_ERR_CONDSEC_INVALID_KEYWORD: - errmsg = - "conditional section INCLUDE or IGNORE keyword expected"; - break; - case XML_ERR_CONDSEC_NOT_FINISHED: - errmsg = "XML conditional section not closed"; - break; - case XML_ERR_XMLDECL_NOT_STARTED: - errmsg = "Text declaration '' expected"; - break; - case XML_ERR_EXT_ENTITY_STANDALONE: - errmsg = "external parsed entities cannot be standalone"; - break; - case XML_ERR_ENTITYREF_SEMICOL_MISSING: - errmsg = "EntityRef: expecting ';'"; - break; - case XML_ERR_DOCTYPE_NOT_FINISHED: - errmsg = "DOCTYPE improperly terminated"; - break; - case XML_ERR_LTSLASH_REQUIRED: - errmsg = "EndTag: 'errNo = error; - if (info == NULL) { - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, "%s\n", - errmsg); - } else { - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, "%s: %s\n", - errmsg, info); - } - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, + XML_ERR_FATAL, prefix, localname, NULL, 0, + "Attribute %s:%s redefined\n", prefix, localname); } /** @@ -592,18 +258,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, NULL, NULL, 0, "%s", msg); } /** @@ -616,33 +272,12 @@ xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, * * Handle a warning. */ -static void LIBXML_ATTR_FORMAT(3,0) +void LIBXML_ATTR_FORMAT(3,0) xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - xmlStructuredErrorFunc schannel = NULL; - - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if ((ctxt != NULL) && (ctxt->sax != NULL) && - (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - if (ctxt != NULL) { - __xmlRaiseError(schannel, - (ctxt->sax) ? ctxt->sax->warning : NULL, - ctxt->userData, - ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } else { - __xmlRaiseError(schannel, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -658,31 +293,10 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlValidityError(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - xmlStructuredErrorFunc schannel = NULL; + ctxt->valid = 0; - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = error; - if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - } - if (ctxt != NULL) { - __xmlRaiseError(schannel, - ctxt->vctxt.error, ctxt->vctxt.userData, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - ctxt->valid = 0; - } else { - __xmlRaiseError(schannel, NULL, NULL, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } + xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -698,19 +312,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, int val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, - NULL, 0, NULL, NULL, NULL, val, 0, msg, val); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, NULL, NULL, val, msg, val); } /** @@ -729,20 +332,8 @@ xmlFatalErrMsgStrIntStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, int val, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, - NULL, 0, (const char *) str1, (const char *) str2, - NULL, val, 0, msg, str1, val, str2); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + str1, str2, NULL, val, msg, str1, val, str2); } /** @@ -758,20 +349,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, - XML_FROM_PARSER, error, XML_ERR_FATAL, - NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, - val); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + val, NULL, NULL, 0, msg, val); } /** @@ -787,15 +366,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, - XML_FROM_PARSER, error, XML_ERR_ERROR, - NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, - val); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR, + val, NULL, NULL, 0, msg, val); } /** @@ -814,17 +386,10 @@ xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_ERROR, NULL, 0, (const char *) info1, - (const char *) info2, (const char *) info3, 0, 0, msg, - info1, info2, info3); - if (ctxt != NULL) - ctxt->nsWellFormed = 0; + ctxt->nsWellFormed = 0; + + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR, + info1, info2, info3, 0, msg, info1, info2, info3); } /** @@ -843,13 +408,96 @@ xmlNsWarn(xmlParserCtxtPtr ctxt, xmlParserErrors error, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_WARNING, NULL, 0, (const char *) info1, - (const char *) info2, (const char *) info3, 0, 0, msg, - info1, info2, info3); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING, + info1, info2, info3, 0, msg, info1, info2, info3); +} + +static void +xmlSaturatedAdd(unsigned long *dst, unsigned long val) { + if (val > ULONG_MAX - *dst) + *dst = ULONG_MAX; + else + *dst += val; +} + +static void +xmlSaturatedAddSizeT(unsigned long *dst, unsigned long val) { + if (val > ULONG_MAX - *dst) + *dst = ULONG_MAX; + else + *dst += val; +} + +/** + * xmlParserEntityCheck: + * @ctxt: parser context + * @extra: sum of unexpanded entity sizes + * + * Check for non-linear entity expansion behaviour. + * + * In some cases like xmlExpandEntityInAttValue, this function is called + * for each, possibly nested entity and its unexpanded content length. + * + * In other cases like xmlParseReference, it's only called for each + * top-level entity with its unexpanded content length plus the sum of + * the unexpanded content lengths (plus fixed cost) of all nested + * entities. + * + * Summing the unexpanded lengths also adds the length of the reference. + * This is by design. Taking the length of the entity name into account + * discourages attacks that try to waste CPU time with abusively long + * entity names. See test/recurse/lol6.xml for example. Each call also + * adds some fixed cost XML_ENT_FIXED_COST to discourage attacks with + * short entities. + * + * Returns 1 on error, 0 on success. + */ +static int +xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long extra) +{ + unsigned long consumed; + unsigned long *expandedSize; + xmlParserInputPtr input = ctxt->input; + xmlEntityPtr entity = input->entity; + + if ((entity) && (entity->flags & XML_ENT_CHECKED)) + return(0); + + /* + * Compute total consumed bytes so far, including input streams of + * external entities. + */ + consumed = input->consumed; + xmlSaturatedAddSizeT(&consumed, input->cur - input->base); + xmlSaturatedAdd(&consumed, ctxt->sizeentities); + + if (entity) + expandedSize = &entity->expandedSize; + else + expandedSize = &ctxt->sizeentcopy; + + /* + * Add extra cost and some fixed cost. + */ + xmlSaturatedAdd(expandedSize, extra); + xmlSaturatedAdd(expandedSize, XML_ENT_FIXED_COST); + + /* + * It's important to always use saturation arithmetic when tracking + * entity sizes to make the size checks reliable. If "sizeentcopy" + * overflows, we have to abort. + */ + if ((*expandedSize > XML_PARSER_ALLOWED_EXPANSION) && + ((*expandedSize >= ULONG_MAX) || + (*expandedSize / ctxt->maxAmpl > consumed))) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity amplification factor exceeded, see " + "xmlCtxtSetMaxAmplification.\n"); + xmlHaltParser(ctxt); + return(1); + } + + return(0); } /************************************************************************ @@ -1041,17 +689,7 @@ xmlHasFeature(xmlFeature feature) return(0); #endif case XML_WITH_DEBUG_MEM: -#ifdef DEBUG_MEMORY_LOCATION - return(1); -#else - return(0); -#endif - case XML_WITH_DEBUG_RUN: -#ifdef LIBXML_DEBUG_RUNTIME - return(1); -#else return(0); -#endif case XML_WITH_ZLIB: #ifdef LIBXML_ZLIB_ENABLED return(1); @@ -1078,43 +716,283 @@ xmlHasFeature(xmlFeature feature) /************************************************************************ * * - * SAX2 defaulted attributes handling * + * Simple string buffer * * * ************************************************************************/ -/** - * xmlDetectSAX2: - * @ctxt: an XML parser context - * - * Do the SAX2 detection and specific initialization - */ +typedef struct { + xmlChar *mem; + unsigned size; + unsigned cap; /* size < cap */ + unsigned max; /* size <= max */ + xmlParserErrors code; +} xmlSBuf; + static void -xmlDetectSAX2(xmlParserCtxtPtr ctxt) { - xmlSAXHandlerPtr sax; +xmlSBufInit(xmlSBuf *buf, unsigned max) { + buf->mem = NULL; + buf->size = 0; + buf->cap = 0; + buf->max = max; + buf->code = XML_ERR_OK; +} - /* Avoid unused variable warning if features are disabled. */ - (void) sax; +static int +xmlSBufGrow(xmlSBuf *buf, unsigned len) { + xmlChar *mem; + unsigned cap; - if (ctxt == NULL) return; - sax = ctxt->sax; -#ifdef LIBXML_SAX1_ENABLED - if ((sax) && (sax->initialized == XML_SAX2_MAGIC) && - ((sax->startElementNs != NULL) || - (sax->endElementNs != NULL) || - ((sax->startElement == NULL) && (sax->endElement == NULL)))) - ctxt->sax2 = 1; -#else - ctxt->sax2 = 1; -#endif /* LIBXML_SAX1_ENABLED */ + if (len >= UINT_MAX / 2 - buf->size) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return(-1); + } - 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); + cap = (buf->size + len) * 2; + if (cap < 240) + cap = 240; + + mem = xmlRealloc(buf->mem, cap); + if (mem == NULL) { + buf->code = XML_ERR_NO_MEMORY; + return(-1); } -} + + buf->mem = mem; + buf->cap = cap; + + return(0); +} + +static void +xmlSBufAddString(xmlSBuf *buf, const xmlChar *str, unsigned len) { + if (buf->max - buf->size < len) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return; + } + + if (buf->cap - buf->size <= len) { + if (xmlSBufGrow(buf, len) < 0) + return; + } + + if (len > 0) + memcpy(buf->mem + buf->size, str, len); + buf->size += len; +} + +static void +xmlSBufAddCString(xmlSBuf *buf, const char *str, unsigned len) { + xmlSBufAddString(buf, (const xmlChar *) str, len); +} + +static void +xmlSBufAddChar(xmlSBuf *buf, int c) { + xmlChar *end; + + if (buf->max - buf->size < 4) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return; + } + + if (buf->cap - buf->size <= 4) { + if (xmlSBufGrow(buf, 4) < 0) + return; + } + + end = buf->mem + buf->size; + + if (c < 0x80) { + *end = (xmlChar) c; + buf->size += 1; + } else { + buf->size += xmlCopyCharMultiByte(end, c); + } +} + +static void +xmlSBufAddReplChar(xmlSBuf *buf) { + xmlSBufAddCString(buf, "\xEF\xBF\xBD", 3); +} + +static void +xmlSBufReportError(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) { + if (buf->code == XML_ERR_NO_MEMORY) + xmlCtxtErrMemory(ctxt); + else + xmlFatalErr(ctxt, buf->code, errMsg); +} + +static xmlChar * +xmlSBufFinish(xmlSBuf *buf, int *sizeOut, xmlParserCtxtPtr ctxt, + const char *errMsg) { + if (buf->mem == NULL) { + buf->mem = xmlMalloc(1); + if (buf->mem == NULL) { + buf->code = XML_ERR_NO_MEMORY; + } else { + buf->mem[0] = 0; + } + } else { + buf->mem[buf->size] = 0; + } + + if (buf->code == XML_ERR_OK) { + if (sizeOut != NULL) + *sizeOut = buf->size; + return(buf->mem); + } + + xmlSBufReportError(buf, ctxt, errMsg); + + xmlFree(buf->mem); + + if (sizeOut != NULL) + *sizeOut = 0; + return(NULL); +} + +static void +xmlSBufCleanup(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) { + if (buf->code != XML_ERR_OK) + xmlSBufReportError(buf, ctxt, errMsg); + + xmlFree(buf->mem); +} + +static int +xmlUTF8MultibyteLen(xmlParserCtxtPtr ctxt, const xmlChar *str, + const char *errMsg) { + int c = str[0]; + int c1 = str[1]; + + if ((c1 & 0xC0) != 0x80) + goto encoding_error; + + if (c < 0xE0) { + /* 2-byte sequence */ + if (c < 0xC2) + goto encoding_error; + + return(2); + } else { + int c2 = str[2]; + + if ((c2 & 0xC0) != 0x80) + goto encoding_error; + + if (c < 0xF0) { + /* 3-byte sequence */ + if (c == 0xE0) { + /* overlong */ + if (c1 < 0xA0) + goto encoding_error; + } else if (c == 0xED) { + /* surrogate */ + if (c1 >= 0xA0) + goto encoding_error; + } else if (c == 0xEF) { + /* U+FFFE and U+FFFF are invalid Chars */ + if ((c1 == 0xBF) && (c2 >= 0xBE)) + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, errMsg); + } + + return(3); + } else { + /* 4-byte sequence */ + if ((str[3] & 0xC0) != 0x80) + goto encoding_error; + if (c == 0xF0) { + /* overlong */ + if (c1 < 0x90) + goto encoding_error; + } else if (c >= 0xF4) { + /* greater than 0x10FFFF */ + if ((c > 0xF4) || (c1 >= 0x90)) + goto encoding_error; + } + + return(4); + } + } + +encoding_error: + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; + } + + return(0); +} + +/************************************************************************ + * * + * SAX2 defaulted attributes handling * + * * + ************************************************************************/ + +/** + * xmlCtxtInitializeLate: + * @ctxt: an XML parser context + * + * Final initialization of the parser context before starting to parse. + * + * This accounts for users modifying struct members of parser context + * directly. + */ +static void +xmlCtxtInitializeLate(xmlParserCtxtPtr ctxt) { + xmlSAXHandlerPtr sax; + + /* Avoid unused variable warning if features are disabled. */ + (void) sax; + + /* + * Changing the SAX struct directly is still widespread practice + * in internal and external code. + */ + if (ctxt == NULL) return; + sax = ctxt->sax; +#ifdef LIBXML_SAX1_ENABLED + /* + * Only enable SAX2 if there SAX2 element handlers, except when there + * are no element handlers at all. + */ + if (((ctxt->options & XML_PARSE_SAX1) == 0) && + (sax) && + (sax->initialized == XML_SAX2_MAGIC) && + ((sax->startElementNs != NULL) || + (sax->endElementNs != NULL) || + ((sax->startElement == NULL) && (sax->endElement == NULL)))) + ctxt->sax2 = 1; +#else + ctxt->sax2 = 1; +#endif /* LIBXML_SAX1_ENABLED */ + + /* + * Some users replace the dictionary directly in the context struct. + * We really need an API function to do that cleanly. + */ + ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); + ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); + if ((ctxt->str_xml==NULL) || (ctxt->str_xmlns==NULL) || + (ctxt->str_xml_ns == NULL)) { + xmlErrMemory(ctxt); + } +} + +typedef struct { + xmlHashedString prefix; + xmlHashedString name; + xmlHashedString value; + const xmlChar *valueEnd; + int external; + int expandedSize; +} xmlDefAttr; typedef struct _xmlDefAttrs xmlDefAttrs; typedef xmlDefAttrs *xmlDefAttrsPtr; @@ -1123,9 +1001,9 @@ struct _xmlDefAttrs { int maxAttrs; /* the size of the array */ #if __STDC_VERSION__ >= 199901L /* Using a C99 flexible array member avoids UBSan errors. */ - const xmlChar *values[]; /* array of localname/prefix/values/external */ + xmlDefAttr attrs[]; /* array of localname/prefix/values/external */ #else - const xmlChar *values[5]; + xmlDefAttr attrs[1]; #endif }; @@ -1168,65 +1046,6 @@ xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst) return(dst); } -/** - * xmlAttrNormalizeSpace2: - * @src: the source string - * - * Normalize the space in non CDATA attribute values, a slightly more complex - * front end to avoid allocation problems when running on attribute values - * coming from the input. - * - * Returns a pointer to the normalized value (dst) or NULL if no conversion - * is needed. - */ -static const xmlChar * -xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, xmlChar *src, int *len) -{ - int i; - int remove_head = 0; - int need_realloc = 0; - const xmlChar *cur; - - if ((ctxt == NULL) || (src == NULL) || (len == NULL)) - return(NULL); - i = *len; - if (i <= 0) - return(NULL); - - cur = src; - while (*cur == 0x20) { - cur++; - remove_head++; - } - while (*cur != 0) { - if (*cur == 0x20) { - cur++; - if ((*cur == 0x20) || (*cur == 0)) { - need_realloc = 1; - break; - } - } else - cur++; - } - if (need_realloc) { - xmlChar *ret; - - ret = xmlStrndup(src + remove_head, i - remove_head + 1); - if (ret == NULL) { - xmlErrMemory(ctxt, NULL); - return(NULL); - } - xmlAttrNormalizeSpace(ret, ret); - *len = (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 @@ -1242,9 +1061,12 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt, const xmlChar *fullattr, const xmlChar *value) { xmlDefAttrsPtr defaults; - int len; - const xmlChar *name; - const xmlChar *prefix; + xmlDefAttr *attr; + int len, expandedSize; + xmlHashedString name; + xmlHashedString prefix; + xmlHashedString hvalue; + const xmlChar *localname; /* * Allows to detect attribute redefinitions @@ -1264,41 +1086,38 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt, * 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; + localname = xmlSplitQName3(fullname, &len); + if (localname == NULL) { + name = xmlDictLookupHashed(ctxt->dict, fullname, -1); + prefix.name = NULL; } else { - name = xmlDictLookup(ctxt->dict, name, -1); - prefix = xmlDictLookup(ctxt->dict, fullname, len); + name = xmlDictLookupHashed(ctxt->dict, localname, -1); + prefix = xmlDictLookupHashed(ctxt->dict, fullname, len); + if (prefix.name == NULL) + goto mem_error; } + if (name.name == NULL) + goto mem_error; /* * 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) { + defaults = xmlHashLookup2(ctxt->attsDefault, name.name, prefix.name); + if ((defaults == NULL) || + (defaults->nbAttrs >= defaults->maxAttrs)) { xmlDefAttrsPtr temp; + int newSize; - temp = (xmlDefAttrsPtr) xmlRealloc(defaults, sizeof(xmlDefAttrs) + - (2 * defaults->maxAttrs * 5) * sizeof(const xmlChar *)); + newSize = (defaults != NULL) ? 2 * defaults->maxAttrs : 4; + temp = xmlRealloc(defaults, + sizeof(*defaults) + newSize * sizeof(xmlDefAttr)); if (temp == NULL) goto mem_error; - defaults = temp; - defaults->maxAttrs *= 2; - if (xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, + if (defaults == NULL) + temp->nbAttrs = 0; + temp->maxAttrs = newSize; + defaults = temp; + if (xmlHashUpdateEntry2(ctxt->attsDefault, name.name, prefix.name, defaults, NULL) < 0) { xmlFree(defaults); goto mem_error; @@ -1306,35 +1125,45 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt, } /* - * Split the element name into prefix:localname , the string found + * Split the attribute 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; + localname = xmlSplitQName3(fullattr, &len); + if (localname == NULL) { + name = xmlDictLookupHashed(ctxt->dict, fullattr, -1); + prefix.name = NULL; } else { - name = xmlDictLookup(ctxt->dict, name, -1); - prefix = xmlDictLookup(ctxt->dict, fullattr, len); + name = xmlDictLookupHashed(ctxt->dict, localname, -1); + prefix = xmlDictLookupHashed(ctxt->dict, fullattr, len); + if (prefix.name == NULL) + goto mem_error; } + if (name.name == NULL) + goto mem_error; - 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++; + len = strlen((const char *) value); + hvalue = xmlDictLookupHashed(ctxt->dict, value, len); + if (hvalue.name == NULL) + goto mem_error; + + expandedSize = strlen((const char *) name.name); + if (prefix.name != NULL) + expandedSize += strlen((const char *) prefix.name); + expandedSize += len; + + attr = &defaults->attrs[defaults->nbAttrs++]; + attr->name = name; + attr->prefix = prefix; + attr->value = hvalue; + attr->valueEnd = hvalue.name + len; + attr->external = PARSER_EXTERNAL(ctxt); + attr->expandedSize = expandedSize; return; mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } @@ -1359,15 +1188,13 @@ xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, goto mem_error; } - if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) - return; - - xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, - (void *) (ptrdiff_t) type); + if (xmlHashAdd2(ctxt->attsSpecial, fullname, fullattr, + (void *) (ptrdiff_t) type) < 0) + goto mem_error; return; mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } @@ -1414,6 +1241,8 @@ xmlCleanSpecialAttr(xmlParserCtxtPtr ctxt) * xmlCheckLanguageID: * @lang: pointer to the string value * + * DEPRECATED: Internal function, do not use. + * * Checks that the value conforms to the LanguageID production: * * NOTE: this is somewhat deprecated, those productions were removed from @@ -1610,168 +1439,556 @@ region_m49: * * ************************************************************************/ -static xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, - const xmlChar ** str); +static xmlChar * +xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar **str); -#ifdef SAX2 /** - * nsPush: - * @ctxt: an XML parser context - * @prefix: the namespace prefix or NULL - * @URL: the namespace name + * xmlParserNsCreate: * - * Pushes a new parser namespace on top of the ns stack + * Create a new namespace database. * - * Returns -1 in case of error, -2 if the namespace should be discarded - * and the index in the stack otherwise. + * Returns the new obejct. */ -static int -nsPush(xmlParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *URL) -{ - if (ctxt->options & XML_PARSE_NSCLEAN) { - int i; - for (i = ctxt->nsNr - 2;i >= 0;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); +xmlParserNsData * +xmlParserNsCreate(void) { + xmlParserNsData *nsdb = xmlMalloc(sizeof(*nsdb)); + + if (nsdb == NULL) + return(NULL); + memset(nsdb, 0, sizeof(*nsdb)); + nsdb->defaultNsIndex = INT_MAX; + + return(nsdb); } + /** - * nsPop: - * @ctxt: an XML parser context - * @nr: the number to pop + * xmlParserNsFree: + * @nsdb: namespace database * - * Pops the top @nr parser prefix/namespace from the ns stack + * Free a namespace database. + */ +void +xmlParserNsFree(xmlParserNsData *nsdb) { + if (nsdb == NULL) + return; + + xmlFree(nsdb->extra); + xmlFree(nsdb->hash); + xmlFree(nsdb); +} + +/** + * xmlParserNsReset: + * @nsdb: namespace database * - * Returns the number of namespaces removed + * Reset a namespace database. */ -static int -nsPop(xmlParserCtxtPtr ctxt, int nr) -{ - int i; +static void +xmlParserNsReset(xmlParserNsData *nsdb) { + if (nsdb == NULL) + return; - 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); + nsdb->hashElems = 0; + nsdb->elementId = 0; + nsdb->defaultNsIndex = INT_MAX; - for (i = 0;i < nr;i++) { - ctxt->nsNr--; - ctxt->nsTab[ctxt->nsNr] = NULL; - } - return(nr); + if (nsdb->hash) + memset(nsdb->hash, 0, nsdb->hashSize * sizeof(nsdb->hash[0])); } -#endif +/** + * xmlParserStartElement: + * @nsdb: namespace database + * + * Signal that a new element has started. + * + * Returns 0 on success, -1 if the element counter overflowed. + */ static int -xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { - const xmlChar **atts; - int *attallocs; - int maxatts; +xmlParserNsStartElement(xmlParserNsData *nsdb) { + if (nsdb->elementId == UINT_MAX) + return(-1); + nsdb->elementId++; - 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); + return(0); } /** - * inputPush: - * @ctxt: an XML parser context - * @value: the parser input + * xmlParserNsLookup: + * @ctxt: parser context + * @prefix: namespace prefix + * @bucketPtr: optional bucket (return value) * - * Pushes a new parser input on top of the input stack + * Lookup namespace with given prefix. If @bucketPtr is non-NULL, it will + * be set to the matching bucket, or the first empty bucket if no match + * was found. * - * Returns -1 in case of error, the index in the stack otherwise + * Returns the namespace index on success, INT_MAX if no namespace was + * found. */ -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); - ctxt->inputMax /= 2; - return (-1); +static int +xmlParserNsLookup(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, + xmlParserNsBucket **bucketPtr) { + xmlParserNsBucket *bucket, *tombstone; + unsigned index, hashValue; + + if (prefix->name == NULL) + return(ctxt->nsdb->defaultNsIndex); + + if (ctxt->nsdb->hashSize == 0) + return(INT_MAX); + + hashValue = prefix->hashValue; + index = hashValue & (ctxt->nsdb->hashSize - 1); + bucket = &ctxt->nsdb->hash[index]; + tombstone = NULL; + + while (bucket->hashValue) { + if (bucket->index == INT_MAX) { + if (tombstone == NULL) + tombstone = bucket; + } else if (bucket->hashValue == hashValue) { + if (ctxt->nsTab[bucket->index * 2] == prefix->name) { + if (bucketPtr != NULL) + *bucketPtr = bucket; + return(bucket->index); + } + } + + index++; + bucket++; + if (index == ctxt->nsdb->hashSize) { + index = 0; + bucket = ctxt->nsdb->hash; } } - ctxt->inputTab[ctxt->inputNr] = value; - ctxt->input = value; - return (ctxt->inputNr++); + + if (bucketPtr != NULL) + *bucketPtr = tombstone ? tombstone : bucket; + return(INT_MAX); } + /** - * inputPop: - * @ctxt: an XML parser context + * xmlParserNsLookupUri: + * @ctxt: parser context + * @prefix: namespace prefix * - * Pops the top parser input from the input stack + * Lookup namespace URI with given prefix. * - * Returns the input just removed + * Returns the namespace URI on success, NULL if no namespace was found. */ -xmlParserInputPtr -inputPop(xmlParserCtxtPtr ctxt) -{ - xmlParserInputPtr ret; +static const xmlChar * +xmlParserNsLookupUri(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix) { + const xmlChar *ret; + int nsIndex; + + if (prefix->name == ctxt->str_xml) + return(ctxt->str_xml_ns); + + /* + * minNsIndex is used when building an entity tree. We must + * ignore namespaces declared outside the entity. + */ + nsIndex = xmlParserNsLookup(ctxt, prefix, NULL); + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) + return(NULL); + + ret = ctxt->nsTab[nsIndex * 2 + 1]; + if (ret[0] == 0) + ret = NULL; + return(ret); +} + +/** + * xmlParserNsLookupSax: + * @ctxt: parser context + * @prefix: namespace prefix + * + * Lookup extra data for the given prefix. This returns data stored + * with xmlParserNsUdpateSax. + * + * Returns the data on success, NULL if no namespace was found. + */ +void * +xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { + xmlHashedString hprefix; + int nsIndex; + + if (prefix == ctxt->str_xml) + return(NULL); + + hprefix.name = prefix; + if (prefix != NULL) + hprefix.hashValue = xmlDictComputeHash(ctxt->dict, prefix); + else + hprefix.hashValue = 0; + nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) + return(NULL); + + return(ctxt->nsdb->extra[nsIndex].saxData); +} + +/** + * xmlParserNsUpdateSax: + * @ctxt: parser context + * @prefix: namespace prefix + * @saxData: extra data for SAX handler + * + * Sets or updates extra data for the given prefix. This value will be + * returned by xmlParserNsLookupSax as long as the namespace with the + * given prefix is in scope. + * + * Returns the data on success, NULL if no namespace was found. + */ +int +xmlParserNsUpdateSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix, + void *saxData) { + xmlHashedString hprefix; + int nsIndex; + + if (prefix == ctxt->str_xml) + return(-1); + + hprefix.name = prefix; + if (prefix != NULL) + hprefix.hashValue = xmlDictComputeHash(ctxt->dict, prefix); + else + hprefix.hashValue = 0; + nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) + return(-1); + + ctxt->nsdb->extra[nsIndex].saxData = saxData; + return(0); +} + +/** + * xmlParserNsGrow: + * @ctxt: parser context + * + * Grows the namespace tables. + * + * Returns 0 on success, -1 if a memory allocation failed. + */ +static int +xmlParserNsGrow(xmlParserCtxtPtr ctxt) { + const xmlChar **table; + xmlParserNsExtra *extra; + int newSize; + + if (ctxt->nsMax > INT_MAX / 2) + goto error; + newSize = ctxt->nsMax ? ctxt->nsMax * 2 : 16; + + table = xmlRealloc(ctxt->nsTab, 2 * newSize * sizeof(table[0])); + if (table == NULL) + goto error; + ctxt->nsTab = table; + + extra = xmlRealloc(ctxt->nsdb->extra, newSize * sizeof(extra[0])); + if (extra == NULL) + goto error; + ctxt->nsdb->extra = extra; + + ctxt->nsMax = newSize; + return(0); + +error: + xmlErrMemory(ctxt); + return(-1); +} + +/** + * xmlParserNsPush: + * @ctxt: parser context + * @prefix: prefix with hash value + * @uri: uri with hash value + * @saxData: extra data for SAX handler + * @defAttr: whether the namespace comes from a default attribute + * + * Push a new namespace on the table. + * + * Returns 1 if the namespace was pushed, 0 if the namespace was ignored, + * -1 if a memory allocation failed. + */ +static int +xmlParserNsPush(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, + const xmlHashedString *uri, void *saxData, int defAttr) { + xmlParserNsBucket *bucket = NULL; + xmlParserNsExtra *extra; + const xmlChar **ns; + unsigned hashValue, nsIndex, oldIndex; + + if ((prefix != NULL) && (prefix->name == ctxt->str_xml)) + return(0); + + if ((ctxt->nsNr >= ctxt->nsMax) && (xmlParserNsGrow(ctxt) < 0)) { + xmlErrMemory(ctxt); + return(-1); + } + + /* + * Default namespace and 'xml' namespace + */ + if ((prefix == NULL) || (prefix->name == NULL)) { + oldIndex = ctxt->nsdb->defaultNsIndex; + + if (oldIndex != INT_MAX) { + extra = &ctxt->nsdb->extra[oldIndex]; + + if (extra->elementId == ctxt->nsdb->elementId) { + if (defAttr == 0) + xmlErrAttributeDup(ctxt, NULL, BAD_CAST "xmlns"); + return(0); + } + + if ((ctxt->options & XML_PARSE_NSCLEAN) && + (uri->name == ctxt->nsTab[oldIndex * 2 + 1])) + return(0); + } + + ctxt->nsdb->defaultNsIndex = ctxt->nsNr; + goto populate_entry; + } + + /* + * Hash table lookup + */ + oldIndex = xmlParserNsLookup(ctxt, prefix, &bucket); + if (oldIndex != INT_MAX) { + extra = &ctxt->nsdb->extra[oldIndex]; + + /* + * Check for duplicate definitions on the same element. + */ + if (extra->elementId == ctxt->nsdb->elementId) { + if (defAttr == 0) + xmlErrAttributeDup(ctxt, BAD_CAST "xmlns", prefix->name); + return(0); + } + + if ((ctxt->options & XML_PARSE_NSCLEAN) && + (uri->name == ctxt->nsTab[bucket->index * 2 + 1])) + return(0); + + bucket->index = ctxt->nsNr; + goto populate_entry; + } + + /* + * Insert new bucket + */ + + hashValue = prefix->hashValue; + + /* + * Grow hash table, 50% fill factor + */ + if (ctxt->nsdb->hashElems + 1 > ctxt->nsdb->hashSize / 2) { + xmlParserNsBucket *newHash; + unsigned newSize, i, index; + + if (ctxt->nsdb->hashSize > UINT_MAX / 2) { + xmlErrMemory(ctxt); + return(-1); + } + newSize = ctxt->nsdb->hashSize ? ctxt->nsdb->hashSize * 2 : 16; + newHash = xmlMalloc(newSize * sizeof(newHash[0])); + if (newHash == NULL) { + xmlErrMemory(ctxt); + return(-1); + } + memset(newHash, 0, newSize * sizeof(newHash[0])); + + for (i = 0; i < ctxt->nsdb->hashSize; i++) { + unsigned hv = ctxt->nsdb->hash[i].hashValue; + unsigned newIndex; + + if ((hv == 0) || (ctxt->nsdb->hash[i].index == INT_MAX)) + continue; + newIndex = hv & (newSize - 1); + + while (newHash[newIndex].hashValue != 0) { + newIndex++; + if (newIndex == newSize) + newIndex = 0; + } + + newHash[newIndex] = ctxt->nsdb->hash[i]; + } + + xmlFree(ctxt->nsdb->hash); + ctxt->nsdb->hash = newHash; + ctxt->nsdb->hashSize = newSize; + + /* + * Relookup + */ + index = hashValue & (newSize - 1); + + while (newHash[index].hashValue != 0) { + index++; + if (index == newSize) + index = 0; + } + + bucket = &newHash[index]; + } + + bucket->hashValue = hashValue; + bucket->index = ctxt->nsNr; + ctxt->nsdb->hashElems++; + oldIndex = INT_MAX; + +populate_entry: + nsIndex = ctxt->nsNr; + + ns = &ctxt->nsTab[nsIndex * 2]; + ns[0] = prefix ? prefix->name : NULL; + ns[1] = uri->name; + + extra = &ctxt->nsdb->extra[nsIndex]; + extra->saxData = saxData; + extra->prefixHashValue = prefix ? prefix->hashValue : 0; + extra->uriHashValue = uri->hashValue; + extra->elementId = ctxt->nsdb->elementId; + extra->oldIndex = oldIndex; + + ctxt->nsNr++; + + return(1); +} + +/** + * xmlParserNsPop: + * @ctxt: an XML parser context + * @nr: the number to pop + * + * Pops the top @nr namespaces and restores the hash table. + * + * Returns the number of namespaces popped. + */ +static int +xmlParserNsPop(xmlParserCtxtPtr ctxt, int nr) +{ + int i; + + /* assert(nr <= ctxt->nsNr); */ + + for (i = ctxt->nsNr - 1; i >= ctxt->nsNr - nr; i--) { + const xmlChar *prefix = ctxt->nsTab[i * 2]; + xmlParserNsExtra *extra = &ctxt->nsdb->extra[i]; + + if (prefix == NULL) { + ctxt->nsdb->defaultNsIndex = extra->oldIndex; + } else { + xmlHashedString hprefix; + xmlParserNsBucket *bucket = NULL; + + hprefix.name = prefix; + hprefix.hashValue = extra->prefixHashValue; + xmlParserNsLookup(ctxt, &hprefix, &bucket); + /* assert(bucket && bucket->hashValue); */ + bucket->index = extra->oldIndex; + } + } + + ctxt->nsNr -= nr; + return(nr); +} + +static int +xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { + const xmlChar **atts; + unsigned *attallocs; + int maxatts; + + if (nr + 5 > ctxt->maxatts) { + maxatts = ctxt->maxatts == 0 ? 55 : (nr + 5) * 2; + atts = (const xmlChar **) xmlMalloc( + maxatts * sizeof(const xmlChar *)); + if (atts == NULL) goto mem_error; + attallocs = xmlRealloc(ctxt->attallocs, + (maxatts / 5) * sizeof(attallocs[0])); + if (attallocs == NULL) { + xmlFree(atts); + goto mem_error; + } + if (ctxt->maxatts > 0) + memcpy(atts, ctxt->atts, ctxt->maxatts * sizeof(const xmlChar *)); + xmlFree(ctxt->atts); + ctxt->atts = atts; + ctxt->attallocs = attallocs; + ctxt->maxatts = maxatts; + } + return(ctxt->maxatts); +mem_error: + xmlErrMemory(ctxt); + 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) +{ + char *directory = NULL; + + if ((ctxt == NULL) || (value == NULL)) + return(-1); + + if (ctxt->inputNr >= ctxt->inputMax) { + size_t newSize = ctxt->inputMax * 2; + xmlParserInputPtr *tmp; + + tmp = (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab, + newSize * sizeof(*tmp)); + if (tmp == NULL) { + xmlErrMemory(ctxt); + return (-1); + } + ctxt->inputTab = tmp; + ctxt->inputMax = newSize; + } + + if ((ctxt->inputNr == 0) && (value->filename != NULL)) { + directory = xmlParserGetDirectory(value->filename); + if (directory == NULL) { + xmlErrMemory(ctxt); + return(-1); + } + } + + ctxt->inputTab[ctxt->inputNr] = value; + ctxt->input = value; + + if (ctxt->inputNr == 0) { + xmlFree(ctxt->directory); + ctxt->directory = directory; + } + + 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); @@ -1791,6 +2008,8 @@ inputPop(xmlParserCtxtPtr ctxt) * @ctxt: an XML parser context * @value: the element node * + * DEPRECATED: Internal function, do not use. + * * Pushes a new element node on top of the node stack * * Returns -1 in case of error, the index in the stack otherwise @@ -1798,7 +2017,19 @@ inputPop(xmlParserCtxtPtr ctxt) int nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) { - if (ctxt == NULL) return(0); + int maxDepth; + + if (ctxt == NULL) + return(0); + + maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; + if (ctxt->nodeNr > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "Excessive depth in document: %d use XML_PARSE_HUGE option\n", + ctxt->nodeNr); + xmlHaltParser(ctxt); + return(-1); + } if (ctxt->nodeNr >= ctxt->nodeMax) { xmlNodePtr *tmp; @@ -1806,20 +2037,12 @@ nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } ctxt->nodeTab = tmp; ctxt->nodeMax *= 2; } - if ((((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, - "Excessive depth in document: %d use XML_PARSE_HUGE option\n", - xmlParserMaxDepth); - xmlHaltParser(ctxt); - return(-1); - } ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++); @@ -1829,6 +2052,8 @@ nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) * nodePop: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, do not use. + * * Pops the top element node from the node stack * * Returns the node just removed @@ -1905,7 +2130,7 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, tag->nsNr = nsNr; return (ctxt->nameNr++); mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } #ifdef LIBXML_PUSH_ENABLED @@ -1940,6 +2165,8 @@ nameNsPop(xmlParserCtxtPtr ctxt) * @ctxt: an XML parser context * @value: the element name * + * DEPRECATED: Internal function, do not use. + * * Pushes a new element name on top of the name stack * * Returns -1 in case of error, the index in the stack otherwise @@ -1964,13 +2191,16 @@ namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) ctxt->name = value; return (ctxt->nameNr++); mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } + /** * namePop: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, do not use. + * * Pops the top element name from the name stack * * Returns the name just removed @@ -2000,7 +2230,7 @@ static int spacePush(xmlParserCtxtPtr ctxt, int val) { tmp = (int *) xmlRealloc(ctxt->spaceTab, ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); ctxt->spaceMax /=2; return(-1); } @@ -2086,7 +2316,7 @@ static int spacePop(xmlParserCtxtPtr ctxt) { #define SKIP(val) do { \ ctxt->input->cur += (val),ctxt->input->col+=(val); \ if (*ctxt->input->cur == 0) \ - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ + xmlParserGrow(ctxt); \ } while (0) #define SKIPL(val) do { \ @@ -2098,57 +2328,31 @@ static int spacePop(xmlParserCtxtPtr ctxt) { ctxt->input->cur++; \ } \ if (*ctxt->input->cur == 0) \ - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ + xmlParserGrow(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); +#define SHRINK \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ + xmlParserShrink(ctxt); -static void xmlSHRINK (xmlParserCtxtPtr ctxt) { - xmlParserInputShrink(ctxt->input); - if (*ctxt->input->cur == 0) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); -} - -#define GROW if ((ctxt->progressive == 0) && \ - (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ - xmlGROW (ctxt); - -static void xmlGROW (xmlParserCtxtPtr ctxt) { - ptrdiff_t curEnd = ctxt->input->end - ctxt->input->cur; - ptrdiff_t curBase = ctxt->input->cur - ctxt->input->base; - - if (((curEnd > XML_MAX_LOOKUP_LIMIT) || - (curBase > XML_MAX_LOOKUP_LIMIT)) && - ((ctxt->input->buf) && - (ctxt->input->buf->readcallback != xmlInputReadCallbackNop)) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Huge input lookup"); - xmlHaltParser(ctxt); - return; - } - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - if ((ctxt->input->cur > ctxt->input->end) || - (ctxt->input->cur < ctxt->input->base)) { - xmlHaltParser(ctxt); - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "cur index out of bound"); - return; - } - if ((ctxt->input->cur != NULL) && (*ctxt->input->cur == 0)) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); -} +#define GROW \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + xmlParserGrow(ctxt); #define SKIP_BLANKS xmlSkipBlankChars(ctxt) +#define SKIP_BLANKS_PE xmlSkipBlankCharsPE(ctxt) + #define NEXT xmlNextChar(ctxt) #define NEXT1 { \ ctxt->input->col++; \ ctxt->input->cur++; \ if (*ctxt->input->cur == 0) \ - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ + xmlParserGrow(ctxt); \ } #define NEXTL(l) do { \ @@ -2161,86 +2365,156 @@ static void xmlGROW (xmlParserCtxtPtr ctxt) { #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; \ +#define COPY_BUF(b, i, v) \ + if (v < 0x80) b[i++] = v; \ else i += xmlCopyCharMultiByte(&b[i],v) -#define CUR_CONSUMED \ - (ctxt->input->consumed + (ctxt->input->cur - ctxt->input->base)) - /** * 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. + * DEPRECATED: Internal function, do not use. + * + * Skip whitespace in the input stream. * * Returns the number of space chars skipped */ - int xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { + const xmlChar *cur; int res = 0; /* * It's Okay to use CUR/NEXT here since all the blanks are on * the ASCII range. */ - if (((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) || - (ctxt->instate == XML_PARSER_START)) { - const xmlChar *cur; - /* - * if we are in the document content, go really fast - */ - cur = ctxt->input->cur; - while (IS_BLANK_CH(*cur)) { - if (*cur == '\n') { - ctxt->input->line++; ctxt->input->col = 1; - } else { - ctxt->input->col++; - } - cur++; - if (res < INT_MAX) - res++; - if (*cur == 0) { - ctxt->input->cur = cur; - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - } - ctxt->input->cur = cur; - } else { - int expandPE = ((ctxt->external != 0) || (ctxt->inputNr != 1)); - - while (1) { - if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */ - NEXT; - } else if (CUR == '%') { - /* - * Need to handle support of entities branching here - */ - if ((expandPE == 0) || (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0)) - break; - xmlParsePEReference(ctxt); - } else if (CUR == 0) { - if (ctxt->inputNr <= 1) - break; - xmlPopInput(ctxt); - } else { - break; - } - - /* - * Also increase the counter when entering or exiting a PERef. - * The spec says: "When a parameter-entity reference is recognized - * in the DTD and included, its replacement text MUST be enlarged - * by the attachment of one leading and one following space (#x20) - * character." - */ - if (res < INT_MAX) - res++; + cur = ctxt->input->cur; + while (IS_BLANK_CH(*cur)) { + if (*cur == '\n') { + ctxt->input->line++; ctxt->input->col = 1; + } else { + ctxt->input->col++; } + cur++; + if (res < INT_MAX) + res++; + if (*cur == 0) { + ctxt->input->cur = cur; + xmlParserGrow(ctxt); + cur = ctxt->input->cur; + } + } + ctxt->input->cur = cur; + + return(res); +} + +static void +xmlPopPE(xmlParserCtxtPtr ctxt) { + unsigned long consumed; + xmlEntityPtr ent; + + ent = ctxt->input->entity; + + ent->flags &= ~XML_ENT_EXPANDING; + + if ((ent->flags & XML_ENT_CHECKED) == 0) { + int result; + + /* + * Read the rest of the stream in case of errors. We want + * to account for the whole entity size. + */ + do { + ctxt->input->cur = ctxt->input->end; + xmlParserShrink(ctxt); + result = xmlParserGrow(ctxt); + } while (result > 0); + + consumed = ctxt->input->consumed; + xmlSaturatedAddSizeT(&consumed, + ctxt->input->end - ctxt->input->base); + + xmlSaturatedAdd(&ent->expandedSize, consumed); + + /* + * Add to sizeentities when parsing an external entity + * for the first time. + */ + if (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) { + xmlSaturatedAdd(&ctxt->sizeentities, consumed); + } + + ent->flags |= XML_ENT_CHECKED; + } + + xmlPopInput(ctxt); + + xmlParserEntityCheck(ctxt, ent->expandedSize); +} + +/** + * xmlSkipBlankCharsPE: + * @ctxt: the XML parser context + * + * Skip whitespace in the input stream, also handling parameter + * entities. + * + * Returns the number of space chars skipped + */ +static int +xmlSkipBlankCharsPE(xmlParserCtxtPtr ctxt) { + int res = 0; + int inParam; + int expandParam; + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + + if (!inParam && !expandParam) + return(xmlSkipBlankChars(ctxt)); + + while (PARSER_STOPPED(ctxt) == 0) { + if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */ + NEXT; + } else if (CUR == '%') { + if ((expandParam == 0) || + (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0)) + break; + + /* + * Expand parameter entity. We continue to consume + * whitespace at the start of the entity and possible + * even consume the whole entity and pop it. We might + * even pop multiple PEs in this loop. + */ + xmlParsePEReference(ctxt); + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + } else if (CUR == 0) { + if (inParam == 0) + break; + + xmlPopPE(ctxt); + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + } else { + break; + } + + /* + * Also increase the counter when entering or exiting a PERef. + * The spec says: "When a parameter-entity reference is recognized + * in the DTD and included, its replacement text MUST be enlarged + * by the attachment of one leading and one following space (#x20) + * character." + */ + if (res < INT_MAX) + res++; } + return(res); } @@ -2261,17 +2535,13 @@ xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { */ xmlChar xmlPopInput(xmlParserCtxtPtr ctxt) { + xmlParserInputPtr input; + if ((ctxt == NULL) || (ctxt->inputNr <= 1)) return(0); - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "Popping input %d\n", ctxt->inputNr); - if ((ctxt->inputNr > 1) && (ctxt->inSubset == 0) && - (ctxt->instate != XML_PARSER_EOF)) - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "Unfinished entity outside the DTD"); - xmlFreeInputStream(inputPop(ctxt)); + input = inputPop(ctxt); + xmlFreeInputStream(input); if (*ctxt->input->cur == 0) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + xmlParserGrow(ctxt); return(CUR); } @@ -2280,33 +2550,26 @@ xmlPopInput(xmlParserCtxtPtr ctxt) { * @ctxt: an XML parser context * @input: an XML parser input fragment (entity, XML fragment ...). * - * xmlPushInput: switch to a new input stream which is stacked on top - * of the previous one(s). + * Push an input stream onto the stack. + * * Returns -1 in case of error or the index in the input stack */ int xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { + int maxDepth; int ret; - if (input == NULL) return(-1); - - if (xmlParserDebugEntities) { - if ((ctxt->input != NULL) && (ctxt->input->filename)) - xmlGenericError(xmlGenericErrorContext, - "%s(%d): ", ctxt->input->filename, - ctxt->input->line); - xmlGenericError(xmlGenericErrorContext, - "Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur); - } - if (((ctxt->inputNr > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || - (ctxt->inputNr > 1024)) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - while (ctxt->inputNr > 1) - xmlFreeInputStream(inputPop(ctxt)); + + if ((ctxt == NULL) || (input == NULL)) + return(-1); + + maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + if (ctxt->inputNr > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + xmlHaltParser(ctxt); return(-1); } ret = inputPush(ctxt, input); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); GROW; return(ret); } @@ -2315,7 +2578,9 @@ xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { * xmlParseCharRef: * @ctxt: an XML parser context * - * parse Reference declarations + * DEPRECATED: Internal function, don't use. + * + * Parse a numeric character reference. Always consumes '&'. * * [66] CharRef ::= '&#' [0-9]+ ';' | * '&#x' [0-9a-fA-F]+ ';' @@ -2338,12 +2603,10 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { (NXT(2) == 'x')) { SKIP(3); GROW; - while (RAW != ';') { /* loop blocked by count */ + while ((RAW != ';') && (PARSER_STOPPED(ctxt) == 0)) { if (count++ > 20) { count = 0; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 16 + (CUR - '0'); @@ -2374,8 +2637,6 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { if (count++ > 20) { count = 0; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 10 + (CUR - '0'); @@ -2396,6 +2657,8 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { ctxt->input->cur++; } } else { + if (RAW == '&') + SKIP(1); xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); } @@ -2516,6 +2779,8 @@ xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { * xmlParserHandlePEReference: * @ctxt: the parser context * + * DEPRECATED: Internal function, do not use. + * * [69] PEReference ::= '%' Name ';' * * [ WFC: No Recursion ] @@ -2546,78 +2811,9 @@ xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { */ void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { - switch(ctxt->instate) { - case XML_PARSER_CDATA_SECTION: - return; - case XML_PARSER_COMMENT: - return; - case XML_PARSER_START_TAG: - return; - case XML_PARSER_END_TAG: - return; - case XML_PARSER_EOF: - xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL); - return; - case XML_PARSER_PROLOG: - case XML_PARSER_START: - case XML_PARSER_MISC: - xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL); - return; - case XML_PARSER_ENTITY_DECL: - case XML_PARSER_CONTENT: - case XML_PARSER_ATTRIBUTE_VALUE: - case XML_PARSER_PI: - case XML_PARSER_SYSTEM_LITERAL: - case XML_PARSER_PUBLIC_LITERAL: - /* we just ignore it there */ - return; - case XML_PARSER_EPILOG: - xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL); - return; - case XML_PARSER_ENTITY_VALUE: - /* - * NOTE: in the case of entity values, we don't do the - * substitution here since we need the literal - * entity value to be able to save the internal - * subset of the document. - * This will be handled by xmlStringDecodeEntities - */ - return; - case XML_PARSER_DTD: - /* - * [WFC: Well-Formedness Constraint: PEs in Internal Subset] - * In the internal DTD subset, parameter-entity references - * can occur only where markup declarations can occur, not - * within markup declarations. - * In that case this is handled in xmlParseMarkupDecl - */ - if ((ctxt->external == 0) && (ctxt->inputNr == 1)) - return; - if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0) - return; - break; - case XML_PARSER_IGNORE: - return; - } - xmlParsePEReference(ctxt); } -/* - * Macro used to grow the current buffer. - * buffer##_size is expected to be a size_t - * mem_error: is expected to handle memory allocation failures - */ -#define growBuffer(buffer, n) { \ - xmlChar *tmp; \ - size_t new_size = buffer##_size * 2 + n; \ - if (new_size < buffer##_size) goto mem_error; \ - tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ - if (tmp == NULL) goto mem_error; \ - buffer = tmp; \ - buffer##_size = new_size; \ -} - /** * xmlStringLenDecodeEntities: * @ctxt: the parser context @@ -2628,191 +2824,23 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { * @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 ';' + * DEPRECATED: Internal function, don't use. * * 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; - size_t buffer_size = 0; - size_t nbchars = 0; - - xmlChar *current = NULL; - xmlChar *rep = NULL; - const xmlChar *last; - xmlEntityPtr ent; - int c,l; - + int what ATTRIBUTE_UNUSED, + xmlChar end, xmlChar end2, xmlChar end3) { 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); - if (buffer == NULL) goto mem_error; - - /* - * OK loop until we reach one of the ending char or a size limit. - * we are operating on already parsed values. - */ - if (str < last) - c = CUR_SCHAR(str, l); - else - c = 0; - while ((c != 0) && (c != end) && /* non input consuming loop */ - (c != end2) && (c != end3) && - (ctxt->instate != XML_PARSER_EOF)) { - - if (c == 0) break; - if ((c == '&') && (str[1] == '#')) { - int val = xmlParseStringCharRef(ctxt, &str); - if (val == 0) - goto int_error; - COPY_BUF(0,buffer,nbchars,val); - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "String decoding Entity Reference: %.30s\n", - str); - ent = xmlParseStringEntityRef(ctxt, &str); - xmlParserEntityCheck(ctxt, 0, ent, 0); - if (ent != NULL) - ctxt->nbentities += ent->checked / 2; - if ((ent != NULL) && - (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - if (ent->content != NULL) { - COPY_BUF(0,buffer,nbchars,ent->content[0]); - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } else { - xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, - "predefined entity has no content\n"); - goto int_error; - } - } else if ((ent != NULL) && (ent->content != NULL)) { - ctxt->depth++; - rep = xmlStringDecodeEntities(ctxt, ent->content, what, - 0, 0, 0); - ctxt->depth--; - if (rep == NULL) { - ent->content[0] = 0; - goto int_error; - } + return(NULL); - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) - 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 + i + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, i + XML_PARSER_BUFFER_SIZE); - } - for (;i > 0;i--) - buffer[nbchars++] = *cur++; - buffer[nbchars++] = ';'; - } - } else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) { - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "String decoding PE Reference: %.30s\n", str); - ent = xmlParseStringPEReference(ctxt, &str); - xmlParserEntityCheck(ctxt, 0, ent, 0); - if (ent != NULL) - ctxt->nbentities += ent->checked / 2; - if (ent != NULL) { - if (ent->content == NULL) { - /* - * Note: external parsed entities will not be loaded, - * it is not required for a non-validating parser to - * complete external PEReferences coming from the - * internal subset - */ - if (((ctxt->options & XML_PARSE_NOENT) != 0) || - ((ctxt->options & XML_PARSE_DTDVALID) != 0) || - (ctxt->validate != 0)) { - xmlLoadEntityContent(ctxt, ent); - } else { - xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING, - "not validating will not read content for PE entity %s\n", - ent->name, NULL); - } - } - ctxt->depth++; - rep = xmlStringDecodeEntities(ctxt, ent->content, what, - 0, 0, 0); - ctxt->depth--; - if (rep == NULL) { - if (ent->content != NULL) - ent->content[0] = 0; - goto int_error; - } - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) - goto int_error; - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - xmlFree(rep); - rep = NULL; - } - } else { - COPY_BUF(l,buffer,nbchars,c); - str += l; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - if (str < last) - c = CUR_SCHAR(str, l); - else - c = 0; - } - buffer[nbchars] = 0; - return(buffer); + if ((str[len] != 0) || + (end != 0) || (end2 != 0) || (end3 != 0)) + return(NULL); -mem_error: - xmlErrMemory(ctxt, NULL); -int_error: - if (rep != NULL) - xmlFree(rep); - if (buffer != NULL) - xmlFree(buffer); - return(NULL); + return(xmlExpandEntitiesInAttValue(ctxt, str, 0)); } /** @@ -2824,21 +2852,22 @@ int_error: * @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 ';' + * DEPRECATED: Internal function, don't use. * * Returns A newly allocated string with the substitution done. The caller * must deallocate it ! */ xmlChar * -xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, +xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, + int what ATTRIBUTE_UNUSED, xmlChar end, xmlChar end2, xmlChar end3) { - if ((ctxt == NULL) || (str == NULL)) return(NULL); - return(xmlStringLenDecodeEntities(ctxt, str, xmlStrlen(str), what, - end, end2, end3)); + if ((ctxt == NULL) || (str == NULL)) + return(NULL); + + if ((end != 0) || (end2 != 0) || (end3 != 0)) + return(NULL); + + return(xmlExpandEntitiesInAttValue(ctxt, str, 0)); } /************************************************************************ @@ -2861,7 +2890,7 @@ xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, int blank_chars) { - int i, ret; + int i; xmlNodePtr lastChild; /* @@ -2891,9 +2920,25 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, */ if (ctxt->node == NULL) return(0); if (ctxt->myDoc != NULL) { - ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); - if (ret == 0) return(1); - if (ret == 1) return(0); + xmlElementPtr elemDecl = NULL; + xmlDocPtr doc = ctxt->myDoc; + const xmlChar *prefix = NULL; + + if (ctxt->node->ns) + prefix = ctxt->node->ns->prefix; + if (doc->intSubset != NULL) + elemDecl = xmlHashLookup2(doc->intSubset->elements, ctxt->node->name, + prefix); + if ((elemDecl == NULL) && (doc->extSubset != NULL)) + elemDecl = xmlHashLookup2(doc->extSubset->elements, ctxt->node->name, + prefix); + if (elemDecl != NULL) { + if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) + return(1); + if ((elemDecl->etype == XML_ELEMENT_TYPE_ANY) || + (elemDecl->etype == XML_ELEMENT_TYPE_MIXED)) + return(0); + } } /* @@ -2926,7 +2971,7 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, * xmlSplitQName: * @ctxt: an XML parser context * @name: an XML parser context - * @prefix: a xmlChar ** + * @prefixOut: a xmlChar ** * * parse an UTF8 encoded XML qualified name string * @@ -2941,27 +2986,21 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, */ xmlChar * -xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { +xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefixOut) { xmlChar buf[XML_MAX_NAMELEN + 5]; xmlChar *buffer = NULL; int len = 0; int max = XML_MAX_NAMELEN; xmlChar *ret = NULL; + xmlChar *prefix; const xmlChar *cur = name; int c; - if (prefix == NULL) return(NULL); - *prefix = NULL; + if (prefixOut == NULL) return(NULL); + *prefixOut = NULL; if (cur == NULL) return(NULL); -#ifndef XML_XML_NAMESPACE - /* xml: prefix is not really a namespace */ - if ((cur[0] == 'x') && (cur[1] == 'm') && - (cur[2] == 'l') && (cur[3] == ':')) - return(xmlStrdup(name)); -#endif - /* nasty but well=formed */ if (cur[0] == ':') return(xmlStrdup(name)); @@ -2978,9 +3017,9 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { */ max = len * 2; - buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); @@ -2989,11 +3028,10 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { xmlChar *tmp; max *= 2; - tmp = (xmlChar *) xmlRealloc(buffer, - max * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlFree(buffer); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } buffer = tmp; @@ -3007,13 +3045,16 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { if ((c == ':') && (*cur == 0)) { if (buffer != NULL) xmlFree(buffer); - *prefix = NULL; return(xmlStrdup(name)); } - if (buffer == NULL) + if (buffer == NULL) { ret = xmlStrndup(buf, len); - else { + if (ret == NULL) { + xmlErrMemory(ctxt); + return(NULL); + } + } else { ret = buffer; buffer = NULL; max = XML_MAX_NAMELEN; @@ -3022,9 +3063,15 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { if (c == ':') { c = *cur; - *prefix = ret; + prefix = ret; if (c == 0) { - return(xmlStrndup(BAD_CAST "", 0)); + ret = xmlStrndup(BAD_CAST "", 0); + if (ret == NULL) { + xmlFree(prefix); + return(NULL); + } + *prefixOut = prefix; + return(ret); } len = 0; @@ -3057,9 +3104,10 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { */ max = len * 2; - buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); + xmlFree(prefix); return(NULL); } memcpy(buffer, buf, len); @@ -3068,10 +3116,10 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { xmlChar *tmp; max *= 2; - tmp = (xmlChar *) xmlRealloc(buffer, - max * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); + xmlFree(prefix); xmlFree(buffer); return(NULL); } @@ -3083,11 +3131,17 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { buffer[len] = 0; } - if (buffer == NULL) + if (buffer == NULL) { ret = xmlStrndup(buf, len); - else { + if (ret == NULL) { + xmlFree(prefix); + return(NULL); + } + } else { ret = buffer; } + + *prefixOut = prefix; } return(ret); @@ -3105,14 +3159,6 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { * 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 @@ -3194,25 +3240,18 @@ xmlIsNameChar(xmlParserCtxtPtr ctxt, int c) { return(0); } -static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, - int *len, int *alloc, int normalize); - static const xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt) { + const xmlChar *ret; int len = 0, l; int c; - int count = 0; - -#ifdef DEBUG - nbParseNameComplex++; -#endif + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; /* * Handler for more complex cases */ - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); c = CUR_CHAR(l); if ((ctxt->options & XML_PARSE_OLD10) == 0) { /* @@ -3261,13 +3300,8 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { ((c >= 0xFDF0) && (c <= 0xFFFD)) || ((c >= 0x10000) && (c <= 0xEFFFF)) )) { - if (count++ > XML_PARSER_CHUNK_SIZE) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - } - len += l; + if (len <= INT_MAX - l) + len += l; NEXTL(l); c = CUR_CHAR(l); } @@ -3287,19 +3321,13 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { (c == '_') || (c == ':') || (IS_COMBINING(c)) || (IS_EXTENDER(c)))) { - if (count++ > XML_PARSER_CHUNK_SIZE) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - } - len += l; + if (len <= INT_MAX - l) + len += l; NEXTL(l); c = CUR_CHAR(l); } } - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); } @@ -3314,14 +3342,20 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { return (NULL); } if ((*ctxt->input->cur == '\n') && (ctxt->input->cur[-1] == '\r')) - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len)); - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len); + else + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); } /** * xmlParseName: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML name. * * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | @@ -3338,14 +3372,13 @@ const xmlChar * xmlParseName(xmlParserCtxtPtr ctxt) { const xmlChar *in; const xmlChar *ret; - int count = 0; + size_t count = 0; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; GROW; -#ifdef DEBUG - nbParseName++; -#endif - /* * Accelerator for simple ASCII names */ @@ -3362,8 +3395,7 @@ xmlParseName(xmlParserCtxtPtr ctxt) { in++; if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; - if ((count > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (count > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); } @@ -3371,7 +3403,7 @@ xmlParseName(xmlParserCtxtPtr ctxt) { ctxt->input->cur = in; ctxt->input->col += count; if (ret == NULL) - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(ret); } } @@ -3379,65 +3411,44 @@ xmlParseName(xmlParserCtxtPtr ctxt) { return(xmlParseNameComplex(ctxt)); } -static const xmlChar * +static xmlHashedString xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { + xmlHashedString ret; int len = 0, l; int c; - int count = 0; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; size_t startPosition = 0; -#ifdef DEBUG - nbParseNCNameComplex++; -#endif + ret.name = NULL; + ret.hashValue = 0; /* * Handler for more complex cases */ - GROW; startPosition = CUR_PTR - BASE_PTR; c = CUR_CHAR(l); if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ (!xmlIsNameStartChar(ctxt, c) || (c == ':'))) { - return(NULL); + return(ret); } while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ (xmlIsNameChar(ctxt, c) && (c != ':'))) { - if (count++ > XML_PARSER_CHUNK_SIZE) { - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); - return(NULL); - } - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - } - len += l; + if (len <= INT_MAX - l) + len += l; NEXTL(l); c = CUR_CHAR(l); - if (c == 0) { - count = 0; - /* - * when shrinking to extend the buffer we really need to preserve - * the part of the name we already parsed. Hence rolling back - * by current length. - */ - ctxt->input->cur -= l; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - ctxt->input->cur += l; - c = CUR_CHAR(l); - } } - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); - return(NULL); + return(ret); } - return(xmlDictLookup(ctxt->dict, (BASE_PTR + startPosition), len)); + ret = xmlDictLookupHashed(ctxt->dict, (BASE_PTR + startPosition), len); + if (ret.name == NULL) + xmlErrMemory(ctxt); + return(ret); } /** @@ -3455,15 +3466,16 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { * Returns the Name parsed or NULL */ -static const xmlChar * +static xmlHashedString xmlParseNCName(xmlParserCtxtPtr ctxt) { const xmlChar *in, *e; - const xmlChar *ret; - int count = 0; + xmlHashedString ret; + size_t count = 0; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; -#ifdef DEBUG - nbParseNCName++; -#endif + ret.name = NULL; /* * Accelerator for simple ASCII names @@ -3484,16 +3496,15 @@ xmlParseNCName(xmlParserCtxtPtr ctxt) { goto complex; if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; - if ((count > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (count > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); - return(NULL); + return(ret); } - ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + ret = xmlDictLookupHashed(ctxt->dict, ctxt->input->cur, count); ctxt->input->cur = in; ctxt->input->col += count; - if (ret == NULL) { - xmlErrMemory(ctxt, NULL); + if (ret.name == NULL) { + xmlErrMemory(ctxt); } return(ret); } @@ -3520,8 +3531,6 @@ xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { const xmlChar *ret; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); in = ctxt->input->cur; while (*in != 0 && *in == *cmp) { @@ -3564,24 +3573,24 @@ xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { static xmlChar * xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar *ret; const xmlChar *cur = *str; int len = 0, l; int c; - -#ifdef DEBUG - nbParseStringName++; -#endif + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; c = CUR_SCHAR(cur, l); if (!xmlIsNameStartChar(ctxt, c)) { return(NULL); } - COPY_BUF(l,buf,len,c); + COPY_BUF(buf, len, c); cur += l; c = CUR_SCHAR(cur, l); while (xmlIsNameChar(ctxt, c)) { - COPY_BUF(l,buf,len,c); + COPY_BUF(buf, len, c); cur += l; c = CUR_SCHAR(cur, l); if (len >= XML_MAX_NAMELEN) { /* test bigentname.xml */ @@ -3592,9 +3601,9 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar *buffer; int max = len * 2; - buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); @@ -3602,44 +3611,46 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { if (len + 10 > max) { xmlChar *tmp; - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); - xmlFree(buffer); - return(NULL); - } max *= 2; - tmp = (xmlChar *) xmlRealloc(buffer, - max * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buffer); return(NULL); } buffer = tmp; } - COPY_BUF(l,buffer,len,c); + COPY_BUF(buffer, len, c); cur += l; c = CUR_SCHAR(cur, l); + if (len > maxLength) { + xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); + xmlFree(buffer); + return(NULL); + } } buffer[len] = 0; *str = cur; return(buffer); } } - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); return(NULL); } *str = cur; - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); } /** * xmlParseNmtoken: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML Nmtoken. * * [7] Nmtoken ::= (NameChar)+ @@ -3652,34 +3663,19 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar * xmlParseNmtoken(xmlParserCtxtPtr ctxt) { xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar *ret; int len = 0, l; int c; - int count = 0; - -#ifdef DEBUG - nbParseNmToken++; -#endif + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); c = CUR_CHAR(l); while (xmlIsNameChar(ctxt, c)) { - if (count++ > XML_PARSER_CHUNK_SIZE) { - count = 0; - GROW; - } - COPY_BUF(l,buf,len,c); + COPY_BUF(buf, len, c); NEXTL(l); c = CUR_CHAR(l); - if (c == 0) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - c = CUR_CHAR(l); - } if (len >= XML_MAX_NAMELEN) { /* * Okay someone managed to make a huge token, so he's ready to pay @@ -3688,41 +3684,31 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) { xmlChar *buffer; int max = len * 2; - buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); while (xmlIsNameChar(ctxt, c)) { - if (count++ > XML_PARSER_CHUNK_SIZE) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buffer); - return(NULL); - } - } if (len + 10 > max) { xmlChar *tmp; - if ((max > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); - xmlFree(buffer); - return(NULL); - } max *= 2; - tmp = (xmlChar *) xmlRealloc(buffer, - max * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buffer); return(NULL); } buffer = tmp; } - COPY_BUF(l,buffer,len,c); + COPY_BUF(buffer, len, c); + if (len > maxLength) { + xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); + xmlFree(buffer); + return(NULL); + } NEXTL(l); c = CUR_CHAR(l); } @@ -3732,408 +3718,815 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) { } if (len == 0) return(NULL); - if ((len > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); return(NULL); } - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); } /** - * xmlParseEntityValue: - * @ctxt: an XML parser context - * @orig: if non-NULL store a copy of the original entity value - * - * parse a value for ENTITY declarations + * xmlExpandPEsInEntityValue: + * @ctxt: parser context + * @buf: string buffer + * @str: entity value + * @length: size of entity value + * @depth: nesting depth * - * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | + * Validate an entity value and expand parameter entities. + */ +static void +xmlExpandPEsInEntityValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf, + const xmlChar *str, int length, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + const xmlChar *end, *chunk; + int c, l; + + if (str == NULL) + return; + + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; + } + + end = str + length; + chunk = str; + + while ((str < end) && (!PARSER_STOPPED(ctxt))) { + c = *str; + + if (c >= 0x80) { + l = xmlUTF8MultibyteLen(ctxt, str, + "invalid character in entity value\n"); + if (l == 0) { + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + xmlSBufAddReplChar(buf); + str += 1; + chunk = str; + } else { + str += l; + } + } else if (c == '&') { + if (str[1] == '#') { + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + + c = xmlParseStringCharRef(ctxt, &str); + if (c == 0) + return; + + xmlSBufAddChar(buf, c); + + chunk = str; + } else { + xmlChar *name; + + /* + * General entity references are checked for + * syntactic validity. + */ + str++; + name = xmlParseStringName(ctxt, &str); + + if ((name == NULL) || (*str++ != ';')) { + xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_CHAR_ERROR, + "EntityValue: '&' forbidden except for entities " + "references\n"); + xmlFree(name); + return; + } + + xmlFree(name); + } + } else if (c == '%') { + xmlEntityPtr ent; + + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + + ent = xmlParseStringPEReference(ctxt, &str); + if (ent == NULL) + return; + + if (!PARSER_EXTERNAL(ctxt)) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); + return; + } + + if (ent->content == NULL) { + /* + * Note: external parsed entities will not be loaded, + * it is not required for a non-validating parser to + * complete external PEReferences coming from the + * internal subset + */ + if (((ctxt->options & XML_PARSE_NO_XXE) == 0) && + ((ctxt->replaceEntities) || + (ctxt->validate))) { + xmlLoadEntityContent(ctxt, ent); + } else { + xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING, + "not validating will not read content for " + "PE entity %s\n", ent->name, NULL); + } + } + + /* + * TODO: Skip if ent->content is still NULL. + */ + + if (xmlParserEntityCheck(ctxt, ent->length)) + return; + + if (ent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; + } + + ent->flags |= XML_ENT_EXPANDING; + xmlExpandPEsInEntityValue(ctxt, buf, ent->content, ent->length, + depth); + ent->flags &= ~XML_ENT_EXPANDING; + + chunk = str; + } else { + /* Normal ASCII char */ + if (!IS_BYTE_CHAR(c)) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in entity value\n"); + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + xmlSBufAddReplChar(buf); + str += 1; + chunk = str; + } else { + str += 1; + } + } + } + + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + + return; +} + +/** + * xmlParseEntityValue: + * @ctxt: an XML parser context + * @orig: if non-NULL store a copy of the original entity value + * + * DEPRECATED: Internal function, don't use. + * + * parse a value for ENTITY declarations + * + * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | * "'" ([^%&'] | PEReference | Reference)* "'" * * Returns the EntityValue parsed with reference substituted or NULL */ - xmlChar * xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { - 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; + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + const xmlChar *start; + int quote, length; - if (RAW == '"') stop = '"'; - else if (RAW == '\'') stop = '\''; - else { - xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL); + xmlSBufInit(&buf, maxLength); + + GROW; + + quote = CUR; + if ((quote != '"') && (quote != '\'')) { + xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); return(NULL); } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); - if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - return(NULL); + CUR_PTR++; + + length = 0; + + /* + * Copy raw content of the entity into a buffer + */ + while (1) { + int c; + + if (PARSER_STOPPED(ctxt)) + goto error; + + if (CUR_PTR >= ctxt->input->end) { + xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); + goto error; + } + + c = CUR; + + if (c == 0) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in entity value\n"); + goto error; + } + if (c == quote) + break; + NEXTL(1); + length += 1; + + /* + * TODO: Check growth threshold + */ + if (ctxt->input->end - CUR_PTR < 10) + GROW; + } + + start = CUR_PTR - length; + + if (orig != NULL) { + *orig = xmlStrndup(start, length); + if (*orig == NULL) + xmlErrMemory(ctxt); + } + + xmlExpandPEsInEntityValue(ctxt, &buf, start, length, ctxt->inputNr); + + NEXTL(1); + + return(xmlSBufFinish(&buf, NULL, ctxt, "entity length too long")); + +error: + xmlSBufCleanup(&buf, ctxt, "entity length too long"); + return(NULL); +} + +/** + * xmlCheckEntityInAttValue: + * @ctxt: parser context + * @pent: entity + * @depth: nesting depth + * + * Check an entity reference in an attribute value for validity + * without expanding it. + */ +static void +xmlCheckEntityInAttValue(xmlParserCtxtPtr ctxt, xmlEntityPtr pent, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + const xmlChar *str; + unsigned long expandedSize = pent->length; + int c, flags; + + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; + } + + if (pent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; } /* - * The content of the entity definition is copied in a buffer. + * If we're parsing a default attribute value in DTD content, + * the entity might reference other entities which weren't + * defined yet, so the check isn't reliable. */ + if (ctxt->inSubset == 0) + flags = XML_ENT_CHECKED | XML_ENT_VALIDATED; + else + flags = XML_ENT_VALIDATED; + + str = pent->content; + if (str == NULL) + goto done; - ctxt->instate = XML_PARSER_ENTITY_VALUE; - input = ctxt->input; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - goto error; - NEXT; - c = CUR_CHAR(l); /* - * NOTE: 4.4.5 Included in Literal - * When a parameter entity reference appears in a literal entity - * value, ... a single or double quote character in the replacement - * text is always treated as a normal data character and will not - * terminate the literal. - * In practice it means we stop the loop only when back at parsing - * the initial entity and the quote is found + * Note that entity values are already validated. We only check + * for illegal less-than signs and compute the expanded size + * of the entity. No special handling for multi-byte characters + * is needed. */ - while (((IS_CHAR(c)) && ((c != stop) || /* checked */ - (ctxt->input != input))) && (ctxt->instate != XML_PARSER_EOF)) { - if (len + 5 >= size) { - xmlChar *tmp; + while (!PARSER_STOPPED(ctxt)) { + c = *str; - size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); - if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); - goto error; - } - buf = tmp; - } - COPY_BUF(l,buf,len,c); - NEXTL(l); + if (c != '&') { + if (c == 0) + break; - GROW; - c = CUR_CHAR(l); - if (c == 0) { - GROW; - c = CUR_CHAR(l); - } + if (c == '<') + xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, + "'<' in entity '%s' is not allowed in attributes " + "values\n", pent->name); + + str += 1; + } else if (str[1] == '#') { + int val; + + val = xmlParseStringCharRef(ctxt, &str); + if (val == 0) { + pent->content[0] = 0; + break; + } + } else { + xmlChar *name; + xmlEntityPtr ent; + + name = xmlParseStringEntityRef(ctxt, &str); + if (name == NULL) { + pent->content[0] = 0; + break; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1); + xmlFree(name); + + if ((ent != NULL) && + (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { + if ((ent->flags & flags) != flags) { + pent->flags |= XML_ENT_EXPANDING; + xmlCheckEntityInAttValue(ctxt, ent, depth); + pent->flags &= ~XML_ENT_EXPANDING; + } + + xmlSaturatedAdd(&expandedSize, ent->expandedSize); + xmlSaturatedAdd(&expandedSize, XML_ENT_FIXED_COST); + } + } } - buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) - goto error; - if (c != stop) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); - goto error; + +done: + if (ctxt->inSubset == 0) + pent->expandedSize = expandedSize; + + pent->flags |= flags; +} + +/** + * xmlExpandEntityInAttValue: + * @ctxt: parser context + * @buf: string buffer + * @str: entity or attribute value + * @pent: entity for entity value, NULL for attribute values + * @normalize: whether to collapse whitespace + * @inSpace: whitespace state + * @depth: nesting depth + * @check: whether to check for amplification + * + * Expand general entity references in an entity or attribute value. + * Perform attribute value normalization. + */ +static void +xmlExpandEntityInAttValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf, + const xmlChar *str, xmlEntityPtr pent, int normalize, + int *inSpace, int depth, int check) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + int c, chunkSize; + + if (str == NULL) + return; + + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; } - NEXT; + + if (pent != NULL) { + if (pent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; + } + + if (check) { + if (xmlParserEntityCheck(ctxt, pent->length)) + return; + } + } + + chunkSize = 0; /* - * Raise problem w.r.t. '&' and '%' being used in non-entities - * reference constructs. Note Charref will be handled in - * xmlStringDecodeEntities() + * Note that entity values are already validated. No special + * handling for multi-byte characters is needed. */ - cur = buf; - while (*cur != 0) { /* non input consuming */ - if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { - xmlChar *name; - xmlChar tmp = *cur; - int nameOk = 0; + while (!PARSER_STOPPED(ctxt)) { + c = *str; - cur++; - name = xmlParseStringName(ctxt, &cur); - if (name != NULL) { - nameOk = 1; - xmlFree(name); + if (c != '&') { + if (c == 0) + break; + + /* + * If this function is called without an entity, it is used to + * expand entities in an attribute content where less-than was + * already unscaped and is allowed. + */ + if ((pent != NULL) && (c == '<')) { + xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, + "'<' in entity '%s' is not allowed in attributes " + "values\n", pent->name); + break; } - if ((nameOk == 0) || (*cur != ';')) { - xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, - "EntityValue: '%c' forbidden except for entities references\n", - tmp); - goto error; - } - if ((tmp == '%') && (ctxt->inSubset == 1) && - (ctxt->inputNr == 1)) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); - goto error; + + if (c <= 0x20) { + if ((normalize) && (*inSpace)) { + /* Skip char */ + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + } else if (c < 0x20) { + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + xmlSBufAddCString(buf, " ", 1); + } else { + chunkSize += 1; + } + + *inSpace = 1; + } else { + chunkSize += 1; + *inSpace = 0; + } + + str += 1; + } else if (str[1] == '#') { + int val; + + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + val = xmlParseStringCharRef(ctxt, &str); + if (val == 0) { + if (pent != NULL) + pent->content[0] = 0; + break; + } + + if (val == ' ') { + if ((!normalize) || (!*inSpace)) + xmlSBufAddCString(buf, " ", 1); + *inSpace = 1; + } else { + xmlSBufAddChar(buf, val); + *inSpace = 0; + } + } else { + xmlChar *name; + xmlEntityPtr ent; + + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + name = xmlParseStringEntityRef(ctxt, &str); + if (name == NULL) { + if (pent != NULL) + pent->content[0] = 0; + break; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1); + xmlFree(name); + + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (ent->content == NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "predefined entity has no content\n"); + break; + } + + xmlSBufAddString(buf, ent->content, ent->length); + + *inSpace = 0; + } else if ((ent != NULL) && (ent->content != NULL)) { + if (pent != NULL) + pent->flags |= XML_ENT_EXPANDING; + xmlExpandEntityInAttValue(ctxt, buf, ent->content, ent, + normalize, inSpace, depth, check); + if (pent != NULL) + pent->flags &= ~XML_ENT_EXPANDING; } - if (*cur == 0) - break; - } - cur++; + } } - /* - * Then PEReference entities are substituted. - * - * NOTE: 4.4.7 Bypassed - * When a general entity reference appears in the EntityValue in - * an entity declaration, it is bypassed and left as is. - * so XML_SUBSTITUTE_REF is not set here. - */ - ++ctxt->depth; - ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, - 0, 0, 0); - --ctxt->depth; - if (orig != NULL) { - *orig = buf; - buf = NULL; - } + if (chunkSize > 0) + xmlSBufAddString(buf, str - chunkSize, chunkSize); -error: - if (buf != NULL) - xmlFree(buf); - return(ret); + return; } /** - * xmlParseAttValueComplex: + * xmlExpandEntitiesInAttValue: + * @ctxt: parser context + * @str: entity or attribute value + * @normalize: whether to collapse whitespace + * + * Expand general entity references in an entity or attribute value. + * Perform attribute value normalization. + * + * Returns the expanded attribtue value. + */ +xmlChar * +xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str, + int normalize) { + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + int inSpace = 1; + + xmlSBufInit(&buf, maxLength); + + xmlExpandEntityInAttValue(ctxt, &buf, str, NULL, normalize, &inSpace, + ctxt->inputNr, /* check */ 0); + + if ((normalize) && (inSpace) && (buf.size > 0)) + buf.size--; + + return(xmlSBufFinish(&buf, NULL, ctxt, "AttValue length too long")); +} + +/** + * xmlParseAttValueInternal: * @ctxt: an XML parser context - * @len: the resulting attribute len - * @normalize: whether to apply the inner normalization + * @len: attribute len result + * @alloc: whether the attribute was reallocated as a new string + * @normalize: if 1 then further non-CDATA normalization must be done * - * parse a value for an attribute, this is the fallback function - * of xmlParseAttValue() when the attribute parsing requires handling - * of non-ASCII characters, or normalization compaction. + * parse a value for an attribute. + * NOTE: if no normalization is needed, the routine will return pointers + * directly from the data buffer. * - * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + * 3.3.3 Attribute-Value Normalization: + * Before the value of an attribute is passed to the application or + * checked for validity, the XML processor must normalize it as follows: + * - a character reference is processed by appending the referenced + * character to the attribute value + * - an entity reference is processed by recursively processing the + * replacement text of the entity + * - a whitespace character (#x20, #xD, #xA, #x9) is processed by + * appending #x20 to the normalized value, except that only a single + * #x20 is appended for a "#xD#xA" sequence that is part of an external + * parsed entity or the literal entity value of an internal parsed entity + * - other characters are processed by appending them to the normalized value + * If the declared value is not CDATA, then the XML processor must further + * process the normalized attribute value by discarding any leading and + * trailing space (#x20) characters, and by replacing sequences of space + * (#x20) characters by a single space (#x20) character. + * All attributes for which no declaration has been read should be treated + * by a non-validating parser as if declared CDATA. + * + * Returns the AttValue parsed or NULL. The value has to be freed by the + * caller if it was copied, this can be detected by val[*len] == 0. */ static xmlChar * -xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { - xmlChar limit = 0; - xmlChar *buf = NULL; - xmlChar *rep = NULL; - size_t len = 0; - size_t buf_size = 0; - int c, l, in_space = 0; - xmlChar *current = NULL; - xmlEntityPtr ent; +xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *attlen, int *alloc, + int normalize, int isNamespace) { + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + xmlChar *ret; + int c, l, quote, flags, chunkSize; + int inSpace = 1; + int replaceEntities; - if (NXT(0) == '"') { - ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; - limit = '"'; - NEXT; - } else if (NXT(0) == '\'') { - limit = '\''; - ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; - NEXT; - } else { + /* Always expand namespace URIs */ + replaceEntities = (ctxt->replaceEntities) || (isNamespace); + + xmlSBufInit(&buf, maxLength); + + GROW; + + quote = CUR; + if ((quote != '"') && (quote != '\'')) { xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); return(NULL); } + NEXTL(1); - /* - * allocate a translation buffer. - */ - buf_size = XML_PARSER_BUFFER_SIZE; - buf = (xmlChar *) xmlMallocAtomic(buf_size); - if (buf == NULL) goto mem_error; + if (ctxt->inSubset == 0) + flags = XML_ENT_CHECKED | XML_ENT_VALIDATED; + else + flags = XML_ENT_VALIDATED; - /* - * 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 != '<')) && - (ctxt->instate != XML_PARSER_EOF)) { - /* - * Impose a reasonable limit on attribute size, unless XML_PARSE_HUGE - * special option is given - */ - if ((len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + inSpace = 1; + chunkSize = 0; + + while (1) { + if (PARSER_STOPPED(ctxt)) + goto error; + + if (CUR_PTR >= ctxt->input->end) { xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - goto mem_error; + "AttValue: ' expected\n"); + goto error; } - if (c == '&') { - in_space = 0; - if (NXT(1) == '#') { - int val = xmlParseCharRef(ctxt); - - if (val == '&') { - if (ctxt->replaceEntities) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - buf[len++] = '&'; - } else { - /* - * The reparsing will be done in xmlStringGetNodeList() - * called by the attribute() function in SAX.c - */ - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - buf[len++] = '&'; - buf[len++] = '#'; - buf[len++] = '3'; - buf[len++] = '8'; - buf[len++] = ';'; - } - } else if (val != 0) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - len += xmlCopyChar(0, &buf[len], val); - } - } else { - ent = xmlParseEntityRef(ctxt); - ctxt->nbentities++; - if (ent != NULL) - ctxt->nbentities += ent->owner; - if ((ent != NULL) && - (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - if ((ctxt->replaceEntities == 0) && - (ent->content[0] == '&')) { - buf[len++] = '&'; - buf[len++] = '#'; - buf[len++] = '3'; - buf[len++] = '8'; - buf[len++] = ';'; - } else { - buf[len++] = ent->content[0]; - } - } else if ((ent != NULL) && - (ctxt->replaceEntities != 0)) { - if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) { - ++ctxt->depth; - rep = xmlStringDecodeEntities(ctxt, ent->content, - XML_SUBSTITUTE_REF, - 0, 0, 0); - --ctxt->depth; - if (rep != NULL) { - current = rep; - while (*current != 0) { /* non input consuming */ - if ((*current == 0xD) || (*current == 0xA) || - (*current == 0x9)) { - buf[len++] = 0x20; - current++; - } else - buf[len++] = *current++; - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - } - xmlFree(rep); - rep = NULL; - } - } else { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - if (ent->content != NULL) - buf[len++] = ent->content[0]; - } - } else if (ent != NULL) { - int i = xmlStrlen(ent->name); - const xmlChar *cur = ent->name; - /* - * This may look absurd but is needed to detect - * entities problems - */ - if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && - (ent->content != NULL) && (ent->checked == 0)) { - unsigned long oldnbent = ctxt->nbentities, diff; - - ++ctxt->depth; - rep = xmlStringDecodeEntities(ctxt, ent->content, - XML_SUBSTITUTE_REF, 0, 0, 0); - --ctxt->depth; - - diff = ctxt->nbentities - oldnbent + 1; - if (diff > INT_MAX / 2) - diff = INT_MAX / 2; - ent->checked = diff * 2; - if (rep != NULL) { - if (xmlStrchr(rep, '<')) - ent->checked |= 1; - xmlFree(rep); - rep = NULL; - } else { - ent->content[0] = 0; - } - } + /* + * TODO: Check growth threshold + */ + if (ctxt->input->end - CUR_PTR < 10) + GROW; + + c = CUR; + + if (c >= 0x80) { + l = xmlUTF8MultibyteLen(ctxt, CUR_PTR, + "invalid character in attribute value\n"); + if (l == 0) { + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + xmlSBufAddReplChar(&buf); + NEXTL(1); + } else { + chunkSize += l; + NEXTL(l); + } - /* - * Just output the reference - */ - buf[len++] = '&'; - while (len + i + 10 > buf_size) { - growBuffer(buf, i + 10); - } - for (;i > 0;i--) - buf[len++] = *cur++; - buf[len++] = ';'; - } - } - } 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 + 10 > buf_size) { - growBuffer(buf, 10); - } - } - in_space = 1; - } - } else { - in_space = 0; - COPY_BUF(l,buf,len,c); - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - } - NEXTL(l); + inSpace = 0; + } else if (c != '&') { + if (c > 0x20) { + if (c == quote) + break; + + if (c == '<') + xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); + + chunkSize += 1; + inSpace = 0; + } else if (!IS_BYTE_CHAR(c)) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in attribute value\n"); + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + xmlSBufAddReplChar(&buf); + inSpace = 0; + } else { + /* Whitespace */ + if ((normalize) && (inSpace)) { + /* Skip char */ + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + } else if (c < 0x20) { + /* Convert to space */ + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + xmlSBufAddCString(&buf, " ", 1); + } else { + chunkSize += 1; + } + + inSpace = 1; + + if ((c == 0xD) && (NXT(1) == 0xA)) + CUR_PTR++; + } + + NEXTL(1); + } else if (NXT(1) == '#') { + int val; + + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + val = xmlParseCharRef(ctxt); + if (val == 0) + goto error; + + if ((val == '&') && (!replaceEntities)) { + /* + * The reparsing will be done in xmlStringGetNodeList() + * called by the attribute() function in SAX.c + */ + xmlSBufAddCString(&buf, "&", 5); + inSpace = 0; + } else if (val == ' ') { + if ((!normalize) || (!inSpace)) + xmlSBufAddCString(&buf, " ", 1); + inSpace = 1; + } else { + xmlSBufAddChar(&buf, val); + inSpace = 0; + } + } else { + const xmlChar *name; + xmlEntityPtr ent; + + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) { + /* + * Probably a literal '&' which wasn't escaped. + * TODO: Handle gracefully in recovery mode. + */ + continue; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 1); + if (ent == NULL) + continue; + + if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) { + if ((ent->content[0] == '&') && (!replaceEntities)) + xmlSBufAddCString(&buf, "&", 5); + else + xmlSBufAddString(&buf, ent->content, ent->length); + inSpace = 0; + } else if (replaceEntities) { + xmlExpandEntityInAttValue(ctxt, &buf, ent->content, ent, + normalize, &inSpace, ctxt->inputNr, + /* check */ 1); + } else { + if ((ent->flags & flags) != flags) + xmlCheckEntityInAttValue(ctxt, ent, ctxt->inputNr); + + if (xmlParserEntityCheck(ctxt, ent->expandedSize)) { + ent->content[0] = 0; + goto error; + } + + /* + * Just output the reference + */ + xmlSBufAddCString(&buf, "&", 1); + xmlSBufAddString(&buf, ent->name, xmlStrlen(ent->name)); + xmlSBufAddCString(&buf, ";", 1); + + inSpace = 0; + } } - GROW; - c = CUR_CHAR(l); } - if (ctxt->instate == XML_PARSER_EOF) - goto error; - if ((in_space) && (normalize)) { - while ((len > 0) && (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 ((buf.mem == NULL) && (alloc != NULL)) { + ret = (xmlChar *) CUR_PTR - chunkSize; - /* - * There we potentially risk an overflow, don't allow attribute value of - * length more than INT_MAX it is a very reasonable assumption ! - */ - if (len >= INT_MAX) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - goto mem_error; + if (attlen != NULL) + *attlen = chunkSize; + if ((normalize) && (inSpace) && (chunkSize > 0)) + *attlen -= 1; + *alloc = 0; + + /* Report potential error */ + xmlSBufCleanup(&buf, ctxt, "AttValue length too long"); + } else { + if (chunkSize > 0) + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + + if ((normalize) && (inSpace) && (buf.size > 0)) + buf.size--; + + ret = xmlSBufFinish(&buf, attlen, ctxt, "AttValue length too long"); + + if (ret != NULL) { + if (attlen != NULL) + *attlen = buf.size; + if (alloc != NULL) + *alloc = 1; + } } - if (attlen != NULL) *attlen = (int) len; - return(buf); + NEXTL(1); + + return(ret); -mem_error: - xmlErrMemory(ctxt, NULL); error: - if (buf != NULL) - xmlFree(buf); - if (rep != NULL) - xmlFree(rep); + xmlSBufCleanup(&buf, ctxt, "AttValue length too long"); return(NULL); } @@ -4141,6 +4534,8 @@ error: * xmlParseAttValue: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse a value for an attribute * Note: the parser won't do substitution of entities here, this * will be handled later in xmlStringGetNodeList @@ -4174,13 +4569,15 @@ error: xmlChar * xmlParseAttValue(xmlParserCtxtPtr ctxt) { if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL); - return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0)); + return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0, 0)); } /** * xmlParseSystemLiteral: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML Literal * * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") @@ -4194,11 +4591,11 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { int len = 0; int size = XML_PARSER_BUFFER_SIZE; int cur, l; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; xmlChar stop; - int state = ctxt->instate; - int count = 0; - SHRINK; if (RAW == '"') { NEXT; stop = '"'; @@ -4210,55 +4607,35 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { return(NULL); } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } - ctxt->instate = XML_PARSER_SYSTEM_LITERAL; cur = CUR_CHAR(l); while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */ if (len + 5 >= size) { xmlChar *tmp; - if ((size > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral"); - xmlFree(buf); - ctxt->instate = (xmlParserInputState) state; - return(NULL); - } size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - xmlErrMemory(ctxt, NULL); - ctxt->instate = (xmlParserInputState) state; + xmlErrMemory(ctxt); return(NULL); } buf = tmp; } - count++; - if (count > 50) { - SHRINK; - GROW; - count = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); - } - } - COPY_BUF(l,buf,len,cur); + COPY_BUF(buf, len, cur); + if (len > maxLength) { + xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral"); + xmlFree(buf); + return(NULL); + } 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 { @@ -4271,6 +4648,8 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { * xmlParsePubidLiteral: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML public literal * * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" @@ -4283,12 +4662,12 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = XML_PARSER_BUFFER_SIZE; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; xmlChar cur; xmlChar stop; - int count = 0; - xmlParserInputState oldstate = ctxt->instate; - SHRINK; if (RAW == '"') { NEXT; stop = '"'; @@ -4299,62 +4678,45 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); return(NULL); } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } - ctxt->instate = XML_PARSER_PUBLIC_LITERAL; cur = CUR; - while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) { /* checked */ + while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop) && + (PARSER_STOPPED(ctxt) == 0)) { /* checked */ if (len + 1 >= size) { xmlChar *tmp; - if ((size > XML_MAX_NAME_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID"); - xmlFree(buf); - return(NULL); - } size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); return(NULL); } buf = tmp; } buf[len++] = cur; - count++; - if (count > 50) { - SHRINK; - GROW; - count = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); - } - } + if (len > maxLength) { + xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID"); + xmlFree(buf); + return(NULL); + } 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; + NEXTL(1); } - ctxt->instate = oldstate; return(buf); } -static void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata); +static void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial); /* * used for the test in the inner loop of the char data testing @@ -4395,12 +4757,12 @@ static const unsigned char test_char_data[256] = { }; /** - * xmlParseCharData: + * xmlParseCharDataInternal: * @ctxt: an XML parser context - * @cdata: int indicating whether we are within a CDATA section + * @partial: buffer may contain partial UTF-8 sequences * - * parse a CharData section. - * if we are within a CDATA section ']]>' marks an end of section. + * Parse character data. Always makes progress if the first char isn't + * '<' or '&'. * * The right angle bracket (>) may be represented using the string ">", * and must, for compatibility, be escaped using ">" or a character @@ -4409,147 +4771,142 @@ static const unsigned char test_char_data[256] = { * * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */ - -void -xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) { +static void +xmlParseCharDataInternal(xmlParserCtxtPtr ctxt, int partial) { 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; - } + */ + 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->disableSAX == 0) && + (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->disableSAX == 0) && + (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 + 1; - 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; - if (ctxt->instate == XML_PARSER_EOF) - return; - in = ctxt->input->cur; - } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); - nbchar = 0; - } + 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 + 1; + return; + } + in++; + ctxt->input->col++; + goto get_more; + } + nbchar = in - ctxt->input->cur; + if (nbchar > 0) { + if ((ctxt->sax != NULL) && + (ctxt->disableSAX == 0) && + (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) && + (ctxt->disableSAX == 0)) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + ctxt->input->cur, nbchar); + line = ctxt->input->line; + col = ctxt->input->col; + } + } + 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) || (*in == 0x0a)); ctxt->input->line = line; ctxt->input->col = col; - xmlParseCharDataComplex(ctxt, cdata); + xmlParseCharDataComplex(ctxt, partial); } /** @@ -4557,34 +4914,28 @@ get_more: * @ctxt: an XML parser context * @cdata: int indicating whether we are within a CDATA section * + * Always makes progress if the first char isn't '<' or '&'. + * * 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) { +xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial) { 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); - } + (IS_CHAR(cur))) { + if ((cur == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { + xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); } - COPY_BUF(l,buf,nbchar,cur); + COPY_BUF(buf, nbchar, cur); /* move current position before possible calling of ctxt->sax->characters */ NEXTL(l); - cur = CUR_CHAR(l); if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { buf[nbchar] = 0; @@ -4606,18 +4957,9 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { } } nbchar = 0; - /* something really bad happened in the SAX callback */ - if (ctxt->instate != XML_PARSER_CONTENT) - return; - } - count++; - if (count > 50) { - SHRINK; - GROW; - count = 0; - if (ctxt->instate == XML_PARSER_EOF) - return; + SHRINK; } + cur = CUR_CHAR(l); } if (nbchar != 0) { buf[nbchar] = 0; @@ -4637,15 +4979,41 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { } } } - 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); + /* + * cur == 0 can mean + * + * - End of buffer. + * - An actual 0 character. + * - An incomplete UTF-8 sequence. This is allowed if partial is set. + */ + if (ctxt->input->cur < ctxt->input->end) { + if ((cur == 0) && (CUR != 0)) { + if (partial == 0) { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "Incomplete UTF-8 sequence starting with %02X\n", CUR); + NEXTL(1); + } + } else if ((cur != '<') && (cur != '&')) { + /* Generate the error and skip the offending character */ + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "PCDATA invalid Char value %d\n", cur); + NEXTL(l); + } } } +/** + * xmlParseCharData: + * @ctxt: an XML parser context + * @cdata: unused + * + * DEPRECATED: Internal function, don't use. + */ +void +xmlParseCharData(xmlParserCtxtPtr ctxt, ATTRIBUTE_UNUSED int cdata) { + xmlParseCharDataInternal(ctxt, 0); +} + /** * xmlParseExternalID: * @ctxt: an XML parser context @@ -4653,6 +5021,8 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { * @strict: indicate whether we should restrict parsing to only * production [75], see NOTE below * + * DEPRECATED: Internal function, don't use. + * * Parse an External ID or a Public ID * * NOTE: Productions [75] and [83] interact badly since [75] can generate @@ -4672,8 +5042,6 @@ 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); @@ -4741,21 +5109,19 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, int q, ql; int r, rl; int cur, l; - size_t count = 0; - int inputid; - - inputid = ctxt->input->id; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; if (buf == NULL) { len = 0; size = XML_PARSER_BUFFER_SIZE; - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } } - GROW; /* Assure there's enough input data */ q = CUR_CHAR(ql); if (q == 0) goto not_terminated; @@ -4773,7 +5139,7 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, if (!IS_CHAR(r)) { xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, "xmlParseComment: invalid xmlChar value %d\n", - q); + r); xmlFree (buf); return; } @@ -4787,13 +5153,6 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, if ((r == '-') && (q == '-')) { xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); } - if ((len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, - "Comment too big found", NULL); - xmlFree (buf); - return; - } if (len + 5 >= size) { xmlChar *new_buf; size_t new_size; @@ -4802,35 +5161,28 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, new_buf = (xmlChar *) xmlRealloc(buf, new_size); if (new_buf == NULL) { xmlFree (buf); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } buf = new_buf; size = new_size; } - COPY_BUF(ql,buf,len,q); + COPY_BUF(buf, len, q); + if (len > maxLength) { + xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, + "Comment too big found", NULL); + xmlFree (buf); + return; + } + q = r; ql = rl; r = cur; rl = l; - count++; - if (count > 50) { - SHRINK; - GROW; - count = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } - } NEXTL(l); cur = CUR_CHAR(l); - if (cur == 0) { - SHRINK; - GROW; - cur = CUR_CHAR(l); - } + } buf[len] = 0; if (cur == 0) { @@ -4841,11 +5193,6 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, "xmlParseComment: invalid xmlChar value %d\n", cur); } else { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "Comment doesn't start and stop in the same" - " entity\n"); - } NEXT; if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) @@ -4864,7 +5211,10 @@ not_terminated: * xmlParseComment: * @ctxt: an XML parser context * - * Skip an XML (SGML) comment + * DEPRECATED: Internal function, don't use. + * + * Parse an XML (SGML) comment. Always consumes 'options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; const xmlChar *in; size_t nbchar = 0; int 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; + if ((RAW != '<') || (NXT(1) != '!')) + return; + SKIP(2); + if ((RAW != '-') || (NXT(1) != '-')) + return; + SKIP(2); GROW; /* @@ -4926,40 +5276,33 @@ get_more: * 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; - } + if (buf == NULL) { + if ((*in == '-') && (in[1] == '-')) + size = nbchar + 1; + else + size = XML_PARSER_BUFFER_SIZE + nbchar; + buf = (xmlChar *) xmlMallocAtomic(size); + if (buf == NULL) { + xmlErrMemory(ctxt); + 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); + if (new_buf == NULL) { + xmlFree (buf); + xmlErrMemory(ctxt); + return; + } + buf = new_buf; + } + memcpy(&buf[len], ctxt->input->cur, nbchar); + len += nbchar; + buf[len] = 0; } - if ((len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { + if (len > maxLength) { xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment too big found", NULL); xmlFree (buf); @@ -4982,19 +5325,10 @@ get_more: } SHRINK; GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } in = ctxt->input->cur; if (*in == '-') { if (in[1] == '-') { if (in[2] == '>') { - if (ctxt->input->id != inputid) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "comment doesn't start and stop in the" - " same entity\n"); - } SKIP(3); if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) { @@ -5005,8 +5339,6 @@ get_more: } if (buf != NULL) xmlFree(buf); - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; return; } if (buf != NULL) { @@ -5017,10 +5349,6 @@ get_more: } else xmlFatalErrMsgStr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, "Double hyphen within comment\n", NULL); - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } in++; ctxt->input->col++; } @@ -5030,7 +5358,6 @@ get_more: } } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); xmlParseCommentComplex(ctxt, buf, len, size); - ctxt->instate = state; return; } @@ -5039,6 +5366,8 @@ get_more: * xmlParsePITarget: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the name of a PI * * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) @@ -5129,6 +5458,12 @@ xmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) { goto error; if (URL != NULL) { + /* + * Unfortunately, the catalog API doesn't report OOM errors. + * xmlGetLastError isn't very helpful since we don't know + * where the last error came from. We'd have to reset it + * before this call and restore it afterwards. + */ ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL); xmlFree(URL); } @@ -5147,6 +5482,8 @@ error: * xmlParsePI: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML Processing Instruction. * * [16] PI ::= '' Char*)))? '?>' @@ -5159,20 +5496,17 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; size_t len = 0; size_t size = XML_PARSER_BUFFER_SIZE; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; int cur, l; const xmlChar *target; - xmlParserInputState state; - int count = 0; if ((RAW == '<') && (NXT(1) == '?')) { - int inputid = ctxt->input->id; - state = ctxt->instate; - ctxt->instate = XML_PARSER_PI; /* * this is a Processing Instruction. */ SKIP(2); - SHRINK; /* * Parse the target name and check for special support like @@ -5181,11 +5515,6 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { target = xmlParsePITarget(ctxt); if (target != NULL) { if ((RAW == '?') && (NXT(1) == '>')) { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "PI declaration doesn't start and stop in" - " the same entity\n"); - } SKIP(2); /* @@ -5195,14 +5524,11 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, NULL); - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; return; } - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - ctxt->instate = state; + xmlErrMemory(ctxt); return; } if (SKIP_BLANKS == 0) { @@ -5217,64 +5543,32 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { size_t new_size = size * 2; tmp = (xmlChar *) xmlRealloc(buf, new_size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); - ctxt->instate = state; return; } buf = tmp; size = new_size; } - count++; - if (count > 50) { - SHRINK; - GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } - count = 0; - if ((len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, - "PI %s too big found", target); - xmlFree(buf); - ctxt->instate = state; - return; - } - } - COPY_BUF(l,buf,len,cur); + COPY_BUF(buf, len, cur); + if (len > maxLength) { + xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, + "PI %s too big found", target); + xmlFree(buf); + return; + } NEXTL(l); cur = CUR_CHAR(l); - if (cur == 0) { - SHRINK; - GROW; - cur = CUR_CHAR(l); - } } - if ((len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, - "PI %s too big found", target); - xmlFree(buf); - ctxt->instate = state; - return; - } buf[len] = 0; if (cur != '?') { xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, "ParsePI: PI %s never end ...\n", target); } else { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "PI declaration doesn't start and stop in" - " the same entity\n"); - } SKIP(2); #ifdef LIBXML_CATALOG_ENABLED - if (((state == XML_PARSER_MISC) || - (state == XML_PARSER_START)) && + if ((ctxt->inSubset == 0) && (xmlStrEqual(target, XML_CATALOG_PI))) { xmlCatalogAllow allow = xmlCatalogGetDefaults(); if ((allow == XML_CATA_ALLOW_DOCUMENT) || @@ -5296,8 +5590,6 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { } else { xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL); } - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; } } @@ -5305,7 +5597,9 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { * xmlParseNotationDecl: * @ctxt: an XML parser context * - * parse a notation declaration + * DEPRECATED: Internal function, don't use. + * + * Parse a notation declaration. Always consumes '' * @@ -5323,11 +5617,14 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { xmlChar *Pubid; xmlChar *Systemid; - if (CMP10(CUR_PTR, '<', '!', 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { + if ((CUR != '<') || (NXT(1) != '!')) + return; + SKIP(2); + + if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { int inputid = ctxt->input->id; - SHRINK; - SKIP(10); - if (SKIP_BLANKS == 0) { + SKIP(8); + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '') { if (inputid != ctxt->input->id) { @@ -5377,7 +5674,9 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { * xmlParseEntityDecl: * @ctxt: an XML parser context * - * parse input->id; - SHRINK; - SKIP(8); - if (SKIP_BLANKS == 0) { + SKIP(6); + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'instate = XML_PARSER_ENTITY_DECL; /* * handle the various case of definitions... */ @@ -5459,34 +5760,16 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { - xmlURIPtr uri; - - uri = xmlParseURI((const char *) URI); - if (uri == NULL) { - xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, - "Invalid URI: %s\n", URI); - /* - * This really ought to be a well formedness error - * but the XML Core WG decided otherwise c.f. issue - * E26 of the XML erratas. - */ - } else { - if (uri->fragment != NULL) { - /* - * Okay this is foolish to block those but not - * invalid URIs. - */ - xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); - } else { - if ((ctxt->sax != NULL) && - (!ctxt->disableSAX) && - (ctxt->sax->entityDecl != NULL)) - ctxt->sax->entityDecl(ctxt->userData, name, - XML_EXTERNAL_PARAMETER_ENTITY, - literal, URI, NULL); - } - xmlFreeURI(uri); - } + if (xmlStrchr(URI, '#')) { + xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); + } else { + if ((ctxt->sax != NULL) && + (!ctxt->disableSAX) && + (ctxt->sax->entityDecl != NULL)) + ctxt->sax->entityDecl(ctxt->userData, name, + XML_EXTERNAL_PARAMETER_ENTITY, + literal, URI, NULL); + } } } } else { @@ -5505,14 +5788,19 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); - return; + xmlErrMemory(ctxt); + goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } - if (ctxt->myDoc->intSubset == NULL) + if (ctxt->myDoc->intSubset == NULL) { ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); + if (ctxt->myDoc->intSubset == NULL) { + xmlErrMemory(ctxt); + goto done; + } + } xmlSAX2EntityDecl(ctxt, name, XML_INTERNAL_GENERAL_ENTITY, NULL, NULL, value); @@ -5523,35 +5811,17 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { - xmlURIPtr uri; - - uri = xmlParseURI((const char *)URI); - if (uri == NULL) { - xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, - "Invalid URI: %s\n", URI); - /* - * This really ought to be a well formedness error - * but the XML Core WG decided otherwise c.f. issue - * E26 of the XML erratas. - */ - } else { - if (uri->fragment != NULL) { - /* - * Okay this is foolish to block those but not - * invalid URIs. - */ - xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); - } - xmlFreeURI(uri); - } + if (xmlStrchr(URI, '#')) { + xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); + } } - if ((RAW != '>') && (SKIP_BLANKS == 0)) { + if ((RAW != '>') && (SKIP_BLANKS_PE == 0)) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required before 'NDATA'\n"); } if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) { SKIP(5); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NDATA'\n"); } @@ -5576,15 +5846,20 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); - return; + xmlErrMemory(ctxt); + goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } - if (ctxt->myDoc->intSubset == NULL) + if (ctxt->myDoc->intSubset == NULL) { ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); + if (ctxt->myDoc->intSubset == NULL) { + xmlErrMemory(ctxt); + goto done; + } + } xmlSAX2EntityDecl(ctxt, name, XML_EXTERNAL_GENERAL_PARSED_ENTITY, literal, URI, NULL); @@ -5592,9 +5867,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { } } } - if (ctxt->instate == XML_PARSER_EOF) - goto done; - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, "xmlParseEntityDecl: entity %s not terminated\n", name); @@ -5644,6 +5917,8 @@ done: * @ctxt: an XML parser context * @value: Receive a possible fixed default value for the attribute * + * DEPRECATED: Internal function, don't use. + * * Parse an attribute default declaration * * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) @@ -5686,13 +5961,12 @@ xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) { if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) { SKIP(6); val = XML_ATTRIBUTE_FIXED; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '#FIXED'\n"); } } ret = xmlParseAttValue(ctxt); - ctxt->instate = XML_PARSER_DTD; if (ret == NULL) { xmlFatalErrMsg(ctxt, (xmlParserErrors)ctxt->errNo, "Attribute default value declaration error\n"); @@ -5705,6 +5979,8 @@ xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) { * xmlParseNotationType: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an Notation attribute type. * * Note: the leading 'NOTATION' S part has already being parsed... @@ -5727,10 +6003,9 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL); return(NULL); } - SHRINK; do { NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, @@ -5753,6 +6028,7 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { if (tmp == NULL) { cur = xmlCreateEnumeration(name); if (cur == NULL) { + xmlErrMemory(ctxt); xmlFreeEnumeration(ret); return(NULL); } @@ -5762,7 +6038,7 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { last = cur; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); @@ -5777,6 +6053,8 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { * xmlParseEnumerationType: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an Enumeration attribute type. * * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' @@ -5797,10 +6075,9 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_STARTED, NULL); return(NULL); } - SHRINK; do { NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; name = xmlParseNmtoken(ctxt); if (name == NULL) { xmlFatalErr(ctxt, XML_ERR_NMTOKEN_REQUIRED, NULL); @@ -5823,6 +6100,7 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { if (!xmlDictOwns(ctxt->dict, name)) xmlFree(name); if (cur == NULL) { + xmlErrMemory(ctxt); xmlFreeEnumeration(ret); return(NULL); } @@ -5832,7 +6110,7 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { last = cur; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_FINISHED, NULL); @@ -5847,6 +6125,8 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { * @ctxt: an XML parser context * @tree: the enumeration tree built while parsing * + * DEPRECATED: Internal function, don't use. + * * parse an Enumerated attribute type. * * [57] EnumeratedType ::= NotationType | Enumeration @@ -5861,7 +6141,7 @@ int xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { SKIP(8); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NOTATION'\n"); return(0); @@ -5880,6 +6160,8 @@ xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { * @ctxt: an XML parser context * @tree: the enumeration tree built while parsing * + * DEPRECATED: Internal function, don't use. + * * parse the Attribute list def for an element * * [54] AttType ::= StringType | TokenizedType | EnumeratedType @@ -5922,7 +6204,6 @@ xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { */ int xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { - SHRINK; if (CMP5(CUR_PTR, 'C', 'D', 'A', 'T', 'A')) { SKIP(5); return(XML_ATTRIBUTE_CDATA); @@ -5955,7 +6236,9 @@ xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { * xmlParseAttributeListDecl: * @ctxt: an XML parser context * - * : parse the Attribute list def for an element + * DEPRECATED: Internal function, don't use. + * + * Parse an attribute list declaration for an element. Always consumes '' * @@ -5968,11 +6251,15 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { const xmlChar *attrName; xmlEnumerationPtr tree; - if (CMP9(CUR_PTR, '<', '!', 'A', 'T', 'T', 'L', 'I', 'S', 'T')) { + if ((CUR != '<') || (NXT(1) != '!')) + return; + SKIP(2); + + if (CMP7(CUR_PTR, 'A', 'T', 'T', 'L', 'I', 'S', 'T')) { int inputid = ctxt->input->id; - SKIP(9); - if (SKIP_BLANKS == 0) { + SKIP(7); + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '') && (ctxt->instate != XML_PARSER_EOF)) { + while ((RAW != '>') && (PARSER_STOPPED(ctxt) == 0)) { int type; int def; xmlChar *defaultValue = NULL; @@ -5998,7 +6285,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { break; } GROW; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute name\n"); break; @@ -6010,7 +6297,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { } GROW; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute type\n"); if (tree != NULL) @@ -6031,7 +6318,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { GROW; if (RAW != '>') { - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute default value\n"); if (defaultValue != NULL) @@ -6076,6 +6363,8 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { * @ctxt: an XML parser context * @inputchk: the input used for the current entity, needed for boundary checks * + * DEPRECATED: Internal function, don't use. + * * parse the declaration for a Mixed Element content * The leading '(' and spaces have been skipped in xmlParseElementContentDecl * @@ -6098,8 +6387,7 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { GROW; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { SKIP(7); - SKIP_BLANKS; - SHRINK; + SKIP_BLANKS_PE; if (RAW == ')') { if (ctxt->input->id != inputchk) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, @@ -6109,7 +6397,7 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { NEXT; ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); if (ret == NULL) - return(NULL); + goto mem_error; if (RAW == '*') { ret->ocur = XML_ELEMENT_CONTENT_MULT; NEXT; @@ -6118,35 +6406,29 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { } if ((RAW == '(') || (RAW == '|')) { ret = cur = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); - if (ret == NULL) return(NULL); + if (ret == NULL) + goto mem_error; } - while ((RAW == '|') && (ctxt->instate != XML_PARSER_EOF)) { + while ((RAW == '|') && (PARSER_STOPPED(ctxt) == 0)) { NEXT; + n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); + if (n == NULL) + goto mem_error; if (elem == NULL) { - ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (ret == NULL) { - xmlFreeDocElementContent(ctxt->myDoc, cur); - return(NULL); - } - ret->c1 = cur; + n->c1 = cur; if (cur != NULL) - cur->parent = ret; - cur = ret; + cur->parent = n; + ret = cur = n; } else { - n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (n == NULL) { - xmlFreeDocElementContent(ctxt->myDoc, ret); - return(NULL); - } - n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); - if (n->c1 != NULL) - n->c1->parent = n; cur->c2 = n; - if (n != NULL) - n->parent = cur; + n->parent = cur; + n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); + if (n->c1 == NULL) + goto mem_error; + n->c1->parent = n; cur = n; } - SKIP_BLANKS; + SKIP_BLANKS_PE; elem = xmlParseName(ctxt); if (elem == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, @@ -6154,15 +6436,16 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } if ((RAW == ')') && (NXT(1) == '*')) { if (elem != NULL) { cur->c2 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); - if (cur->c2 != NULL) - cur->c2->parent = cur; + if (cur->c2 == NULL) + goto mem_error; + cur->c2->parent = cur; } if (ret != NULL) ret->ocur = XML_ELEMENT_CONTENT_MULT; @@ -6182,6 +6465,11 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { xmlFatalErr(ctxt, XML_ERR_PCDATA_REQUIRED, NULL); } return(ret); + +mem_error: + xmlErrMemory(ctxt); + xmlFreeDocElementContent(ctxt->myDoc, ret); + return(NULL); } /** @@ -6219,30 +6507,30 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { static xmlElementContentPtr xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL; const xmlChar *elem; xmlChar type = 0; - if (((depth > 128) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || - (depth > 2048)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED, -"xmlParseElementChildrenContentDecl : depth %d too deep, use XML_PARSE_HUGE\n", - depth); + if (depth > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "xmlParseElementChildrenContentDecl : depth %d too deep, " + "use XML_PARSE_HUGE\n", depth); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; if (RAW == '(') { int inputid = ctxt->input->id; /* Recurse on first child */ NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (cur == NULL) return(NULL); - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } else { elem = xmlParseName(ctxt); @@ -6252,7 +6540,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } cur = ret = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (cur == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } GROW; @@ -6270,9 +6558,8 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } GROW; } - SKIP_BLANKS; - SHRINK; - while ((RAW != ')') && (ctxt->instate != XML_PARSER_EOF)) { + SKIP_BLANKS_PE; + while ((RAW != ')') && (PARSER_STOPPED(ctxt) == 0)) { /* * Each loop we parse one separator and one element. */ @@ -6296,6 +6583,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_SEQ); if (op == NULL) { + xmlErrMemory(ctxt); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); xmlFreeDocElementContent(ctxt->myDoc, ret); @@ -6336,6 +6624,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); if (op == NULL) { + xmlErrMemory(ctxt); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) @@ -6366,13 +6655,13 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, return(NULL); } GROW; - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; if (RAW == '(') { int inputid = ctxt->input->id; /* Recurse on second child */ NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (last == NULL) { @@ -6380,7 +6669,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; } else { elem = xmlParseName(ctxt); if (elem == NULL) { @@ -6391,6 +6680,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } last = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (last == NULL) { + xmlErrMemory(ctxt); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); @@ -6408,7 +6698,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, last->ocur = XML_ELEMENT_CONTENT_ONCE; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } if ((cur != NULL) && (last != NULL)) { @@ -6494,6 +6784,8 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, * @ctxt: an XML parser context * @inputchk: the input used for the current entity, needed for boundary checks * + * DEPRECATED: Internal function, don't use. + * * parse the declaration for a Mixed Element content * The leading '(' and spaces have been skipped in xmlParseElementContentDecl * @@ -6531,6 +6823,8 @@ xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { * @name: the name of the element being defined. * @result: the Element Content pointer will be stored here if any * + * DEPRECATED: Internal function, don't use. + * * parse the declaration for an Element content either Mixed or Children, * the cases EMPTY and ANY are handled directly in xmlParseElementDecl * @@ -6556,9 +6850,7 @@ xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, } NEXT; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(-1); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { tree = xmlParseElementMixedContentDecl(ctxt, inputid); res = XML_ELEMENT_TYPE_MIXED; @@ -6566,7 +6858,7 @@ xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, tree = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, 1); res = XML_ELEMENT_TYPE_ELEMENT; } - SKIP_BLANKS; + SKIP_BLANKS_PE; *result = tree; return(res); } @@ -6575,7 +6867,9 @@ xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, * xmlParseElementDecl: * @ctxt: an XML parser context * - * parse an Element declaration. + * DEPRECATED: Internal function, don't use. + * + * Parse an element declaration. Always consumes '' * @@ -6590,12 +6884,16 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { int ret = -1; xmlElementContentPtr content = NULL; + if ((CUR != '<') || (NXT(1) != '!')) + return(ret); + SKIP(2); + /* GROW; done in the caller */ - if (CMP9(CUR_PTR, '<', '!', 'E', 'L', 'E', 'M', 'E', 'N', 'T')) { + if (CMP7(CUR_PTR, 'E', 'L', 'E', 'M', 'E', 'N', 'T')) { int inputid = ctxt->input->id; - SKIP(9); - if (SKIP_BLANKS == 0) { + SKIP(7); + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'ELEMENT'\n"); return(-1); @@ -6606,7 +6904,7 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { "xmlParseElementDecl: no name for Element\n"); return(-1); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the element name\n"); } @@ -6629,18 +6927,12 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { /* * [ WFC: PEs in Internal Subset ] error handling. */ - if ((RAW == '%') && (ctxt->external == 0) && - (ctxt->inputNr == 1)) { - xmlFatalErrMsg(ctxt, XML_ERR_PEREF_IN_INT_SUBSET, - "PEReference: forbidden within markup decl in internal subset\n"); - } else { - xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, - "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n"); - } + xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, + "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n"); return(-1); } - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '>') { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); @@ -6682,6 +6974,8 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { * xmlParseConditionalSections * @ctxt: an XML parser context * + * Parse a conditional section. Always consumes '' * [63] ignoreSect ::= '' @@ -6695,16 +6989,16 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { size_t inputIdsSize = 0; size_t depth = 0; - while (ctxt->instate != XML_PARSER_EOF) { + while (PARSER_STOPPED(ctxt) == 0) { if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { int id = ctxt->input->id; SKIP(3); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (CMP7(CUR_PTR, 'I', 'N', 'C', 'L', 'U', 'D', 'E')) { SKIP(7); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); @@ -6724,7 +7018,7 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { tmp = (int *) xmlRealloc(inputIds, inputIdsSize * sizeof(int)); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto error; } inputIds = tmp; @@ -6732,12 +7026,10 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { inputIds[depth] = id; depth++; } else if (CMP6(CUR_PTR, 'I', 'G', 'N', 'O', 'R', 'E')) { - int state; - xmlParserInputState instate; size_t ignoreDepth = 0; SKIP(6); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); @@ -6750,48 +7042,35 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { } NEXT; - /* - * Parse up to the end of the conditional section but disable - * SAX event generating DTD building in the meantime - */ - state = ctxt->disableSAX; - instate = ctxt->instate; - if (ctxt->recovery == 0) ctxt->disableSAX = 1; - ctxt->instate = XML_PARSER_IGNORE; - - while (RAW != 0) { + while (PARSER_STOPPED(ctxt) == 0) { + if (RAW == 0) { + xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); + goto error; + } if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { SKIP(3); ignoreDepth++; /* Check for integer overflow */ if (ignoreDepth == 0) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto error; } } else if ((RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { + SKIP(3); if (ignoreDepth == 0) break; - SKIP(3); ignoreDepth--; } else { NEXT; } } - ctxt->disableSAX = state; - ctxt->instate = instate; - - if (RAW == 0) { - xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); - goto error; - } if (ctxt->input->id != id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is" " not in the same entity\n"); } - SKIP(3); } else { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID_KEYWORD, NULL); xmlHaltParser(ctxt); @@ -6806,23 +7085,19 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { " in the same entity\n"); } SKIP(3); - } else { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; - + } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { xmlParseMarkupDecl(ctxt); - - if ((id == ctxt->input->id) && (cons == CUR_CONSUMED)) { - xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); - xmlHaltParser(ctxt); - goto error; - } + } else { + xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); + xmlHaltParser(ctxt); + goto error; } if (depth == 0) break; - SKIP_BLANKS; + SKIP_BLANKS_PE; + SHRINK; GROW; } @@ -6834,7 +7109,9 @@ error: * xmlParseMarkupDecl: * @ctxt: an XML parser context * - * parse Markup declarations + * DEPRECATED: Internal function, don't use. + * + * Parse markup declarations. Always consumes 'instate == XML_PARSER_EOF) - return; - - ctxt->instate = XML_PARSER_DTD; } /** * xmlParseTextDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML declaration header for external entities * * [77] TextDecl ::= '' @@ -6904,8 +7177,6 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { void xmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlChar *version; - const xmlChar *encoding; - int oldstate; /* * We know that 'instate; - ctxt->instate = XML_PARSER_START; - if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed after 'errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right here - */ - ctxt->instate = oldstate; - return; - } - if ((encoding == NULL) && (ctxt->errNo == XML_ERR_OK)) { - xmlFatalErrMsg(ctxt, XML_ERR_MISSING_ENCODING, - "Missing encoding in text declaration\n"); - } + xmlParseEncodingDecl(ctxt); SKIP_BLANKS; if ((RAW == '?') && (NXT(1) == '>')) { @@ -6964,12 +7224,15 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); NEXT; } else { + int c; + xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); - MOVETO_ENDTAG(CUR_PTR); - NEXT; + while ((PARSER_STOPPED(ctxt) == 0) && ((c = CUR) != 0)) { + NEXT; + if (c == '>') + break; + } } - - ctxt->instate = oldstate; } /** @@ -6987,91 +7250,76 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { void xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, const xmlChar *SystemID) { - xmlDetectSAX2(ctxt); - GROW; + int oldInputNr; - if ((ctxt->encoding == NULL) && - (ctxt->input->end - ctxt->input->cur >= 4)) { - xmlChar start[4]; - xmlCharEncoding enc; + xmlCtxtInitializeLate(ctxt); - 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); - } + xmlDetectEncoding(ctxt); if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) { xmlParseTextDecl(ctxt); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right here - */ - xmlHaltParser(ctxt); - return; - } } if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); return; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } - if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL)) - xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID); + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL) && + (xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID) == NULL)) { + xmlErrMemory(ctxt); + } - ctxt->instate = XML_PARSER_DTD; - ctxt->external = 1; - SKIP_BLANKS; - while (((RAW == '<') && (NXT(1) == '?')) || - ((RAW == '<') && (NXT(1) == '!')) || - (RAW == '%')) { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; + ctxt->inSubset = 2; + oldInputNr = ctxt->inputNr; + SKIP_BLANKS_PE; + while (((RAW != 0) || (ctxt->inputNr > oldInputNr)) && + (!PARSER_STOPPED(ctxt))) { GROW; if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { - xmlParseConditionalSections(ctxt); - } else - xmlParseMarkupDecl(ctxt); - SKIP_BLANKS; - - if ((id == ctxt->input->id) && (cons == CUR_CONSUMED)) { - xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); - break; - } + xmlParseConditionalSections(ctxt); + } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { + xmlParseMarkupDecl(ctxt); + } else { + xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); + xmlHaltParser(ctxt); + return; + } + SKIP_BLANKS_PE; + SHRINK; } + while (ctxt->inputNr > oldInputNr) + xmlPopPE(ctxt); + if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); } - } /** * xmlParseReference: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse and handle entity references in content, depending on the SAX * interface, this may end-up in a call to character() if this is a * CharRef, a predefined entity, if there is no reference() callback. * or if the parser was asked to switch to that mode. * + * Always consumes '&'. + * * [67] Reference ::= EntityRef | CharRef */ void xmlParseReference(xmlParserCtxtPtr ctxt) { - xmlEntityPtr ent; + xmlEntityPtr ent = NULL; + const xmlChar *name; xmlChar *val; - int was_checked; - xmlNodePtr list = NULL; - xmlParserErrors ret = XML_ERR_OK; - if (RAW != '&') return; @@ -7082,53 +7330,43 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { if (NXT(1) == '#') { int i = 0; xmlChar out[16]; - int hex = NXT(2); int value = xmlParseCharRef(ctxt); if (value == 0) return; - if (ctxt->charset != XML_CHAR_ENCODING_UTF8) { - /* - * So we are using non-UTF-8 buffers - * Check that the char fit on 8bits, if not - * generate a CharRef. - */ - if (value <= 0xFF) { - out[0] = value; - out[1] = 0; - if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && - (!ctxt->disableSAX)) - ctxt->sax->characters(ctxt->userData, out, 1); - } else { - if ((hex == 'x') || (hex == 'X')) - snprintf((char *)out, sizeof(out), "#x%X", value); - else - snprintf((char *)out, sizeof(out), "#%d", value); - if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && - (!ctxt->disableSAX)) - ctxt->sax->reference(ctxt->userData, out); - } - } else { - /* - * Just encode the value in UTF-8 - */ - COPY_BUF(0 ,out, i, value); - out[i] = 0; - if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && - (!ctxt->disableSAX)) - ctxt->sax->characters(ctxt->userData, out, i); - } + + /* + * Just encode the value in UTF-8 + */ + COPY_BUF(out, i, value); + out[i] = 0; + if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && + (!ctxt->disableSAX)) + ctxt->sax->characters(ctxt->userData, out, i); return; } /* * We are seeing an entity reference */ - ent = xmlParseEntityRef(ctxt); - if (ent == NULL) return; + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) + return; + ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 0); + if (ent == NULL) { + /* + * Create a reference for undeclared entities. + */ + if ((ctxt->replaceEntities == 0) && + (ctxt->sax != NULL) && + (ctxt->disableSAX == 0) && + (ctxt->sax->reference != NULL)) { + ctxt->sax->reference(ctxt->userData, name); + } + return; + } if (!ctxt->wellFormed) return; - was_checked = ent->checked; /* special case of predefined entities */ if ((ent->name == NULL) || @@ -7144,6 +7382,14 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { return; } + /* + * Some users try to parse entities on their own and used to set + * the renamed "checked" member. Fix the flags to cover this + * case. + */ + if (((ent->flags & XML_ENT_PARSED) == 0) && (ent->children != NULL)) + ent->flags |= XML_ENT_PARSED; + /* * The first reference to the entity trigger a parsing phase * where the ent->children is filled with the result from @@ -7153,393 +7399,220 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { * of validating, or substituting entities were given. Doing so is * far more secure as the parser will only process data coming from * the document entity by default. - */ - if (((ent->checked == 0) || - ((ent->children == NULL) && (ctxt->options & XML_PARSE_NOENT))) && - ((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) || - (ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) { - unsigned long oldnbent = ctxt->nbentities, diff; - - /* - * This is a bit hackish but this seems the best - * way to make sure both SAX and DOM entity support - * behaves okay. - */ - void *user_data; - if (ctxt->userData == ctxt) - user_data = NULL; - else - user_data = ctxt->userData; - - /* - * Check that this entity is well formed - * 4.3.2: An internal general parsed entity is well-formed - * if its replacement text matches the production labeled - * content. - */ - if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { - ctxt->depth++; - ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content, - user_data, &list); - ctxt->depth--; - - } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { - ctxt->depth++; - ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax, - user_data, ctxt->depth, ent->URI, - ent->ExternalID, &list); - ctxt->depth--; - } else { - ret = XML_ERR_ENTITY_PE_INTERNAL; - xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, - "invalid entity type found\n", NULL); - } - - /* - * Store the number of entities needing parsing for this entity - * content and do checkings - */ - diff = ctxt->nbentities - oldnbent + 1; - if (diff > INT_MAX / 2) - diff = INT_MAX / 2; - ent->checked = diff * 2; - if ((ent->content != NULL) && (xmlStrchr(ent->content, '<'))) - ent->checked |= 1; - if (ret == XML_ERR_ENTITY_LOOP) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - xmlHaltParser(ctxt); - xmlFreeNodeList(list); - return; - } - if (xmlParserEntityCheck(ctxt, 0, ent, 0)) { - xmlFreeNodeList(list); - return; - } - - if ((ret == XML_ERR_OK) && (list != NULL)) { - if (((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY))&& - (ent->children == NULL)) { - ent->children = list; - /* - * Prune it directly in the generated document - * except for single text nodes. - */ - if ((ctxt->replaceEntities == 0) || - (ctxt->parseMode == XML_PARSE_READER) || - ((list->type == XML_TEXT_NODE) && - (list->next == NULL))) { - ent->owner = 1; - while (list != NULL) { - list->parent = (xmlNodePtr) ent; - if (list->doc != ent->doc) - xmlSetTreeDoc(list, ent->doc); - if (list->next == NULL) - ent->last = list; - list = list->next; - } - list = NULL; - } else { - ent->owner = 0; - while (list != NULL) { - list->parent = (xmlNodePtr) ctxt->node; - list->doc = ctxt->myDoc; - if (list->next == NULL) - ent->last = list; - list = list->next; - } - list = ent->children; -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, list, NULL); -#endif /* LIBXML_LEGACY_ENABLED */ - } - } else { - xmlFreeNodeList(list); - list = NULL; - } - } else if ((ret != XML_ERR_OK) && - (ret != XML_WAR_UNDECLARED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' failed to parse\n", ent->name); - if (ent->content != NULL) - ent->content[0] = 0; - xmlParserEntityCheck(ctxt, 0, ent, 0); - } else if (list != NULL) { - xmlFreeNodeList(list); - list = NULL; - } - if (ent->checked == 0) - ent->checked = 2; - - /* Prevent entity from being parsed and expanded twice (Bug 760367). */ - was_checked = 0; - } else if (ent->checked != 1) { - ctxt->nbentities += ent->checked / 2; + * + * FIXME: This doesn't work correctly since entities can be + * expanded with different namespace declarations in scope. + * For example: + * + * "> + * ]> + * + * + * &ent; + * + * + * &ent; + * + * + * + * Proposed fix: + * + * - Ignore current namespace declarations when parsing the + * entity. If a prefix can't be resolved, don't report an error + * but mark it as unresolved. + * - Try to resolve these prefixes when expanding the entity. + * This will require a specialized version of xmlStaticCopyNode + * which can also make use of the namespace hash table to avoid + * quadratic behavior. + * + * Alternatively, we could simply reparse the entity on each + * expansion like we already do with custom SAX callbacks. + * External entity content should be cached in this case. + */ + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (((ctxt->options & XML_PARSE_NO_XXE) == 0) && + ((ctxt->replaceEntities) || + (ctxt->validate)))) { + if ((ent->flags & XML_ENT_PARSED) == 0) { + xmlCtxtParseEntity(ctxt, ent); + } else if (ent->children == NULL) { + /* + * Probably running in SAX mode and the callbacks don't + * build the entity content. Parse the entity again. + * + * This will also be triggered in normal tree builder mode + * if an entity happens to be empty, causing unnecessary + * reloads. It's hard to come up with a reliable check in + * which mode we're running. + */ + xmlCtxtParseEntity(ctxt, ent); + } } /* - * Now that the entity content has been gathered - * provide it to the application, this can take different forms based - * on the parsing modes. + * We also check for amplification if entities aren't substituted. + * They might be expanded later. */ - if (ent->children == NULL) { - /* - * Probably running in SAX mode and the callbacks don't - * build the entity content. So unless we already went - * though parsing for first checking go though the entity - * content to generate callbacks associated to the entity - */ - if (was_checked != 0) { - void *user_data; - /* - * This is a bit hackish but this seems the best - * way to make sure both SAX and DOM entity support - * behaves okay. - */ - if (ctxt->userData == ctxt) - user_data = NULL; - else - user_data = ctxt->userData; - - if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { - ctxt->depth++; - ret = xmlParseBalancedChunkMemoryInternal(ctxt, - ent->content, user_data, NULL); - ctxt->depth--; - } else if (ent->etype == - XML_EXTERNAL_GENERAL_PARSED_ENTITY) { - ctxt->depth++; - ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, - ctxt->sax, user_data, ctxt->depth, - ent->URI, ent->ExternalID, NULL); - ctxt->depth--; - } else { - ret = XML_ERR_ENTITY_PE_INTERNAL; - xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, - "invalid entity type found\n", NULL); - } - if (ret == XML_ERR_ENTITY_LOOP) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - return; - } - } - if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && - (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { - /* - * Entity reference callback comes second, it's somewhat - * superfluous but a compatibility to historical behaviour - */ - ctxt->sax->reference(ctxt->userData, ent->name); - } - return; - } + if (xmlParserEntityCheck(ctxt, ent->expandedSize)) + return; - /* - * If we didn't get any children for the entity being built - */ - if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && - (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { + if ((ctxt->sax == NULL) || (ctxt->disableSAX)) + return; + + if (ctxt->replaceEntities == 0) { /* - * Create a node. + * Create a reference */ - ctxt->sax->reference(ctxt->userData, ent->name); - return; - } + if (ctxt->sax->reference != NULL) + ctxt->sax->reference(ctxt->userData, ent->name); + } else if ((ent->children != NULL) && (ctxt->node != NULL)) { + xmlNodePtr copy, cur; - if ((ctxt->replaceEntities) || (ent->children == NULL)) { - /* - * There is a problem on the handling of _private for entities - * (bug 155816): Should we copy the content of the field from - * the entity (possibly overwriting some value set by the user - * when a copy is created), should we leave it alone, or should - * we try to take care of different situations? The problem - * is exacerbated by the usage of this field by the xmlReader. - * To fix this bug, we look at _private on the created node - * and, if it's NULL, we copy in whatever was in the entity. - * If it's not NULL we leave it alone. This is somewhat of a - * hack - maybe we should have further tests to determine - * what to do. + /* + * Seems we are generating the DOM content, copy the tree */ - if ((ctxt->node != NULL) && (ent->children != NULL)) { - /* - * Seems we are generating the DOM content, do - * a simple tree copy for all references except the first - * In the first occurrence list contains the replacement. - */ - if (((list == NULL) && (ent->owner == 0)) || - (ctxt->parseMode == XML_PARSE_READER)) { - xmlNodePtr nw = NULL, cur, firstChild = NULL; + cur = ent->children; - /* - * We are copying here, make sure there is no abuse - */ - ctxt->sizeentcopy += ent->length + 5; - if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) - return; + /* + * Handle first text node with SAX to coalesce text efficiently + */ + if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + int len = xmlStrlen(cur->content); + + if ((cur->type == XML_TEXT_NODE) || + (ctxt->sax->cdataBlock == NULL)) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt, cur->content, len); + } else { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt, cur->content, len); + } - /* - * when operating on a reader, the entities definitions - * are always owning the entities subtree. - if (ctxt->parseMode == XML_PARSE_READER) - ent->owner = 1; - */ + cur = cur->next; + } - cur = ent->children; - while (cur != NULL) { - nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); - if (nw != NULL) { - if (nw->_private == NULL) - nw->_private = cur->_private; - if (firstChild == NULL){ - firstChild = nw; - } - nw = xmlAddChild(ctxt->node, nw); - } - if (cur == ent->last) { - /* - * needed to detect some strange empty - * node cases in the reader tests - */ - if ((ctxt->parseMode == XML_PARSE_READER) && - (nw != NULL) && - (nw->type == XML_ELEMENT_NODE) && - (nw->children == NULL)) - nw->extra = 1; + while (cur != NULL) { + xmlNodePtr last; - break; - } - cur = cur->next; - } -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, firstChild, nw); -#endif /* LIBXML_LEGACY_ENABLED */ - } else if ((list == NULL) || (ctxt->inputNr > 0)) { - xmlNodePtr nw = NULL, cur, next, last, - firstChild = NULL; + /* + * Handle last text node with SAX to coalesce text efficiently + */ + if ((cur->next == NULL) && + ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE))) { + int len = xmlStrlen(cur->content); + + if ((cur->type == XML_TEXT_NODE) || + (ctxt->sax->cdataBlock == NULL)) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt, cur->content, len); + } else { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt, cur->content, len); + } - /* - * We are copying here, make sure there is no abuse - */ - ctxt->sizeentcopy += ent->length + 5; - if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) - return; + break; + } - /* - * Copy the entity child list and make it the new - * entity child list. The goal is to make sure any - * ID or REF referenced will be the one from the - * document content and not the entity copy. - */ - cur = ent->children; - ent->children = NULL; - last = ent->last; - ent->last = NULL; - while (cur != NULL) { - next = cur->next; - cur->next = NULL; - cur->parent = NULL; - nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); - if (nw != NULL) { - if (nw->_private == NULL) - nw->_private = cur->_private; - if (firstChild == NULL){ - firstChild = cur; - } - xmlAddChild((xmlNodePtr) ent, nw); - xmlAddChild(ctxt->node, cur); - } - if (cur == last) - break; - cur = next; - } - if (ent->owner == 0) - ent->owner = 1; -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, firstChild, nw); -#endif /* LIBXML_LEGACY_ENABLED */ - } else { - const xmlChar *nbktext; + /* + * Reset coalesce buffer stats only for non-text nodes. + */ + ctxt->nodemem = 0; + ctxt->nodelen = 0; - /* - * the name change is to avoid coalescing of the - * node with a possible previous text one which - * would make ent->children a dangling pointer - */ - nbktext = xmlDictLookup(ctxt->dict, BAD_CAST "nbktext", - -1); - if (ent->children->type == XML_TEXT_NODE) - ent->children->name = nbktext; - if ((ent->last != ent->children) && - (ent->last->type == XML_TEXT_NODE)) - ent->last->name = nbktext; - xmlAddChildList(ctxt->node, ent->children); - } + copy = xmlDocCopyNode(cur, ctxt->myDoc, 1); - /* - * This is to avoid a nasty side effect, see - * characters() in SAX.c - */ - ctxt->nodemem = 0; - ctxt->nodelen = 0; - return; - } - } -} + if (copy == NULL) { + xmlErrMemory(ctxt); + break; + } -/** - * xmlParseEntityRef: - * @ctxt: an XML parser context - * - * parse ENTITY references declarations - * - * [68] EntityRef ::= '&' Name ';' - * - * [ WFC: Entity Declared ] - * In a document without any DTD, a document with only an internal DTD - * subset which contains no parameter entity references, or a document - * with "standalone='yes'", the Name given in the entity reference - * must match that in an entity declaration, except that well-formed - * documents need not declare any of the following entities: amp, lt, - * gt, apos, quot. The declaration of a parameter entity must precede - * any reference to it. Similarly, the declaration of a general entity - * must precede any reference to it which appears in a default value in an - * attribute-list declaration. Note that if entities are declared in the - * external subset or in external parameter entities, a non-validating - * processor is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be declared is a - * well-formedness constraint only if standalone='yes'. - * - * [ WFC: Parsed Entity ] - * An entity reference must not contain the name of an unparsed entity - * - * Returns the xmlEntityPtr if found, or NULL otherwise. - */ -xmlEntityPtr -xmlParseEntityRef(xmlParserCtxtPtr ctxt) { - const xmlChar *name; - xmlEntityPtr ent = NULL; + if (ctxt->parseMode == XML_PARSE_READER) { + /* Needed for reader */ + copy->extra = cur->extra; + /* Maybe needed for reader */ + copy->_private = cur->_private; + } - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); + copy->parent = ctxt->node; + last = ctxt->node->last; + if (last == NULL) { + ctxt->node->children = copy; + } else { + last->next = copy; + copy->prev = last; + } + ctxt->node->last = copy; - if (RAW != '&') - return(NULL); - NEXT; - name = xmlParseName(ctxt); - if (name == NULL) { - xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, - "xmlParseEntityRef: no name\n"); - return(NULL); + cur = cur->next; + } } - if (RAW != ';') { - xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); - return(NULL); +} + +static void +xmlHandleUndeclaredEntity(xmlParserCtxtPtr ctxt, const xmlChar *name) { + /* + * [ WFC: Entity Declared ] + * In a document without any DTD, a document with only an + * internal DTD subset which contains no parameter entity + * references, or a document with "standalone='yes'", the + * Name given in the entity reference must match that in an + * entity declaration, except that well-formed documents + * need not declare any of the following entities: amp, lt, + * gt, apos, quot. + * The declaration of a parameter entity must precede any + * reference to it. + * Similarly, the declaration of a general entity must + * precede any reference to it which appears in a default + * value in an attribute-list declaration. Note that if + * entities are declared in the external subset or in + * external parameter entities, a non-validating processor + * is not obligated to read and process their declarations; + * for such documents, the rule that an entity must be + * declared is a well-formedness constraint only if + * standalone='yes'. + */ + if ((ctxt->standalone == 1) || + ((ctxt->hasExternalSubset == 0) && + (ctxt->hasPErefs == 0))) { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name); + } else if (ctxt->validate) { + /* + * [ VC: Entity Declared ] + * In a document with an external subset or external + * parameter entities with "standalone='no'", ... + * ... The declaration of a parameter entity must + * precede any reference to it... + */ + xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name, NULL); + } else if ((ctxt->loadsubset) || + ((ctxt->replaceEntities) && + ((ctxt->options & XML_PARSE_NO_XXE) == 0))) { + /* + * Also raise a non-fatal error + * + * - if the external subset is loaded and all entity declarations + * should be available, or + * - entity substition was requested without restricting + * external entity access. + */ + xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name); + } else { + xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name, NULL); } - NEXT; + + ctxt->valid = 0; +} + +static xmlEntityPtr +xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) { + xmlEntityPtr ent; /* * Predefined entities override any extra definition @@ -7550,11 +7623,6 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { return(ent); } - /* - * Increase the number of entity references parsed - */ - ctxt->nbentities++; - /* * Ask first SAX for entity resolution, otherwise try the * entities which may have stored in the parser context. @@ -7570,46 +7638,9 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { ent = xmlSAX2GetEntity(ctxt, name); } } - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - /* - * [ WFC: Entity Declared ] - * In a document without any DTD, a document with only an - * internal DTD subset which contains no parameter entity - * references, or a document with "standalone='yes'", the - * Name given in the entity reference must match that in an - * entity declaration, except that well-formed documents - * need not declare any of the following entities: amp, lt, - * gt, apos, quot. - * The declaration of a parameter entity must precede any - * reference to it. - * Similarly, the declaration of a general entity must - * precede any reference to it which appears in a default - * value in an attribute-list declaration. Note that if - * entities are declared in the external subset or in - * external parameter entities, a non-validating processor - * is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be - * declared is a well-formedness constraint only if - * standalone='yes'. - */ + if (ent == NULL) { - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && - (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - } else { - xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - if ((ctxt->inSubset == 0) && - (ctxt->sax != NULL) && - (ctxt->sax->reference != NULL)) { - ctxt->sax->reference(ctxt->userData, name); - } - } - xmlParserEntityCheck(ctxt, 0, ent, 0); - ctxt->valid = 0; + xmlHandleUndeclaredEntity(ctxt, name); } /* @@ -7620,6 +7651,7 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, "Entity reference to unparsed entity %s\n", name); + ent = NULL; } /* @@ -7627,50 +7659,72 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { * Attribute values cannot contain direct or indirect * entity references to external entities. */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, - "Attribute references external entity '%s'\n", name); - } - /* - * [ WFC: No < in Attribute Values ] - * The replacement text of any entity referred to directly or - * indirectly in an attribute value (other than "<") must - * not contain a <. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent != NULL) && - (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { - if (((ent->checked & 1) || (ent->checked == 0)) && - (ent->content != NULL) && (xmlStrchr(ent->content, '<'))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, - "'<' in entity '%s' is not allowed in attributes values\n", name); + else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { + if (inAttr) { + xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, + "Attribute references external entity '%s'\n", name); + ent = NULL; } } - /* - * Internal check, no parameter entities here ... - */ - else { - switch (ent->etype) { - case XML_INTERNAL_PARAMETER_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, - "Attempt to reference the parameter entity '%s'\n", - name); - break; - default: - break; - } + return(ent); +} + +/** + * xmlParseEntityRefInternal: + * @ctxt: an XML parser context + * @inAttr: whether we are in an attribute value + * + * Parse an entity reference. Always consumes '&'. + * + * [68] EntityRef ::= '&' Name ';' + * + * Returns the name, or NULL in case of error. + */ +static const xmlChar * +xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + + GROW; + + if (RAW != '&') + return(NULL); + NEXT; + name = xmlParseName(ctxt); + if (name == NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, + "xmlParseEntityRef: no name\n"); + return(NULL); + } + if (RAW != ';') { + xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); + return(NULL); } + NEXT; - /* - * [ WFC: No Recursion ] - * A parsed entity must not contain a recursive reference - * to itself, either directly or indirectly. - * Done somewhere else - */ - return(ent); + return(name); +} + +/** + * xmlParseEntityRef: + * @ctxt: an XML parser context + * + * DEPRECATED: Internal function, don't use. + * + * Returns the xmlEntityPtr if found, or NULL otherwise. + */ +xmlEntityPtr +xmlParseEntityRef(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + + if (ctxt == NULL) + return(NULL); + + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) + return(NULL); + + return(xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 0)); } /** @@ -7704,12 +7758,11 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer * is updated to the current location in the string. */ -static xmlEntityPtr +static xmlChar * xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { xmlChar *name; const xmlChar *ptr; xmlChar cur; - xmlEntityPtr ent = NULL; if ((str == NULL) || (*str == NULL)) return(NULL); @@ -7734,146 +7787,18 @@ xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { } ptr++; - - /* - * Predefined entities override any extra definition - */ - if ((ctxt->options & XML_PARSE_OLDSAX) == 0) { - ent = xmlGetPredefinedEntity(name); - if (ent != NULL) { - xmlFree(name); - *str = ptr; - return(ent); - } - } - - /* - * Increase the number of entity references parsed - */ - ctxt->nbentities++; - - /* - * Ask first SAX for entity resolution, otherwise try the - * entities which may have stored in the parser context. - */ - if (ctxt->sax != NULL) { - if (ctxt->sax->getEntity != NULL) - ent = ctxt->sax->getEntity(ctxt->userData, name); - if ((ent == NULL) && (ctxt->options & XML_PARSE_OLDSAX)) - ent = xmlGetPredefinedEntity(name); - if ((ent == NULL) && (ctxt->userData==ctxt)) { - ent = xmlSAX2GetEntity(ctxt, name); - } - } - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(name); - return(NULL); - } - - /* - * [ WFC: Entity Declared ] - * In a document without any DTD, a document with only an - * internal DTD subset which contains no parameter entity - * references, or a document with "standalone='yes'", the - * Name given in the entity reference must match that in an - * entity declaration, except that well-formed documents - * need not declare any of the following entities: amp, lt, - * gt, apos, quot. - * The declaration of a parameter entity must precede any - * reference to it. - * Similarly, the declaration of a general entity must - * precede any reference to it which appears in a default - * value in an attribute-list declaration. Note that if - * entities are declared in the external subset or in - * external parameter entities, a non-validating processor - * is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be - * declared is a well-formedness constraint only if - * standalone='yes'. - */ - if (ent == NULL) { - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && - (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - } else { - xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", - name); - } - xmlParserEntityCheck(ctxt, 0, ent, 0); - /* TODO ? check regressions ctxt->valid = 0; */ - } - - /* - * [ WFC: Parsed Entity ] - * An entity reference must not contain the name of an - * unparsed entity - */ - else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, - "Entity reference to unparsed entity %s\n", name); - } - - /* - * [ WFC: No External Entity References ] - * Attribute values cannot contain direct or indirect - * entity references to external entities. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, - "Attribute references external entity '%s'\n", name); - } - /* - * [ WFC: No < in Attribute Values ] - * The replacement text of any entity referred to directly or - * indirectly in an attribute value (other than "<") must - * not contain a <. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent != NULL) && (ent->content != NULL) && - (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && - (xmlStrchr(ent->content, '<'))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, - "'<' in entity '%s' is not allowed in attributes values\n", - name); - } - - /* - * Internal check, no parameter entities here ... - */ - else { - switch (ent->etype) { - case XML_INTERNAL_PARAMETER_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, - "Attempt to reference the parameter entity '%s'\n", - name); - break; - default: - break; - } - } - - /* - * [ WFC: No Recursion ] - * A parsed entity must not contain a recursive reference - * to itself, either directly or indirectly. - * Done somewhere else - */ - - xmlFree(name); *str = ptr; - return(ent); + return(name); } /** * xmlParsePEReference: * @ctxt: an XML parser context * - * parse PEReference declarations + * DEPRECATED: Internal function, don't use. + * + * Parse a parameter entity reference. Always consumes '%'. + * * The entity content is handled directly by pushing it's content as * a new input stream. * @@ -7913,9 +7838,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) xmlFatalErrMsg(ctxt, XML_ERR_PEREF_NO_NAME, "PEReference: no name\n"); return; } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "PEReference: %s\n", name); if (RAW != ';') { xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); return; @@ -7923,10 +7845,8 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) NEXT; - /* - * Increase the number of entity references parsed - */ - ctxt->nbentities++; + /* Must be set before xmlHandleUndeclaredEntity */ + ctxt->hasPErefs = 1; /* * Request the entity from SAX @@ -7934,42 +7854,9 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); - if (ctxt->instate == XML_PARSER_EOF) - return; + if (entity == NULL) { - /* - * [ WFC: Entity Declared ] - * In a document without any DTD, a document with only an - * internal DTD subset which contains no parameter entity - * references, or a document with "standalone='yes'", ... - * ... The declaration of a parameter entity must precede - * any reference to it... - */ - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && - (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name); - } else { - /* - * [ VC: Entity Declared ] - * In a document with an external subset or external - * parameter entities with "standalone='no'", ... - * ... The declaration of a parameter entity must - * precede any reference to it... - */ - if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) { - xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name, NULL); - } else - xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name, NULL); - ctxt->valid = 0; - } - xmlParserEntityCheck(ctxt, 0, NULL, 0); + xmlHandleUndeclaredEntity(ctxt, name); } else { /* * Internal checking in case the entity quest barfed @@ -7980,50 +7867,29 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) "Internal: %%%s; is not a parameter entity\n", name, NULL); } else { - xmlChar start[4]; - xmlCharEncoding enc; - - if (xmlParserEntityCheck(ctxt, 0, entity, 0)) - return; - if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && - ((ctxt->options & XML_PARSE_NOENT) == 0) && - ((ctxt->options & XML_PARSE_DTDVALID) == 0) && - ((ctxt->options & XML_PARSE_DTDLOAD) == 0) && - ((ctxt->options & XML_PARSE_DTDATTR) == 0) && - (ctxt->replaceEntities == 0) && - (ctxt->validate == 0)) + ((ctxt->options & XML_PARSE_NO_XXE) || + ((ctxt->loadsubset == 0) && + (ctxt->replaceEntities == 0) && + (ctxt->validate == 0)))) return; + if (entity->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; + } + input = xmlNewEntityInputStream(ctxt, entity); if (xmlPushInput(ctxt, input) < 0) { xmlFreeInputStream(input); return; } + entity->flags |= XML_ENT_EXPANDING; + if (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) { - /* - * 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->instate == XML_PARSER_EOF) - return; - 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); - } - } + xmlDetectEncoding(ctxt); if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { @@ -8032,7 +7898,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) } } } - ctxt->hasPErefs = 1; } /** @@ -8048,90 +7913,123 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) */ static int xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { - xmlParserInputPtr input; - xmlBufferPtr buf; - int l, c; - int count = 0; + xmlParserInputPtr oldinput, input = NULL; + xmlParserInputPtr *oldinputTab; + const xmlChar *oldencoding; + xmlChar *content = NULL; + size_t length, i; + int oldinputNr, oldinputMax; + int ret = -1; + int res; if ((ctxt == NULL) || (entity == NULL) || ((entity->etype != XML_EXTERNAL_PARAMETER_ENTITY) && (entity->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY)) || (entity->content != NULL)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + xmlFatalErr(ctxt, XML_ERR_ARGUMENT, "xmlLoadEntityContent parameter error"); return(-1); } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "Reading %s entity content input\n", entity->name); - - buf = xmlBufferCreate(); - if (buf == NULL) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlLoadEntityContent parameter error"); + input = xmlLoadExternalEntity((char *) entity->URI, + (char *) entity->ExternalID, ctxt); + if (input == NULL) return(-1); - } - xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - input = xmlNewEntityInputStream(ctxt, entity); - if (input == NULL) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlLoadEntityContent input error"); - xmlBufferFree(buf); - return(-1); + oldinput = ctxt->input; + oldinputNr = ctxt->inputNr; + oldinputMax = ctxt->inputMax; + oldinputTab = ctxt->inputTab; + oldencoding = ctxt->encoding; + + ctxt->input = NULL; + ctxt->inputNr = 0; + ctxt->inputMax = 1; + ctxt->encoding = NULL; + ctxt->inputTab = xmlMalloc(sizeof(xmlParserInputPtr)); + if (ctxt->inputTab == NULL) { + xmlErrMemory(ctxt); + xmlFreeInputStream(input); + goto error; } + xmlBufResetInput(input->buf->buffer, input); + + inputPush(ctxt, input); + + xmlDetectEncoding(ctxt); + /* - * Push the entity as the current input, read char by char - * saving to the buffer until the end of the entity or an error + * Parse a possible text declaration first */ - if (xmlPushInput(ctxt, input) < 0) { - xmlBufferFree(buf); - xmlFreeInputStream(input); - return(-1); + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + /* + * An XML-1.0 document can't reference an entity not XML-1.0 + */ + if ((xmlStrEqual(ctxt->version, BAD_CAST "1.0")) && + (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { + xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, + "Version mismatch between document and entity\n"); + } } - GROW; - c = CUR_CHAR(l); - while ((ctxt->input == input) && (ctxt->input->cur < ctxt->input->end) && - (IS_CHAR(c))) { - xmlBufferAdd(buf, ctxt->input->cur, l); - if (count++ > XML_PARSER_CHUNK_SIZE) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlBufferFree(buf); - return(-1); - } - } - NEXTL(l); - c = CUR_CHAR(l); - if (c == 0) { - count = 0; - GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlBufferFree(buf); - return(-1); - } - c = CUR_CHAR(l); - } + length = input->cur - input->base; + xmlBufShrink(input->buf->buffer, length); + xmlSaturatedAdd(&ctxt->sizeentities, length); + + while ((res = xmlParserInputBufferGrow(input->buf, 4096)) > 0) + ; + + xmlBufResetInput(input->buf->buffer, input); + + if (res < 0) { + xmlCtxtErrIO(ctxt, input->buf->error, NULL); + goto error; } - if ((ctxt->input == input) && (ctxt->input->cur >= ctxt->input->end)) { - xmlPopInput(ctxt); - } else if (!IS_CHAR(c)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, - "xmlLoadEntityContent: invalid char value %d\n", - c); - xmlBufferFree(buf); - return(-1); + length = xmlBufUse(input->buf->buffer); + content = xmlBufDetach(input->buf->buffer); + + if (length > INT_MAX) { + xmlErrMemory(ctxt); + goto error; } - entity->content = buf->content; - buf->content = NULL; - xmlBufferFree(buf); - return(0); + for (i = 0; i < length; ) { + int clen = length - i; + int c = xmlGetUTF8Char(content + i, &clen); + + if ((c < 0) || (!IS_CHAR(c))) { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "xmlLoadEntityContent: invalid char value %d\n", + content[i]); + goto error; + } + i += clen; + } + + xmlSaturatedAdd(&ctxt->sizeentities, length); + entity->content = content; + entity->length = length; + content = NULL; + ret = 0; + +error: + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + xmlFree(ctxt->inputTab); + xmlFree((xmlChar *) ctxt->encoding); + + ctxt->input = oldinput; + ctxt->inputNr = oldinputNr; + ctxt->inputMax = oldinputMax; + ctxt->inputTab = oldinputTab; + ctxt->encoding = oldencoding; + + xmlFree(content); + + return(ret); } /** @@ -8194,10 +8092,8 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { } ptr++; - /* - * Increase the number of entity references parsed - */ - ctxt->nbentities++; + /* Must be set before xmlHandleUndeclaredEntity */ + ctxt->hasPErefs = 1; /* * Request the entity from SAX @@ -8205,38 +8101,9 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(name); - *str = ptr; - return(NULL); - } + if (entity == NULL) { - /* - * [ WFC: Entity Declared ] - * In a document without any DTD, a document with only an - * internal DTD subset which contains no parameter entity - * references, or a document with "standalone='yes'", ... - * ... The declaration of a parameter entity must precede - * any reference to it... - */ - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", name); - } else { - /* - * [ VC: Entity Declared ] - * In a document with an external subset or external - * parameter entities with "standalone='no'", ... - * ... The declaration of a parameter entity must - * precede any reference to it... - */ - xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name, NULL); - ctxt->valid = 0; - } - xmlParserEntityCheck(ctxt, 0, NULL, 0); + xmlHandleUndeclaredEntity(ctxt, name); } else { /* * Internal checking in case the entity quest barfed @@ -8248,7 +8115,7 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { name, NULL); } } - ctxt->hasPErefs = 1; + xmlFree(name); *str = ptr; return(entity); @@ -8258,6 +8125,8 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { * xmlParseDocTypeDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse a DOCTYPE declaration * * [28] doctypedecl ::= 'sax != NULL) && (ctxt->sax->internalSubset != NULL) && (!ctxt->disableSAX)) ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI); - if (ctxt->instate == XML_PARSER_EOF) - return; /* * Is there any internal subset declarations ? @@ -8346,41 +8213,41 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * Is there any DTD definition ? */ if (RAW == '[') { - int baseInputNr = ctxt->inputNr; - ctxt->instate = XML_PARSER_DTD; + int oldInputNr = ctxt->inputNr; + NEXT; /* * Parse the succession of Markup declarations and * PEReferences. * Subsequence (markupdecl | PEReference | S)* */ - while (((RAW != ']') || (ctxt->inputNr > baseInputNr)) && - (ctxt->instate != XML_PARSER_EOF)) { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; - - SKIP_BLANKS; - xmlParseMarkupDecl(ctxt); - xmlParsePEReference(ctxt); + SKIP_BLANKS; + while (((RAW != ']') || (ctxt->inputNr > oldInputNr)) && + (PARSER_STOPPED(ctxt) == 0)) { /* * Conditional sections are allowed from external entities included * by PE References in the internal subset. */ - if ((ctxt->inputNr > 1) && (ctxt->input->filename != NULL) && + if ((PARSER_EXTERNAL(ctxt)) && (RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { xmlParseConditionalSections(ctxt); + } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { + xmlParseMarkupDecl(ctxt); + } else if (RAW == '%') { + xmlParsePEReference(ctxt); + } else { + xmlFatalErr(ctxt, XML_ERR_INT_SUBSET_NOT_FINISHED, NULL); + break; } - - if ((id == ctxt->input->id) && (cons == CUR_CONSUMED)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseInternalSubset: error detected in Markup declaration\n"); - if (ctxt->inputNr > baseInputNr) - xmlPopInput(ctxt); - else - break; - } + SKIP_BLANKS_PE; + SHRINK; + GROW; } + + while (ctxt->inputNr > oldInputNr) + xmlPopPE(ctxt); + if (RAW == ']') { NEXT; SKIP_BLANKS; @@ -8390,7 +8257,7 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { /* * We should be at the end of the DOCTYPE declaration. */ - if (RAW != '>') { + if ((ctxt->wellFormed) && (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); return; } @@ -8403,6 +8270,8 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * @ctxt: an XML parser context * @value: a xmlChar ** used to store the value of the attribute * + * DEPRECATED: Internal function, don't use. + * * parse an attribute * * [41] Attribute ::= Name Eq AttValue @@ -8453,11 +8322,10 @@ xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) { NEXT; SKIP_BLANKS; val = xmlParseAttValue(ctxt); - ctxt->instate = XML_PARSER_CONTENT; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); - return(NULL); + return(name); } /* @@ -8496,8 +8364,9 @@ xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) { * xmlParseStartTag: * @ctxt: an XML parser context * - * parse a start of tag either for rule element or - * EmptyElement. In both case we don't parse the tag closing chars. + * DEPRECATED: Internal function, don't use. + * + * Parse a start tag. Always consumes '<'. * * [40] STag ::= '<' Name (S Attribute)* S? '>' * @@ -8550,12 +8419,11 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && - (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; - + (IS_BYTE_CHAR(RAW))) && (PARSER_STOPPED(ctxt) == 0)) { attname = xmlParseAttribute(ctxt, &attvalue); - if ((attname != NULL) && (attvalue != NULL)) { + if (attname == NULL) + break; + if (attvalue != NULL) { /* * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same @@ -8576,7 +8444,7 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -8590,7 +8458,7 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { n = (const xmlChar **) xmlRealloc((void *) atts, maxatts * sizeof(const xmlChar *)); if (n == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -8617,12 +8485,6 @@ failed: xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "attributes construct error\n"); } - if ((cons == CUR_CONSUMED) && (id == ctxt->input->id) && - (attname == NULL) && (attvalue == NULL)) { - xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseStartTag: problem parsing attributes\n"); - break; - } SHRINK; GROW; } @@ -8653,7 +8515,7 @@ failed: * @line: line of the start tag * @nsNr: number of namespaces on the start tag * - * parse an end of tag + * Parse an end tag. Always consumes '' * @@ -8715,6 +8577,8 @@ xmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { * xmlParseEndTag: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an end of tag * * [42] ETag ::= '' @@ -8736,28 +8600,62 @@ xmlParseEndTag(xmlParserCtxtPtr ctxt) { * * ************************************************************************/ -/* - * xmlGetNamespace: +/** + * xmlParseQNameHashed: * @ctxt: an XML parser context - * @prefix: the prefix to lookup + * @prefix: pointer to store the prefix part + * + * parse an XML Namespace QName * - * Lookup the namespace name for the @prefix (which ca be NULL) - * The prefix must come from the @ctxt->dict dictionary + * [6] QName ::= (Prefix ':')? LocalPart + * [7] Prefix ::= NCName + * [8] LocalPart ::= NCName * - * Returns the namespace name or NULL if not bound + * Returns the Name parsed or NULL */ -static const xmlChar * -xmlGetNamespace(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { - int i; - if (prefix == ctxt->str_xml) return(ctxt->str_xml_ns); - for (i = ctxt->nsNr - 2;i >= 0;i-=2) - if (ctxt->nsTab[i] == prefix) { - if ((prefix == NULL) && (*ctxt->nsTab[i + 1] == 0)) - return(NULL); - return(ctxt->nsTab[i + 1]); - } - return(NULL); +static xmlHashedString +xmlParseQNameHashed(xmlParserCtxtPtr ctxt, xmlHashedString *prefix) { + xmlHashedString l, p; + int start, isNCName = 0; + + l.name = NULL; + p.name = NULL; + + GROW; + start = CUR_PTR - BASE_PTR; + + l = xmlParseNCName(ctxt); + if (l.name != NULL) { + isNCName = 1; + if (CUR == ':') { + NEXT; + p = l; + l = xmlParseNCName(ctxt); + } + } + if ((l.name == NULL) || (CUR == ':')) { + xmlChar *tmp; + + l.name = NULL; + p.name = NULL; + if ((isNCName == 0) && (CUR != ':')) + return(l); + tmp = xmlParseNmtoken(ctxt); + if (tmp != NULL) + xmlFree(tmp); + l = xmlDictLookupHashed(ctxt->dict, BASE_PTR + start, + CUR_PTR - (BASE_PTR + start)); + if (l.name == NULL) { + xmlErrMemory(ctxt); + return(l); + } + xmlNsErr(ctxt, XML_NS_ERR_QNAME, + "Failed to parse QName '%s'\n", l.name, NULL, NULL); + } + + *prefix = p; + return(l); } /** @@ -8776,74 +8674,13 @@ xmlGetNamespace(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { static const xmlChar * xmlParseQName(xmlParserCtxtPtr ctxt, const xmlChar **prefix) { - const xmlChar *l, *p; - - GROW; + xmlHashedString n, p; - l = xmlParseNCName(ctxt); - if (l == NULL) { - if (CUR == ':') { - l = xmlParseName(ctxt); - if (l != NULL) { - xmlNsErr(ctxt, XML_NS_ERR_QNAME, - "Failed to parse QName '%s'\n", l, NULL, NULL); - *prefix = NULL; - return(l); - } - } + n = xmlParseQNameHashed(ctxt, &p); + if (n.name == NULL) return(NULL); - } - if (CUR == ':') { - NEXT; - p = l; - l = xmlParseNCName(ctxt); - if (l == NULL) { - xmlChar *tmp; - - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - xmlNsErr(ctxt, XML_NS_ERR_QNAME, - "Failed to parse QName '%s:'\n", p, NULL, NULL); - l = xmlParseNmtoken(ctxt); - if (l == NULL) { - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - tmp = xmlBuildQName(BAD_CAST "", p, NULL, 0); - } else { - tmp = xmlBuildQName(l, p, NULL, 0); - xmlFree((char *)l); - } - p = xmlDictLookup(ctxt->dict, tmp, -1); - if (tmp != NULL) xmlFree(tmp); - *prefix = NULL; - return(p); - } - if (CUR == ':') { - xmlChar *tmp; - - xmlNsErr(ctxt, XML_NS_ERR_QNAME, - "Failed to parse QName '%s:%s:'\n", p, l, NULL); - NEXT; - tmp = (xmlChar *) xmlParseName(ctxt); - if (tmp != NULL) { - tmp = xmlBuildQName(tmp, l, NULL, 0); - l = xmlDictLookup(ctxt->dict, tmp, -1); - if (tmp != NULL) xmlFree(tmp); - *prefix = p; - return(l); - } - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - tmp = xmlBuildQName(BAD_CAST "", l, NULL, 0); - l = xmlDictLookup(ctxt->dict, tmp, -1); - if (tmp != NULL) xmlFree(tmp); - *prefix = p; - return(l); - } - *prefix = p; - } else - *prefix = NULL; - return(l); + *prefix = p.name; + return(n.name); } /** @@ -8875,228 +8712,31 @@ xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, cmp = prefix; while (*in != 0 && *in == *cmp) { ++in; - ++cmp; - } - if ((*cmp == 0) && (*in == ':')) { - in++; - cmp = name; - while (*in != 0 && *in == *cmp) { - ++in; - ++cmp; - } - if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { - /* success */ - ctxt->input->col += in - ctxt->input->cur; - ctxt->input->cur = in; - return((const xmlChar*) 1); - } - } - /* - * all strings coms from the dictionary, equality can be done directly - */ - ret = xmlParseQName (ctxt, &prefix2); - if ((ret == name) && (prefix == prefix2)) - return((const xmlChar*) 1); - return ret; -} - -/** - * xmlParseAttValueInternal: - * @ctxt: an XML parser context - * @len: attribute len result - * @alloc: whether the attribute was reallocated as a new string - * @normalize: if 1 then further non-CDATA normalization must be done - * - * parse a value for an attribute. - * NOTE: if no normalization is needed, the routine will return pointers - * directly from the data buffer. - * - * 3.3.3 Attribute-Value Normalization: - * Before the value of an attribute is passed to the application or - * checked for validity, the XML processor must normalize it as follows: - * - a character reference is processed by appending the referenced - * character to the attribute value - * - an entity reference is processed by recursively processing the - * replacement text of the entity - * - a whitespace character (#x20, #xD, #xA, #x9) is processed by - * appending #x20 to the normalized value, except that only a single - * #x20 is appended for a "#xD#xA" sequence that is part of an external - * parsed entity or the literal entity value of an internal parsed entity - * - other characters are processed by appending them to the normalized value - * If the declared value is not CDATA, then the XML processor must further - * process the normalized attribute value by discarding any leading and - * trailing space (#x20) characters, and by replacing sequences of space - * (#x20) characters by a single space (#x20) character. - * All attributes for which no declaration has been read should be treated - * by a non-validating parser as if declared CDATA. - * - * Returns the AttValue parsed or NULL. The value has to be freed by the - * caller if it was copied, this can be detected by val[*len] == 0. - */ - -#define GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) \ - const xmlChar *oldbase = ctxt->input->base;\ - GROW;\ - if (ctxt->instate == XML_PARSER_EOF)\ - return(NULL);\ - if (oldbase != ctxt->input->base) {\ - ptrdiff_t delta = ctxt->input->base - oldbase;\ - start = start + delta;\ - in = in + delta;\ - }\ - end = ctxt->input->end; - -static xmlChar * -xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc, - int normalize) -{ - xmlChar limit = 0; - const xmlChar *in = NULL, *start, *end, *last; - xmlChar *ret = NULL; - int line, col; - - GROW; - in = (xmlChar *) CUR_PTR; - line = ctxt->input->line; - col = ctxt->input->col; - if (*in != '"' && *in != '\'') { - xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); - return (NULL); - } - ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; - - /* - * try to handle in this routine the most common case where no - * allocation of a new string is required and where content is - * pure ASCII. - */ - limit = *in++; - col++; - end = ctxt->input->end; - start = in; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - } - if (normalize) { - /* - * Skip any leading spaces - */ - while ((in < end) && (*in != limit) && - ((*in == 0x20) || (*in == 0x9) || - (*in == 0xA) || (*in == 0xD))) { - if (*in == 0xA) { - line++; col = 1; - } else { - col++; - } - in++; - start = in; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - while ((in < end) && (*in != limit) && (*in >= 0x20) && - (*in <= 0x7f) && (*in != '&') && (*in != '<')) { - col++; - if ((*in++ == 0x20) && (*in == 0x20)) break; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - last = in; - /* - * skip the trailing blanks - */ - while ((last[-1] == 0x20) && (last > start)) last--; - while ((in < end) && (*in != limit) && - ((*in == 0x20) || (*in == 0x9) || - (*in == 0xA) || (*in == 0xD))) { - if (*in == 0xA) { - line++, col = 1; - } else { - col++; - } - in++; - if (in >= end) { - const xmlChar *oldbase = ctxt->input->base; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - if (oldbase != ctxt->input->base) { - ptrdiff_t delta = ctxt->input->base - oldbase; - start = start + delta; - in = in + delta; - last = last + delta; - } - end = ctxt->input->end; - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } + ++cmp; + } + if ((*cmp == 0) && (*in == ':')) { + in++; + cmp = name; + while (*in != 0 && *in == *cmp) { + ++in; + ++cmp; } - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - if (*in != limit) goto need_complex; - } else { - while ((in < end) && (*in != limit) && (*in >= 0x20) && - (*in <= 0x7f) && (*in != '&') && (*in != '<')) { - in++; - col++; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } + if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { + /* success */ + ctxt->input->col += in - ctxt->input->cur; + ctxt->input->cur = in; + return((const xmlChar*) 1); } - last = in; - if (((in - start) > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - if (*in != limit) goto need_complex; } - in++; - col++; - if (len != NULL) { - *len = last - start; - ret = (xmlChar *) start; - } else { - if (alloc) *alloc = 1; - ret = xmlStrndup(start, last - start); - } - CUR_PTR = in; - ctxt->input->line = line; - ctxt->input->col = col; - if (alloc) *alloc = 0; + /* + * all strings coms from the dictionary, equality can be done directly + */ + ret = xmlParseQName (ctxt, &prefix2); + if (ret == NULL) + return(NULL); + if ((ret == name) && (prefix == prefix2)) + return((const xmlChar*) 1); return ret; -need_complex: - if (alloc) *alloc = 1; - return xmlParseAttValueComplex(ctxt, len, normalize); } /** @@ -9114,24 +8754,31 @@ need_complex: * Returns the attribute name, and the value in *value, . */ -static const xmlChar * +static xmlHashedString xmlParseAttribute2(xmlParserCtxtPtr ctxt, const xmlChar * pref, const xmlChar * elem, - const xmlChar ** prefix, xmlChar ** value, + xmlHashedString * hprefix, xmlChar ** value, int *len, int *alloc) { - const xmlChar *name; - xmlChar *val, *internal_val = NULL; + xmlHashedString hname; + const xmlChar *prefix, *name; + xmlChar *val = NULL, *internal_val = NULL; int normalize = 0; + int isNamespace; *value = NULL; GROW; - name = xmlParseQName(ctxt, prefix); - if (name == NULL) { + hname = xmlParseQNameHashed(ctxt, hprefix); + if (hname.name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "error parsing attribute name\n"); - return (NULL); + return(hname); } + name = hname.name; + if (hprefix->name != NULL) + prefix = hprefix->name; + else + prefix = NULL; /* * get the type if needed @@ -9140,7 +8787,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, int type; type = (int) (ptrdiff_t) xmlHashQLookup2(ctxt->attsSpecial, - pref, elem, *prefix, name); + pref, elem, + prefix, name); if (type != 0) normalize = 1; } @@ -9152,33 +8800,20 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, if (RAW == '=') { NEXT; SKIP_BLANKS; - val = xmlParseAttValueInternal(ctxt, len, alloc, normalize); - if (normalize) { - /* - * Sometimes a second normalisation pass for spaces is needed - * but that only happens if charrefs or entities references - * have been used in the attribute value, i.e. the attribute - * value have been extracted in an allocated string already. - */ - if (*alloc) { - const xmlChar *val2; - - val2 = xmlAttrNormalizeSpace2(ctxt, val, len); - if ((val2 != NULL) && (val2 != val)) { - xmlFree(val); - val = (xmlChar *) val2; - } - } - } - ctxt->instate = XML_PARSER_CONTENT; + isNamespace = (((prefix == NULL) && (name == ctxt->str_xmlns)) || + (prefix == ctxt->str_xmlns)); + val = xmlParseAttValueInternal(ctxt, len, alloc, normalize, + isNamespace); + if (val == NULL) + goto error; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); - return (NULL); + goto error; } - if (*prefix == ctxt->str_xml) { + if (prefix == ctxt->str_xml) { /* * Check that xml:lang conforms to the specification * No more registered as an error, just generate a warning now @@ -9186,6 +8821,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, */ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) { internal_val = xmlStrndup(val, *len); + if (internal_val == NULL) + goto mem_error; if (!xmlCheckLanguageID(internal_val)) { xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, "Malformed value for xml:lang : %s\n", @@ -9198,6 +8835,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, */ if (xmlStrEqual(name, BAD_CAST "space")) { internal_val = xmlStrndup(val, *len); + if (internal_val == NULL) + goto mem_error; if (xmlStrEqual(internal_val, BAD_CAST "default")) *(ctxt->space) = 0; else if (xmlStrEqual(internal_val, BAD_CAST "preserve")) @@ -9214,14 +8853,71 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, } *value = val; - return (name); + return (hname); + +mem_error: + xmlErrMemory(ctxt); +error: + if ((val != NULL) && (*alloc != 0)) + xmlFree(val); + return(hname); +} + +/** + * xmlAttrHashInsert: + * @ctxt: parser context + * @size: size of the hash table + * @name: attribute name + * @uri: namespace uri + * @hashValue: combined hash value of name and uri + * @aindex: attribute index (this is a multiple of 5) + * + * Inserts a new attribute into the hash table. + * + * Returns INT_MAX if no existing attribute was found, the attribute + * index if an attribute was found, -1 if a memory allocation failed. + */ +static int +xmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name, + const xmlChar *uri, unsigned hashValue, int aindex) { + xmlAttrHashBucket *table = ctxt->attrHash; + xmlAttrHashBucket *bucket; + unsigned hindex; + + hindex = hashValue & (size - 1); + bucket = &table[hindex]; + + while (bucket->index >= 0) { + const xmlChar **atts = &ctxt->atts[bucket->index]; + + if (name == atts[0]) { + int nsIndex = (int) (ptrdiff_t) atts[2]; + + if ((nsIndex == NS_INDEX_EMPTY) ? (uri == NULL) : + (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml_ns) : + (uri == ctxt->nsTab[nsIndex * 2 + 1])) + return(bucket->index); + } + + hindex++; + bucket++; + if (hindex >= size) { + hindex = 0; + bucket = table; + } + } + + bucket->index = aindex; + + return(INT_MAX); } + /** * xmlParseStartTag2: * @ctxt: an XML parser context * - * parse a start of tag either for rule element or - * EmptyElement. In both case we don't parse the tag closing chars. + * Parse a start tag. Always consumes '<'. + * * This routine is called when running SAX2 parsing * * [40] STag ::= '<' Name (S Attribute)* S? '>' @@ -9247,48 +8943,47 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, static const xmlChar * xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, - const xmlChar **URI, int *tlen) { + const xmlChar **URI, int *nbNsPtr) { + xmlHashedString hlocalname; + xmlHashedString hprefix; + xmlHashedString hattname; + xmlHashedString haprefix; const xmlChar *localname; const xmlChar *prefix; const xmlChar *attname; const xmlChar *aprefix; - const xmlChar *nsname; - xmlChar *attvalue; + const xmlChar *uri; + xmlChar *attvalue = NULL; const xmlChar **atts = ctxt->atts; + unsigned attrHashSize = 0; int maxatts = ctxt->maxatts; - int nratts, nbatts, nbdef, inputid; - int i, j, nbNs, attval; - unsigned long cur; - int nsNr = ctxt->nsNr; + int nratts, nbatts, nbdef; + int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts; + int alloc = 0; if (RAW != '<') return(NULL); NEXT1; - /* - * NOTE: it is crucial with the SAX2 API to never call SHRINK beyond that - * point since the attribute values may be stored as pointers to - * the buffer and calling SHRINK would destroy them ! - * The Shrinking is only possible once the full set of attribute - * callbacks have been done. - */ - SHRINK; - cur = ctxt->input->cur - ctxt->input->base; - inputid = ctxt->input->id; nbatts = 0; nratts = 0; nbdef = 0; nbNs = 0; + nbTotalDef = 0; attval = 0; - /* Forget any namespaces added during an earlier parse of this element. */ - ctxt->nsNr = nsNr; - localname = xmlParseQName(ctxt, &prefix); - if (localname == NULL) { + if (xmlParserNsStartElement(ctxt->nsdb) < 0) { + xmlErrMemory(ctxt); + return(NULL); + } + + hlocalname = xmlParseQNameHashed(ctxt, &hprefix); + if (hlocalname.name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, "StartTag: invalid element name\n"); return(NULL); } - *tlen = ctxt->input->cur - ctxt->input->base - cur; + localname = hlocalname.name; + prefix = hprefix.name; /* * Now parse the attributes, it ends up with the ending @@ -9298,45 +8993,74 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, SKIP_BLANKS; GROW; + /* + * The ctxt->atts array will be ultimately passed to the SAX callback + * containing five xmlChar pointers for each attribute: + * + * [0] attribute name + * [1] attribute prefix + * [2] namespace URI + * [3] attribute value + * [4] end of attribute value + * + * To save memory, we reuse this array temporarily and store integers + * in these pointer variables. + * + * [0] attribute name + * [1] attribute prefix + * [2] hash value of attribute prefix, and later namespace index + * [3] for non-allocated values: ptrdiff_t offset into input buffer + * [4] for non-allocated values: ptrdiff_t offset into input buffer + * + * The ctxt->attallocs array contains an additional unsigned int for + * each attribute, containing the hash value of the attribute name + * and the alloc flag in bit 31. + */ + while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && - (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; - int len = -1, alloc = 0; - - attname = xmlParseAttribute2(ctxt, prefix, localname, - &aprefix, &attvalue, &len, &alloc); - if ((attname == NULL) || (attvalue == NULL)) + (IS_BYTE_CHAR(RAW))) && (PARSER_STOPPED(ctxt) == 0)) { + int len = -1; + + hattname = xmlParseAttribute2(ctxt, prefix, localname, + &haprefix, &attvalue, &len, + &alloc); + if (hattname.name == NULL) + break; + if (attvalue == NULL) goto next_attr; + attname = hattname.name; + aprefix = haprefix.name; if (len < 0) len = xmlStrlen(attvalue); if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { - const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); - xmlURIPtr uri; - - if (URL == NULL) { - xmlErrMemory(ctxt, "dictionary allocation failure"); - if ((attvalue != NULL) && (alloc != 0)) - xmlFree(attvalue); - localname = NULL; - goto done; + xmlHashedString huri; + xmlURIPtr parsedUri; + + huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); + uri = huri.name; + if (uri == NULL) { + xmlErrMemory(ctxt); + goto next_attr; } - if (*URL != 0) { - uri = xmlParseURI((const char *) URL); - if (uri == NULL) { + if (*uri != 0) { + if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) { + xmlErrMemory(ctxt); + goto next_attr; + } + if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns: '%s' is not a valid URI\n", - URL, NULL, NULL); + uri, NULL, NULL); } else { - if (uri->scheme == NULL) { + if (parsedUri->scheme == NULL) { xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE, "xmlns: URI %s is not absolute\n", - URL, NULL, NULL); + uri, NULL, NULL); } - xmlFreeURI(uri); + xmlFreeURI(parsedUri); } - if (URL == ctxt->str_xml_ns) { + if (uri == ctxt->str_xml_ns) { if (attname != ctxt->str_xml) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace URI cannot be the default namespace\n", @@ -9345,7 +9069,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, goto next_attr; } if ((len == 29) && - (xmlStrEqual(URL, + (xmlStrEqual(uri, BAD_CAST "http://www.w3.org/2000/xmlns/"))) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "reuse of the xmlns namespace name is forbidden\n", @@ -9353,23 +9077,22 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, goto next_attr; } } - /* - * check that it's not a defined namespace - */ - for (j = 1;j <= nbNs;j++) - if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) - break; - if (j <= nbNs) - xmlErrAttributeDup(ctxt, NULL, attname); - else - if (nsPush(ctxt, NULL, URL) > 0) nbNs++; + if (xmlParserNsPush(ctxt, NULL, &huri, NULL, 0) > 0) + nbNs++; } else if (aprefix == ctxt->str_xmlns) { - const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); - xmlURIPtr uri; + xmlHashedString huri; + xmlURIPtr parsedUri; + + huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); + uri = huri.name; + if (uri == NULL) { + xmlErrMemory(ctxt); + goto next_attr; + } if (attname == ctxt->str_xml) { - if (URL != ctxt->str_xml_ns) { + if (uri != ctxt->str_xml_ns) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace prefix mapped to wrong URI\n", NULL, NULL, NULL); @@ -9379,7 +9102,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, */ goto next_attr; } - if (URL == ctxt->str_xml_ns) { + if (uri == ctxt->str_xml_ns) { if (attname != ctxt->str_xml) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xml namespace URI mapped to wrong prefix\n", @@ -9394,48 +9117,43 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, goto next_attr; } if ((len == 29) && - (xmlStrEqual(URL, + (xmlStrEqual(uri, BAD_CAST "http://www.w3.org/2000/xmlns/"))) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "reuse of the xmlns namespace name is forbidden\n", NULL, NULL, NULL); goto next_attr; } - if ((URL == NULL) || (URL[0] == 0)) { + if ((uri == NULL) || (uri[0] == 0)) { xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, "xmlns:%s: Empty XML namespace is not allowed\n", attname, NULL, NULL); goto next_attr; } else { - uri = xmlParseURI((const char *) URL); - if (uri == NULL) { + if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) { + xmlErrMemory(ctxt); + goto next_attr; + } + if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns:%s: '%s' is not a valid URI\n", - attname, URL, NULL); + attname, uri, NULL); } else { - if ((ctxt->pedantic) && (uri->scheme == NULL)) { + if ((ctxt->pedantic) && (parsedUri->scheme == NULL)) { xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE, "xmlns:%s: URI %s is not absolute\n", - attname, URL, NULL); + attname, uri, NULL); } - xmlFreeURI(uri); + xmlFreeURI(parsedUri); } } - /* - * check that it's not a defined namespace - */ - for (j = 1;j <= nbNs;j++) - if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) - break; - if (j <= nbNs) - xmlErrAttributeDup(ctxt, aprefix, attname); - else - if (nsPush(ctxt, attname, URL) > 0) nbNs++; - + if (xmlParserNsPush(ctxt, &hattname, &huri, NULL, 0) > 0) + nbNs++; } else { /* - * Add the pair to atts + * Populate attributes array, see above for repurposing + * of xmlChar pointers. */ if ((atts == NULL) || (nbatts + 5 > maxatts)) { if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { @@ -9444,22 +9162,25 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, maxatts = ctxt->maxatts; atts = ctxt->atts; } - ctxt->attallocs[nratts++] = alloc; + ctxt->attallocs[nratts++] = (hattname.hashValue & 0x7FFFFFFF) | + ((unsigned) alloc << 31); atts[nbatts++] = attname; atts[nbatts++] = aprefix; - /* - * The namespace URI field is used temporarily to point at the - * base of the current input buffer for non-alloced attributes. - * When the input buffer is reallocated, all the pointers become - * invalid, but they can be reconstructed later. - */ - if (alloc) - atts[nbatts++] = NULL; - else - atts[nbatts++] = ctxt->input->base; - atts[nbatts++] = attvalue; - attvalue += len; - atts[nbatts++] = attvalue; + atts[nbatts++] = (const xmlChar *) (size_t) haprefix.hashValue; + if (alloc) { + atts[nbatts++] = attvalue; + attvalue += len; + atts[nbatts++] = attvalue; + } else { + /* + * attvalue points into the input buffer which can be + * reallocated. Store differences to input->base instead. + * The pointers will be reconstructed later. + */ + atts[nbatts++] = (void *) (attvalue - BASE_PTR); + attvalue += len; + atts[nbatts++] = (void *) (attvalue - BASE_PTR); + } /* * tag if some deallocation is needed */ @@ -9474,8 +9195,6 @@ next_attr: } GROW - if (ctxt->instate == XML_PARSER_EOF) - break; if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) break; if (SKIP_BLANKS == 0) { @@ -9483,191 +9202,297 @@ next_attr: "attributes construct error\n"); break; } - if ((cons == CUR_CONSUMED) && (id == ctxt->input->id) && - (attname == NULL) && (attvalue == NULL)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseStartTag: problem parsing attributes\n"); - break; - } GROW; } - if (ctxt->input->id != inputid) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "Unexpected change of input\n"); - localname = NULL; - goto done; - } - - /* Reconstruct attribute value pointers. */ - for (i = 0, j = 0; j < nratts; i += 5, j++) { - if (atts[i+2] != NULL) { - /* - * Arithmetic on dangling pointers is technically undefined - * behavior, but well... - */ - ptrdiff_t offset = ctxt->input->base - atts[i+2]; - atts[i+2] = NULL; /* Reset repurposed namespace URI */ - atts[i+3] += offset; /* value */ - atts[i+4] += offset; /* valuend */ - } - } - /* - * The attributes defaulting + * Namespaces from default attributes */ if (ctxt->attsDefault != NULL) { xmlDefAttrsPtr defaults; defaults = xmlHashLookup2(ctxt->attsDefault, localname, prefix); if (defaults != NULL) { - for (i = 0;i < defaults->nbAttrs;i++) { - attname = defaults->values[5 * i]; - aprefix = defaults->values[5 * i + 1]; + for (i = 0; i < defaults->nbAttrs; i++) { + xmlDefAttr *attr = &defaults->attrs[i]; + + attname = attr->name.name; + aprefix = attr->prefix.name; - /* - * special work for namespaces defaulted defs - */ if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { - /* - * check that it's not a defined namespace - */ - for (j = 1;j <= nbNs;j++) - if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) - break; - if (j <= nbNs) continue; - - nsname = xmlGetNamespace(ctxt, NULL); - if (nsname != defaults->values[5 * i + 2]) { - if (nsPush(ctxt, NULL, - defaults->values[5 * i + 2]) > 0) - nbNs++; - } + xmlParserEntityCheck(ctxt, attr->expandedSize); + + if (xmlParserNsPush(ctxt, NULL, &attr->value, NULL, 1) > 0) + nbNs++; } else if (aprefix == ctxt->str_xmlns) { - /* - * check that it's not a defined namespace - */ - for (j = 1;j <= nbNs;j++) - if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) - break; - if (j <= nbNs) continue; - - nsname = xmlGetNamespace(ctxt, attname); - if (nsname != defaults->values[2]) { - if (nsPush(ctxt, attname, - defaults->values[5 * i + 2]) > 0) - nbNs++; - } - } else { - /* - * check that it's not a defined attribute - */ - for (j = 0;j < nbatts;j+=5) { - if ((attname == atts[j]) && (aprefix == atts[j+1])) - break; - } - if (j < nbatts) continue; + xmlParserEntityCheck(ctxt, attr->expandedSize); - if ((atts == NULL) || (nbatts + 5 > maxatts)) { - if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { - localname = NULL; - goto done; - } - maxatts = ctxt->maxatts; - atts = ctxt->atts; - } - atts[nbatts++] = attname; - atts[nbatts++] = aprefix; - if (aprefix == NULL) - atts[nbatts++] = NULL; - else - atts[nbatts++] = xmlGetNamespace(ctxt, aprefix); - atts[nbatts++] = defaults->values[5 * i + 2]; - atts[nbatts++] = defaults->values[5 * i + 3]; - if ((ctxt->standalone == 1) && - (defaults->values[5 * i + 4] != NULL)) { - xmlValidityError(ctxt, XML_DTD_STANDALONE_DEFAULTED, - "standalone: attribute %s on %s defaulted from external subset\n", - attname, localname); - } - nbdef++; - } + if (xmlParserNsPush(ctxt, &attr->name, &attr->value, + NULL, 1) > 0) + nbNs++; + } else { + nbTotalDef += 1; + } } } } /* - * The attributes checkings + * Resolve attribute namespaces */ - for (i = 0; i < nbatts;i += 5) { + for (i = 0; i < nbatts; i += 5) { + attname = atts[i]; + aprefix = atts[i+1]; + /* * The default namespace does not apply to attribute names. */ - if (atts[i + 1] != NULL) { - nsname = xmlGetNamespace(ctxt, atts[i + 1]); - if (nsname == NULL) { - xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + if (aprefix == NULL) { + nsIndex = NS_INDEX_EMPTY; + } else if (aprefix == ctxt->str_xml) { + nsIndex = NS_INDEX_XML; + } else { + haprefix.name = aprefix; + haprefix.hashValue = (size_t) atts[i+2]; + nsIndex = xmlParserNsLookup(ctxt, &haprefix, NULL); + + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) { + xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s for %s on %s is not defined\n", - atts[i + 1], atts[i], localname); - } - atts[i + 2] = nsname; - } else - nsname = NULL; - /* - * [ WFC: Unique Att Spec ] - * No attribute name may appear more than once in the same - * start-tag or empty-element tag. - * As extended by the Namespace in XML REC. - */ - for (j = 0; j < i;j += 5) { - if (atts[i] == atts[j]) { - if (atts[i+1] == atts[j+1]) { - xmlErrAttributeDup(ctxt, atts[i+1], atts[i]); - break; - } - if ((nsname != NULL) && (atts[j + 2] == nsname)) { - xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, - "Namespaced Attribute %s in '%s' redefined\n", - atts[i], nsname, NULL); - break; - } + aprefix, attname, localname); + nsIndex = NS_INDEX_EMPTY; + } + } + + atts[i+2] = (const xmlChar *) (ptrdiff_t) nsIndex; + } + + /* + * Maximum number of attributes including default attributes. + */ + maxAtts = nratts + nbTotalDef; + + /* + * Verify that attribute names are unique. + */ + if (maxAtts > 1) { + attrHashSize = 4; + while (attrHashSize / 2 < (unsigned) maxAtts) + attrHashSize *= 2; + + if (attrHashSize > ctxt->attrHashMax) { + xmlAttrHashBucket *tmp; + + tmp = xmlRealloc(ctxt->attrHash, attrHashSize * sizeof(tmp[0])); + if (tmp == NULL) { + xmlErrMemory(ctxt); + goto done; + } + + ctxt->attrHash = tmp; + ctxt->attrHashMax = attrHashSize; + } + + memset(ctxt->attrHash, -1, attrHashSize * sizeof(ctxt->attrHash[0])); + + for (i = 0, j = 0; j < nratts; i += 5, j++) { + const xmlChar *nsuri; + unsigned hashValue, nameHashValue, uriHashValue; + int res; + + attname = atts[i]; + aprefix = atts[i+1]; + nsIndex = (ptrdiff_t) atts[i+2]; + /* Hash values always have bit 31 set, see dict.c */ + nameHashValue = ctxt->attallocs[j] | 0x80000000; + + if (nsIndex == NS_INDEX_EMPTY) { + /* + * Prefix with empty namespace means an undeclared + * prefix which was already reported above. + */ + if (aprefix != NULL) + continue; + nsuri = NULL; + uriHashValue = URI_HASH_EMPTY; + } else if (nsIndex == NS_INDEX_XML) { + nsuri = ctxt->str_xml_ns; + uriHashValue = URI_HASH_XML; + } else { + nsuri = ctxt->nsTab[nsIndex * 2 + 1]; + uriHashValue = ctxt->nsdb->extra[nsIndex].uriHashValue; + } + + hashValue = xmlDictCombineHash(nameHashValue, uriHashValue); + res = xmlAttrHashInsert(ctxt, attrHashSize, attname, nsuri, + hashValue, i); + if (res < 0) + continue; + + /* + * [ WFC: Unique Att Spec ] + * No attribute name may appear more than once in the same + * start-tag or empty-element tag. + * As extended by the Namespace in XML REC. + */ + if (res < INT_MAX) { + if (aprefix == atts[res+1]) { + xmlErrAttributeDup(ctxt, aprefix, attname); + } else { + xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, + "Namespaced Attribute %s in '%s' redefined\n", + attname, nsuri, NULL); + } + } + } + } + + /* + * Default attributes + */ + if (ctxt->attsDefault != NULL) { + xmlDefAttrsPtr defaults; + + defaults = xmlHashLookup2(ctxt->attsDefault, localname, prefix); + if (defaults != NULL) { + for (i = 0; i < defaults->nbAttrs; i++) { + xmlDefAttr *attr = &defaults->attrs[i]; + const xmlChar *nsuri; + unsigned hashValue, uriHashValue; + int res; + + attname = attr->name.name; + aprefix = attr->prefix.name; + + if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) + continue; + if (aprefix == ctxt->str_xmlns) + continue; + + if (aprefix == NULL) { + nsIndex = NS_INDEX_EMPTY; + nsuri = NULL; + uriHashValue = URI_HASH_EMPTY; + } if (aprefix == ctxt->str_xml) { + nsIndex = NS_INDEX_XML; + nsuri = ctxt->str_xml_ns; + uriHashValue = URI_HASH_XML; + } else if (aprefix != NULL) { + nsIndex = xmlParserNsLookup(ctxt, &attr->prefix, NULL); + if ((nsIndex == INT_MAX) || + (nsIndex < ctxt->nsdb->minNsIndex)) { + xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + "Namespace prefix %s for %s on %s is not " + "defined\n", + aprefix, attname, localname); + nsIndex = NS_INDEX_EMPTY; + nsuri = NULL; + uriHashValue = URI_HASH_EMPTY; + } else { + nsuri = ctxt->nsTab[nsIndex * 2 + 1]; + uriHashValue = ctxt->nsdb->extra[nsIndex].uriHashValue; + } + } + + /* + * Check whether the attribute exists + */ + if (maxAtts > 1) { + hashValue = xmlDictCombineHash(attr->name.hashValue, + uriHashValue); + res = xmlAttrHashInsert(ctxt, attrHashSize, attname, nsuri, + hashValue, nbatts); + if (res < 0) + continue; + if (res < INT_MAX) { + if (aprefix == atts[res+1]) + continue; + xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, + "Namespaced Attribute %s in '%s' redefined\n", + attname, nsuri, NULL); + } + } + + xmlParserEntityCheck(ctxt, attr->expandedSize); + + if ((atts == NULL) || (nbatts + 5 > maxatts)) { + if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { + localname = NULL; + goto done; + } + maxatts = ctxt->maxatts; + atts = ctxt->atts; + } + + atts[nbatts++] = attname; + atts[nbatts++] = aprefix; + atts[nbatts++] = (const xmlChar *) (ptrdiff_t) nsIndex; + atts[nbatts++] = attr->value.name; + atts[nbatts++] = attr->valueEnd; + if ((ctxt->standalone == 1) && (attr->external != 0)) { + xmlValidityError(ctxt, XML_DTD_STANDALONE_DEFAULTED, + "standalone: attribute %s on %s defaulted " + "from external subset\n", + attname, localname); + } + nbdef++; } } } - nsname = xmlGetNamespace(ctxt, prefix); - if ((prefix != NULL) && (nsname == NULL)) { + /* + * Reconstruct attribute pointers + */ + for (i = 0, j = 0; i < nbatts; i += 5, j++) { + /* namespace URI */ + nsIndex = (ptrdiff_t) atts[i+2]; + if (nsIndex == INT_MAX) + atts[i+2] = NULL; + else if (nsIndex == INT_MAX - 1) + atts[i+2] = ctxt->str_xml_ns; + else + atts[i+2] = ctxt->nsTab[nsIndex * 2 + 1]; + + if ((j < nratts) && (ctxt->attallocs[j] & 0x80000000) == 0) { + atts[i+3] = BASE_PTR + (ptrdiff_t) atts[i+3]; /* value */ + atts[i+4] = BASE_PTR + (ptrdiff_t) atts[i+4]; /* valuend */ + } + } + + uri = xmlParserNsLookupUri(ctxt, &hprefix); + if ((prefix != NULL) && (uri == NULL)) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s on %s is not defined\n", prefix, localname, NULL); } *pref = prefix; - *URI = nsname; + *URI = uri; /* - * SAX: Start of Element ! + * SAX callback */ if ((ctxt->sax != NULL) && (ctxt->sax->startElementNs != NULL) && (!ctxt->disableSAX)) { if (nbNs > 0) - ctxt->sax->startElementNs(ctxt->userData, localname, prefix, - nsname, nbNs, &ctxt->nsTab[ctxt->nsNr - 2 * nbNs], + ctxt->sax->startElementNs(ctxt->userData, localname, prefix, uri, + nbNs, ctxt->nsTab + 2 * (ctxt->nsNr - nbNs), nbatts / 5, nbdef, atts); else - ctxt->sax->startElementNs(ctxt->userData, localname, prefix, - nsname, 0, NULL, nbatts / 5, nbdef, atts); + ctxt->sax->startElementNs(ctxt->userData, localname, prefix, uri, + 0, NULL, nbatts / 5, nbdef, atts); } done: /* - * Free up attribute allocated strings if needed + * Free allocated attribute values */ if (attval != 0) { - for (i = 3,j = 0; j < nratts;i += 5,j++) - if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) - xmlFree((xmlChar *) atts[i]); + for (i = 0, j = 0; j < nratts; i += 5, j++) + if (ctxt->attallocs[j] & 0x80000000) + xmlFree((xmlChar *) atts[i+3]); } + *nbNsPtr = nbNs; return(localname); } @@ -9677,7 +9502,7 @@ done: * @line: line of the start tag * @nsNr: number of namespaces on the start tag * - * parse an end of tag + * Parse an end tag. Always consumes '' * @@ -9706,8 +9531,6 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) { * We should definitely be at the ending "S? '>'" part */ GROW; - if (ctxt->instate == XML_PARSER_EOF) - return; SKIP_BLANKS; if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); @@ -9737,14 +9560,16 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) { spacePop(ctxt); if (tag->nsNr != 0) - nsPop(ctxt, tag->nsNr); + xmlParserNsPop(ctxt, tag->nsNr); } /** * xmlParseCDSect: * @ctxt: an XML parser context * - * Parse escaped pure raw content. + * DEPRECATED: Internal function, don't use. + * + * Parse escaped pure raw content. Always consumes 'options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; - /* Check 2.6.0 was NXT(0) not RAW */ - if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { - SKIP(9); - } else + if ((CUR != '<') || (NXT(1) != '!') || (NXT(2) != '[')) return; + SKIP(3); + + if (!CMP6(CUR_PTR, 'C', 'D', 'A', 'T', 'A', '[')) + return; + SKIP(6); - ctxt->instate = XML_PARSER_CDATA_SECTION; r = CUR_CHAR(rl); if (!IS_CHAR(r)) { xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); - ctxt->instate = XML_PARSER_CONTENT; - return; + goto out; } NEXTL(rl); s = CUR_CHAR(sl); if (!IS_CHAR(s)) { xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); - ctxt->instate = XML_PARSER_CONTENT; - return; + goto out; } NEXTL(sl); cur = CUR_CHAR(l); - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - return; + xmlErrMemory(ctxt); + goto out; } while (IS_CHAR(cur) && ((r != ']') || (s != ']') || (cur != '>'))) { if (len + 5 >= size) { xmlChar *tmp; - if ((size > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, - "CData section too big found", NULL); - xmlFree (buf); - return; - } - tmp = (xmlChar *) xmlRealloc(buf, size * 2 * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size * 2); if (tmp == NULL) { - xmlFree(buf); - xmlErrMemory(ctxt, NULL); - return; + xmlErrMemory(ctxt); + goto out; } buf = tmp; size *= 2; } - COPY_BUF(rl,buf,len,r); + COPY_BUF(buf, len, r); + if (len > maxLength) { + xmlFatalErrMsg(ctxt, XML_ERR_CDATA_NOT_FINISHED, + "CData section too big found\n"); + goto out; + } r = s; rl = sl; s = cur; sl = l; - count++; - if (count > 50) { - SHRINK; - GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } - count = 0; - } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; - ctxt->instate = XML_PARSER_CONTENT; if (cur != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, "CData section not finished\n%.50s\n", buf); - xmlFree(buf); - return; + goto out; } NEXTL(l); @@ -9849,6 +9660,8 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { else if (ctxt->sax->characters != NULL) ctxt->sax->characters(ctxt->userData, buf, len); } + +out: xmlFree(buf); } @@ -9862,13 +9675,13 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { static void xmlParseContentInternal(xmlParserCtxtPtr ctxt) { - int nameNr = ctxt->nameNr; + int oldNameNr = ctxt->nameNr; + int oldSpaceNr = ctxt->spaceNr; + int oldNodeNr = ctxt->nodeNr; GROW; - while ((RAW != 0) && - (ctxt->instate != XML_PARSER_EOF)) { - int id = ctxt->input->id; - unsigned long cons = CUR_CONSUMED; + while ((ctxt->input->cur < ctxt->input->end) && + (PARSER_STOPPED(ctxt) == 0)) { const xmlChar *cur = ctxt->input->cur; /* @@ -9892,7 +9705,6 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { else if ((*cur == '<') && (NXT(1) == '!') && (NXT(2) == '-') && (NXT(3) == '-')) { xmlParseComment(ctxt); - ctxt->instate = XML_PARSER_CONTENT; } /* @@ -9900,7 +9712,7 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { */ else if (*cur == '<') { if (NXT(1) == '/') { - if (ctxt->nameNr <= nameNr) + if (ctxt->nameNr <= oldNameNr) break; xmlParseElementEnd(ctxt); } else { @@ -9917,53 +9729,74 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { xmlParseReference(ctxt); } - /* - * Last case, text. Note that References are handled directly. - */ - else { - xmlParseCharData(ctxt, 0); - } + /* + * Last case, text. Note that References are handled directly. + */ + else { + xmlParseCharDataInternal(ctxt, 0); + } + + SHRINK; + GROW; + } + + if ((ctxt->nameNr > oldNameNr) && + (ctxt->input->cur >= ctxt->input->end) && + (ctxt->wellFormed)) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + } + + /* + * Clean up in error case + */ + + while (ctxt->nodeNr > oldNodeNr) + nodePop(ctxt); - GROW; - SHRINK; + while (ctxt->nameNr > oldNameNr) { + xmlStartTag *tag = &ctxt->pushTab[ctxt->nameNr - 1]; - if ((cons == CUR_CONSUMED) && (id == ctxt->input->id)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "detected an error in element content\n"); - xmlHaltParser(ctxt); - break; - } + if (tag->nsNr != 0) + xmlParserNsPop(ctxt, tag->nsNr); + + namePop(ctxt); } + + while (ctxt->spaceNr > oldSpaceNr) + spacePop(ctxt); } /** * xmlParseContent: * @ctxt: an XML parser context * - * Parse a content sequence. Stops at EOF or 'nameNr; + if ((ctxt == NULL) || (ctxt->input == NULL)) + return; + + xmlCtxtInitializeLate(ctxt); xmlParseContentInternal(ctxt); - if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) { - const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; - int line = ctxt->pushTab[ctxt->nameNr - 1].line; - xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, - "Premature end of data in tag %s line %d\n", - name, line, NULL); - } + if (ctxt->input->cur < ctxt->input->end) + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); } /** * xmlParseElement: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML element * * [39] element ::= EmptyElemTag | STag content ETag @@ -9980,15 +9813,15 @@ xmlParseElement(xmlParserCtxtPtr ctxt) { return; xmlParseContentInternal(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return; - if (CUR == 0) { - const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; - int line = ctxt->pushTab[ctxt->nameNr - 1].line; - xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, - "Premature end of data in tag %s line %d\n", - name, line, NULL); + if (ctxt->input->cur >= ctxt->input->end) { + if (ctxt->wellFormed) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + } return; } @@ -10001,22 +9834,24 @@ xmlParseElement(xmlParserCtxtPtr ctxt) { * * Parse the start of an XML element. Returns -1 in case of error, 0 if an * opening tag was parsed, 1 if an empty element was parsed. + * + * Always consumes '<'. */ static int xmlParseElementStart(xmlParserCtxtPtr ctxt) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; xmlParserNodeInfo node_info; - int line, tlen = 0; - xmlNodePtr ret; - int nsNr = ctxt->nsNr; + int line; + xmlNodePtr cur; + int nbNs = 0; - if (((unsigned int) ctxt->nameNr > xmlParserMaxDepth) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, - "Excessive depth in document: %d use XML_PARSE_HUGE option\n", - xmlParserMaxDepth); + if (ctxt->nameNr > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "Excessive depth in document: %d use XML_PARSE_HUGE option\n", + ctxt->nameNr); xmlHaltParser(ctxt); return(-1); } @@ -10039,19 +9874,17 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { #ifdef LIBXML_SAX1_ENABLED if (ctxt->sax2) #endif /* LIBXML_SAX1_ENABLED */ - name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); + name = xmlParseStartTag2(ctxt, &prefix, &URI, &nbNs); #ifdef LIBXML_SAX1_ENABLED else name = xmlParseStartTag(ctxt); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if (name == NULL) { spacePop(ctxt); return(-1); } - nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr); - ret = ctxt->node; + nameNsPush(ctxt, name, prefix, URI, line, nbNs); + cur = ctxt->node; #ifdef LIBXML_VALID_ENABLED /* @@ -10082,19 +9915,25 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { } namePop(ctxt); spacePop(ctxt); - if (nsNr != ctxt->nsNr) - nsPop(ctxt, ctxt->nsNr - nsNr); - if ( ret != NULL && ctxt->record_info ) { - node_info.end_pos = ctxt->input->consumed + - (CUR_PTR - ctxt->input->base); - node_info.end_line = ctxt->input->line; - node_info.node = ret; - xmlParserAddNodeInfo(ctxt, &node_info); + if (nbNs > 0) + xmlParserNsPop(ctxt, nbNs); + if (cur != NULL && ctxt->record_info) { + node_info.node = cur; + node_info.end_pos = ctxt->input->consumed + + (CUR_PTR - ctxt->input->base); + node_info.end_line = ctxt->input->line; + xmlParserAddNodeInfo(ctxt, &node_info); } return(1); } if (RAW == '>') { NEXT1; + if (cur != NULL && ctxt->record_info) { + node_info.node = cur; + node_info.end_pos = 0; + node_info.end_line = 0; + xmlParserAddNodeInfo(ctxt, &node_info); + } } else { xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_GT_REQUIRED, "Couldn't find end of Start Tag %s line %d\n", @@ -10106,19 +9945,8 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { nodePop(ctxt); namePop(ctxt); spacePop(ctxt); - if (nsNr != ctxt->nsNr) - nsPop(ctxt, ctxt->nsNr - nsNr); - - /* - * Capture end position and add node - */ - if ( ret != NULL && ctxt->record_info ) { - node_info.end_pos = ctxt->input->consumed + - (CUR_PTR - ctxt->input->base); - node_info.end_line = ctxt->input->line; - node_info.node = ret; - xmlParserAddNodeInfo(ctxt, &node_info); - } + if (nbNs > 0) + xmlParserNsPop(ctxt, nbNs); return(-1); } @@ -10129,15 +9957,17 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { * xmlParseElementEnd: * @ctxt: an XML parser context * - * Parse the end of an XML element. + * Parse the end of an XML element. Always consumes 'node; + xmlNodePtr cur = ctxt->node; - if (ctxt->nameNr <= 0) + if (ctxt->nameNr <= 0) { + if ((RAW == '<') && (NXT(1) == '/')) + SKIP(2); return; + } /* * parse the end of tag: 'record_info ) { - node_info.end_pos = ctxt->input->consumed + - (CUR_PTR - ctxt->input->base); - node_info.end_line = ctxt->input->line; - node_info.node = ret; - xmlParserAddNodeInfo(ctxt, &node_info); + if (cur != NULL && ctxt->record_info) { + xmlParserNodeInfoPtr node_info; + + node_info = (xmlParserNodeInfoPtr) xmlParserFindNodeInfo(ctxt, cur); + if (node_info != NULL) { + node_info->end_pos = ctxt->input->consumed + + (CUR_PTR - ctxt->input->base); + node_info->end_line = ctxt->input->line; + } } } @@ -10167,6 +10000,8 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt) { * xmlParseVersionNum: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the XML version value. * * [26] VersionNum ::= '1.' [0-9]+ @@ -10182,9 +10017,9 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) { int size = 10; xmlChar cur; - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } cur = CUR; @@ -10207,10 +10042,10 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) { xmlChar *tmp; size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } buf = tmp; @@ -10227,6 +10062,8 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) { * xmlParseVersionInfo: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the XML version. * * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ") @@ -10274,6 +10111,8 @@ xmlParseVersionInfo(xmlParserCtxtPtr ctxt) { * xmlParseEncName: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the XML encoding name * * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* @@ -10285,14 +10124,17 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; int len = 0; int size = 10; + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_TEXT_LENGTH : + XML_MAX_NAME_LENGTH; xmlChar cur; cur = CUR; if (((cur >= 'a') && (cur <= 'z')) || ((cur >= 'A') && (cur <= 'Z'))) { - buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } @@ -10308,22 +10150,22 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) { xmlChar *tmp; size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); return(NULL); } buf = tmp; } buf[len++] = cur; + if (len > maxLength) { + xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "EncName"); + xmlFree(buf); + return(NULL); + } NEXT; cur = CUR; - if (cur == 0) { - SHRINK; - GROW; - cur = CUR; - } } buf[len] = 0; } else { @@ -10336,6 +10178,8 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) { * xmlParseEncodingDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the XML encoding declaration * * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'") @@ -10350,106 +10194,53 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) { xmlChar *encoding = NULL; SKIP_BLANKS; - if (CMP8(CUR_PTR, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g')) { - SKIP(8); - SKIP_BLANKS; - if (RAW != '=') { - xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); - return(NULL); - } - NEXT; - SKIP_BLANKS; - if (RAW == '"') { - NEXT; - encoding = xmlParseEncName(ctxt); - if (RAW != '"') { - xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); - xmlFree((xmlChar *) encoding); - return(NULL); - } else - NEXT; - } else if (RAW == '\''){ - NEXT; - encoding = xmlParseEncName(ctxt); - if (RAW != '\'') { - xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); - xmlFree((xmlChar *) encoding); - return(NULL); - } else - NEXT; - } else { - xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); - } + if (CMP8(CUR_PTR, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g') == 0) + return(NULL); - /* - * Non standard parsing, allowing the user to ignore encoding - */ - if (ctxt->options & XML_PARSE_IGNORE_ENC) { - xmlFree((xmlChar *) encoding); + SKIP(8); + SKIP_BLANKS; + if (RAW != '=') { + xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); + return(NULL); + } + NEXT; + SKIP_BLANKS; + if (RAW == '"') { + NEXT; + encoding = xmlParseEncName(ctxt); + if (RAW != '"') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + xmlFree((xmlChar *) encoding); return(NULL); - } - - /* - * UTF-16 encoding switch has already taken place at this stage, - * more over the little-endian/big-endian selection is already done - */ - if ((encoding != NULL) && - ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-16")) || - (!xmlStrcasecmp(encoding, BAD_CAST "UTF16")))) { - /* - * If no encoding was passed to the parser, that we are - * using UTF-16 and no decoder is present i.e. the - * document is apparently UTF-8 compatible, then raise an - * encoding mismatch fatal error - */ - if ((ctxt->encoding == NULL) && - (ctxt->input->buf != NULL) && - (ctxt->input->buf->encoder == NULL)) { - xmlFatalErrMsg(ctxt, XML_ERR_INVALID_ENCODING, - "Document labelled UTF-16 but has UTF-8 content\n"); - } - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = encoding; - } - /* - * UTF-8 encoding is handled natively - */ - else if ((encoding != NULL) && - ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-8")) || - (!xmlStrcasecmp(encoding, BAD_CAST "UTF8")))) { - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = encoding; - } - else if (encoding != NULL) { - xmlCharEncodingHandlerPtr handler; - - if (ctxt->input->encoding != NULL) - xmlFree((xmlChar *) ctxt->input->encoding); - ctxt->input->encoding = encoding; - - handler = xmlFindCharEncodingHandler((const char *) encoding); - if (handler != NULL) { - if (xmlSwitchToEncoding(ctxt, handler) < 0) { - /* failed to convert */ - ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING; - return(NULL); - } - } else { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", encoding); - return(NULL); - } - } + } else + NEXT; + } else if (RAW == '\''){ + NEXT; + encoding = xmlParseEncName(ctxt); + if (RAW != '\'') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + xmlFree((xmlChar *) encoding); + return(NULL); + } else + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); } - return(encoding); + + if (encoding == NULL) + return(NULL); + + xmlSetDeclaredEncoding(ctxt, encoding); + + return(ctxt->encoding); } /** * xmlParseSDDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse the XML standalone declaration * * [32] SDDecl ::= S 'standalone' Eq @@ -10534,6 +10325,8 @@ xmlParseSDDecl(xmlParserCtxtPtr ctxt) { * xmlParseXMLDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML declaration header * * [23] XMLDecl ::= '' @@ -10548,7 +10341,8 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { * XML declaration but it does not have a standalone attribute. * It will be overwritten later if a standalone attribute is found. */ - ctxt->input->standalone = -2; + + ctxt->standalone = -2; /* * We know that 'errNo == XML_ERR_UNSUPPORTED_ENCODING) || - (ctxt->instate == XML_PARSER_EOF)) { - /* - * The XML REC instructs us to stop parsing right here - */ - return; - } /* * We may have the standalone status. */ - if ((ctxt->input->encoding != NULL) && (!IS_BLANK_CH(RAW))) { + if ((ctxt->encoding != NULL) && (!IS_BLANK_CH(RAW))) { if ((RAW == '?') && (NXT(1) == '>')) { SKIP(2); return; @@ -10629,7 +10416,7 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { GROW; SKIP_BLANKS; - ctxt->input->standalone = xmlParseSDDecl(ctxt); + ctxt->standalone = xmlParseSDDecl(ctxt); SKIP_BLANKS; if ((RAW == '?') && (NXT(1) == '>')) { @@ -10639,9 +10426,15 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); NEXT; } else { + int c; + xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); - MOVETO_ENDTAG(CUR_PTR); - NEXT; + while ((PARSER_STOPPED(ctxt) == 0) && + ((c = CUR) != 0)) { + NEXT; + if (c == '>') + break; + } } } @@ -10649,6 +10442,8 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { * xmlParseMisc: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML Misc* optional field. * * [27] Misc ::= Comment | PI | S @@ -10656,7 +10451,7 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { void xmlParseMisc(xmlParserCtxtPtr ctxt) { - while (ctxt->instate != XML_PARSER_EOF) { + while (PARSER_STOPPED(ctxt) == 0) { SKIP_BLANKS; GROW; if ((RAW == '<') && (NXT(1) == '?')) { @@ -10669,28 +10464,52 @@ xmlParseMisc(xmlParserCtxtPtr ctxt) { } } +static void +xmlFinishDocument(xmlParserCtxtPtr ctxt) { + xmlDocPtr doc; + + /* + * SAX: end of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + + doc = ctxt->myDoc; + if (doc != NULL) { + if (ctxt->wellFormed) { + doc->properties |= XML_DOC_WELLFORMED; + if (ctxt->valid) + doc->properties |= XML_DOC_DTDVALID; + if (ctxt->nsWellFormed) + doc->properties |= XML_DOC_NSVALID; + } + + if (ctxt->options & XML_PARSE_OLD10) + doc->properties |= XML_DOC_OLD10; + + /* + * Remove locally kept entity definitions if the tree was not built + */ + if (xmlStrEqual(doc->version, SAX_COMPAT_MODE)) { + xmlFreeDoc(doc); + ctxt->myDoc = NULL; + } + } +} + /** * xmlParseDocument: * @ctxt: an XML parser context * - * parse an XML document (and build a tree if using the standard SAX - * interface). - * - * [1] document ::= prolog element Misc* + * Parse an XML document and invoke the SAX handlers. This is useful + * if you're only interested in custom SAX callbacks. If you want a + * document tree, use xmlCtxtParseDocument. * - * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? - * - * Returns 0, -1 in case of error. the parser context is augmented - * as a result of the parsing. + * Returns 0, -1 in case of error. */ int xmlParseDocument(xmlParserCtxtPtr ctxt) { - xmlChar start[4]; - xmlCharEncoding enc; - - xmlInitParser(); - if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1); @@ -10699,70 +10518,37 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { /* * SAX: detecting the level. */ - xmlDetectSAX2(ctxt); - - /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); + xmlCtxtInitializeLate(ctxt); - if ((ctxt->encoding == NULL) && - ((ctxt->input->end - ctxt->input->cur) >= 4)) { - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. - */ - start[0] = RAW; - start[1] = NXT(1); - start[2] = NXT(2); - start[3] = NXT(3); - enc = xmlDetectCharEncoding(&start[0], 4); - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); } + xmlDetectEncoding(ctxt); if (CUR == 0) { xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); return(-1); } - /* - * Check for the XMLDecl in the Prolog. - * do not GROW here to avoid the detected encoder to decode more - * than just the first line, unless the amount of data is really - * too small to hold "input->end - ctxt->input->cur) < 35) { - GROW; - } + GROW; if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { /* * Note that we will switch encoding on the fly. */ xmlParseXMLDecl(ctxt); - if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || - (ctxt->instate == XML_PARSER_EOF)) { - /* - * The XML REC instructs us to stop parsing right here - */ - return(-1); - } - ctxt->standalone = ctxt->input->standalone; SKIP_BLANKS; } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if (ctxt->version == NULL) { + xmlErrMemory(ctxt); + return(-1); + } } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if ((ctxt->myDoc != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL) && (ctxt->input->buf->compressed >= 0)) { ctxt->myDoc->compression = ctxt->input->buf->compressed; @@ -10783,10 +10569,7 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { ctxt->inSubset = 1; xmlParseDocTypeDecl(ctxt); if (RAW == '[') { - ctxt->instate = XML_PARSER_DTD; xmlParseInternalSubset(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); } /* @@ -10797,13 +10580,10 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { (!ctxt->disableSAX)) ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, ctxt->extSubSystem, ctxt->extSubURI); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); - ctxt->instate = XML_PARSER_PROLOG; xmlParseMisc(ctxt); } @@ -10812,53 +10592,37 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { */ GROW; if (RAW != '<') { - xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, - "Start tag expected, '<' not found\n"); + if (ctxt->wellFormed) + xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, + "Start tag expected, '<' not found\n"); } else { - ctxt->instate = XML_PARSER_CONTENT; xmlParseElement(ctxt); - ctxt->instate = XML_PARSER_EPILOG; - /* * The Misc part at the end */ xmlParseMisc(ctxt); - if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); - } - ctxt->instate = XML_PARSER_EOF; + if (ctxt->input->cur < ctxt->input->end) { + if (ctxt->wellFormed) + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); + } else if ((ctxt->input->buf != NULL) && + (ctxt->input->buf->encoder != NULL) && + (ctxt->input->buf->error == 0) && + (!xmlBufIsEmpty(ctxt->input->buf->raw))) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "Truncated multi-byte sequence at EOF\n"); + } } - /* - * SAX: end of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); - - /* - * Remove locally kept entity definitions if the tree was not built - */ - if ((ctxt->myDoc != NULL) && - (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) { - xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; - } + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); - if ((ctxt->wellFormed) && (ctxt->myDoc != NULL)) { - ctxt->myDoc->properties |= XML_DOC_WELLFORMED; - if (ctxt->valid) - ctxt->myDoc->properties |= XML_DOC_DTDVALID; - if (ctxt->nsWellFormed) - ctxt->myDoc->properties |= XML_DOC_NSVALID; - if (ctxt->options & XML_PARSE_OLD10) - ctxt->myDoc->properties |= XML_DOC_OLD10; - } if (! ctxt->wellFormed) { ctxt->valid = 0; return(-1); } + return(0); } @@ -10878,38 +10642,17 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { int xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { - xmlChar start[4]; - xmlCharEncoding enc; - if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1); - xmlDetectSAX2(ctxt); - - GROW; - - /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); + xmlCtxtInitializeLate(ctxt); - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. - */ - if ((ctxt->input->end - ctxt->input->cur) >= 4) { - start[0] = RAW; - start[1] = NXT(1); - start[2] = NXT(2); - start[3] = NXT(3); - enc = xmlDetectCharEncoding(start, 4); - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); } + xmlDetectEncoding(ctxt); if (CUR == 0) { xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); @@ -10925,193 +10668,300 @@ xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { * Note that we will switch encoding on the fly. */ xmlParseXMLDecl(ctxt); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right here - */ - return(-1); - } SKIP_BLANKS; } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); /* * Doing validity checking on chunk doesn't make sense */ - ctxt->instate = XML_PARSER_CONTENT; + ctxt->options &= ~XML_PARSE_DTDVALID; ctxt->validate = 0; - ctxt->loadsubset = 0; ctxt->depth = 0; - xmlParseContent(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); + xmlParseContentInternal(ctxt); - if ((RAW == '<') && (NXT(1) == '/')) { + if (ctxt->input->cur < ctxt->input->end) xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + + /* + * SAX: end of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + + if (! ctxt->wellFormed) return(-1); + return(0); +} + +#ifdef LIBXML_PUSH_ENABLED +/************************************************************************ + * * + * Progressive parsing interfaces * + * * + ************************************************************************/ + +/** + * xmlParseLookupChar: + * @ctxt: an XML parser context + * @c: character + * + * Check whether the input buffer contains a character. + */ +static int +xmlParseLookupChar(xmlParserCtxtPtr ctxt, int c) { + const xmlChar *cur; + + if (ctxt->checkIndex == 0) { + cur = ctxt->input->cur + 1; + } else { + cur = ctxt->input->cur + ctxt->checkIndex; + } + + if (memchr(cur, c, ctxt->input->end - cur) == NULL) { + size_t index = ctxt->input->end - ctxt->input->cur; + + if (index > LONG_MAX) { + ctxt->checkIndex = 0; + return(1); + } + ctxt->checkIndex = index; + return(0); + } else { + ctxt->checkIndex = 0; + return(1); + } +} + +/** + * xmlParseLookupString: + * @ctxt: an XML parser context + * @startDelta: delta to apply at the start + * @str: string + * @strLen: length of string + * + * Check whether the input buffer contains a string. + */ +static const xmlChar * +xmlParseLookupString(xmlParserCtxtPtr ctxt, size_t startDelta, + const char *str, size_t strLen) { + const xmlChar *cur, *term; + + if (ctxt->checkIndex == 0) { + cur = ctxt->input->cur + startDelta; + } else { + cur = ctxt->input->cur + ctxt->checkIndex; + } + + term = BAD_CAST strstr((const char *) cur, str); + if (term == NULL) { + const xmlChar *end = ctxt->input->end; + size_t index; + + /* Rescan (strLen - 1) characters. */ + if ((size_t) (end - cur) < strLen) + end = cur; + else + end -= strLen - 1; + index = end - ctxt->input->cur; + if (index > LONG_MAX) { + ctxt->checkIndex = 0; + return(ctxt->input->end - strLen); + } + ctxt->checkIndex = index; + } else { + ctxt->checkIndex = 0; + } + + return(term); +} + +/** + * xmlParseLookupCharData: + * @ctxt: an XML parser context + * + * Check whether the input buffer contains terminated char data. + */ +static int +xmlParseLookupCharData(xmlParserCtxtPtr ctxt) { + const xmlChar *cur = ctxt->input->cur + ctxt->checkIndex; + const xmlChar *end = ctxt->input->end; + size_t index; + + while (cur < end) { + if ((*cur == '<') || (*cur == '&')) { + ctxt->checkIndex = 0; + return(1); + } + cur++; } - /* - * SAX: end of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); - - if (! ctxt->wellFormed) return(-1); + index = cur - ctxt->input->cur; + if (index > LONG_MAX) { + ctxt->checkIndex = 0; + return(1); + } + ctxt->checkIndex = index; return(0); } -#ifdef LIBXML_PUSH_ENABLED -/************************************************************************ - * * - * Progressive parsing interfaces * - * * - ************************************************************************/ - /** - * xmlParseLookupSequence: + * xmlParseLookupGt: * @ctxt: an XML parser context - * @first: the first char to lookup - * @next: the next char to lookup or zero - * @third: the next char to lookup or zero - * - * Try to find if a sequence (first, next, third) or just (first next) or - * (first) is available in the input stream. - * This function has a side effect of (possibly) incrementing ctxt->checkIndex - * to avoid rescanning sequences of bytes, it DOES change the state of the - * parser, do not use liberally. * - * Returns the index to the current parsing point if the full sequence - * is available, -1 otherwise. + * Check whether there's enough data in the input buffer to finish parsing + * a start tag. This has to take quotes into account. */ static int -xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first, - xmlChar next, xmlChar third) { - int base, len; - xmlParserInputPtr in; - const xmlChar *buf; - - in = ctxt->input; - if (in == NULL) return(-1); - base = in->cur - in->base; - if (base < 0) return(-1); - if (ctxt->checkIndex > base) - base = ctxt->checkIndex; - if (in->buf == NULL) { - buf = in->base; - len = in->length; - } else { - buf = xmlBufContent(in->buf->buffer); - len = xmlBufUse(in->buf->buffer); - } - /* take into account the sequence length */ - if (third) len -= 2; - else if (next) len --; - for (;base < len;base++) { - if (buf[base] == first) { - if (third != 0) { - if ((buf[base + 1] != next) || - (buf[base + 2] != third)) continue; - } else if (next != 0) { - if (buf[base + 1] != next) continue; - } - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - if (next == 0) - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c' found at %d\n", - first, base); - else if (third == 0) - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c%c' found at %d\n", - first, next, base); - else - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c%c%c' found at %d\n", - first, next, third, base); -#endif - return(base - (in->cur - in->base)); - } - } - ctxt->checkIndex = base; -#ifdef DEBUG_PUSH - if (next == 0) - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c' failed\n", first); - else if (third == 0) - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c%c' failed\n", first, next); +xmlParseLookupGt(xmlParserCtxtPtr ctxt) { + const xmlChar *cur; + const xmlChar *end = ctxt->input->end; + int state = ctxt->endCheckState; + size_t index; + + if (ctxt->checkIndex == 0) + cur = ctxt->input->cur + 1; else - xmlGenericError(xmlGenericErrorContext, - "PP: lookup '%c%c%c' failed\n", first, next, third); -#endif - return(-1); + cur = ctxt->input->cur + ctxt->checkIndex; + + while (cur < end) { + if (state) { + if (*cur == state) + state = 0; + } else if (*cur == '\'' || *cur == '"') { + state = *cur; + } else if (*cur == '>') { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return(1); + } + cur++; + } + + index = cur - ctxt->input->cur; + if (index > LONG_MAX) { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return(1); + } + ctxt->checkIndex = index; + ctxt->endCheckState = state; + return(0); } /** - * xmlParseGetLasts: + * xmlParseLookupInternalSubset: * @ctxt: an XML parser context - * @lastlt: pointer to store the last '<' from the input - * @lastgt: pointer to store the last '>' from the input * - * Lookup the last < and > in the current chunk + * Check whether there's enough data in the input buffer to finish parsing + * the internal subset. */ -static void -xmlParseGetLasts(xmlParserCtxtPtr ctxt, const xmlChar **lastlt, - const xmlChar **lastgt) { - const xmlChar *tmp; +static int +xmlParseLookupInternalSubset(xmlParserCtxtPtr ctxt) { + /* + * Sorry, but progressive parsing of the internal subset is not + * supported. We first check that the full content of the internal + * subset is available and parsing is launched only at that point. + * Internal subset ends with "']' S? '>'" in an unescaped section and + * not in a ']]>' sequence which are conditional sections. + */ + const xmlChar *cur, *start; + const xmlChar *end = ctxt->input->end; + int state = ctxt->endCheckState; + size_t index; - if ((ctxt == NULL) || (lastlt == NULL) || (lastgt == NULL)) { - xmlGenericError(xmlGenericErrorContext, - "Internal error: xmlParseGetLasts\n"); - return; - } - if ((ctxt->progressive != 0) && (ctxt->inputNr == 1)) { - tmp = ctxt->input->end; - tmp--; - while ((tmp >= ctxt->input->base) && (*tmp != '<')) tmp--; - if (tmp < ctxt->input->base) { - *lastlt = NULL; - *lastgt = NULL; - } else { - *lastlt = tmp; - tmp++; - while ((tmp < ctxt->input->end) && (*tmp != '>')) { - if (*tmp == '\'') { - tmp++; - while ((tmp < ctxt->input->end) && (*tmp != '\'')) tmp++; - if (tmp < ctxt->input->end) tmp++; - } else if (*tmp == '"') { - tmp++; - while ((tmp < ctxt->input->end) && (*tmp != '"')) tmp++; - if (tmp < ctxt->input->end) tmp++; - } else - tmp++; - } - if (tmp < ctxt->input->end) - *lastgt = tmp; - else { - tmp = *lastlt; - tmp--; - while ((tmp >= ctxt->input->base) && (*tmp != '>')) tmp--; - if (tmp >= ctxt->input->base) - *lastgt = tmp; - else - *lastgt = NULL; - } - } + if (ctxt->checkIndex == 0) { + cur = ctxt->input->cur + 1; } else { - *lastlt = NULL; - *lastgt = NULL; + cur = ctxt->input->cur + ctxt->checkIndex; + } + start = cur; + + while (cur < end) { + if (state == '-') { + if ((*cur == '-') && + (cur[1] == '-') && + (cur[2] == '>')) { + state = 0; + cur += 3; + start = cur; + continue; + } + } + else if (state == ']') { + if (*cur == '>') { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return(1); + } + if (IS_BLANK_CH(*cur)) { + state = ' '; + } else if (*cur != ']') { + state = 0; + start = cur; + continue; + } + } + else if (state == ' ') { + if (*cur == '>') { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return(1); + } + if (!IS_BLANK_CH(*cur)) { + state = 0; + start = cur; + continue; + } + } + else if (state != 0) { + if (*cur == state) { + state = 0; + start = cur + 1; + } + } + else if (*cur == '<') { + if ((cur[1] == '!') && + (cur[2] == '-') && + (cur[3] == '-')) { + state = '-'; + cur += 4; + /* Don't treat as comment */ + start = cur; + continue; + } + } + else if ((*cur == '"') || (*cur == '\'') || (*cur == ']')) { + state = *cur; + } + + cur++; } + + /* + * Rescan the three last characters to detect "" + * split across chunks. + */ + if ((state == 0) || (state == '-')) { + if (cur - start < 3) + cur = start; + else + cur -= 3; + } + index = cur - ctxt->input->cur; + if (index > LONG_MAX) { + ctxt->checkIndex = 0; + ctxt->endCheckState = 0; + return(1); + } + ctxt->checkIndex = index; + ctxt->endCheckState = state; + return(0); } + /** * xmlCheckCdataPush: * @cur: pointer to the block of characters @@ -11192,103 +11042,19 @@ xmlCheckCdataPush(const xmlChar *utf, int len, int complete) { static int xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { int ret = 0; - int avail, tlen; + size_t avail; xmlChar cur, next; - const xmlChar *lastlt, *lastgt; if (ctxt->input == NULL) return(0); -#ifdef DEBUG_PUSH - switch (ctxt->instate) { - case XML_PARSER_EOF: - xmlGenericError(xmlGenericErrorContext, - "PP: try EOF\n"); break; - case XML_PARSER_START: - xmlGenericError(xmlGenericErrorContext, - "PP: try START\n"); break; - case XML_PARSER_MISC: - xmlGenericError(xmlGenericErrorContext, - "PP: try MISC\n");break; - case XML_PARSER_COMMENT: - xmlGenericError(xmlGenericErrorContext, - "PP: try COMMENT\n");break; - case XML_PARSER_PROLOG: - xmlGenericError(xmlGenericErrorContext, - "PP: try PROLOG\n");break; - case XML_PARSER_START_TAG: - xmlGenericError(xmlGenericErrorContext, - "PP: try START_TAG\n");break; - case XML_PARSER_CONTENT: - xmlGenericError(xmlGenericErrorContext, - "PP: try CONTENT\n");break; - case XML_PARSER_CDATA_SECTION: - xmlGenericError(xmlGenericErrorContext, - "PP: try CDATA_SECTION\n");break; - case XML_PARSER_END_TAG: - xmlGenericError(xmlGenericErrorContext, - "PP: try END_TAG\n");break; - case XML_PARSER_ENTITY_DECL: - xmlGenericError(xmlGenericErrorContext, - "PP: try ENTITY_DECL\n");break; - case XML_PARSER_ENTITY_VALUE: - xmlGenericError(xmlGenericErrorContext, - "PP: try ENTITY_VALUE\n");break; - case XML_PARSER_ATTRIBUTE_VALUE: - xmlGenericError(xmlGenericErrorContext, - "PP: try ATTRIBUTE_VALUE\n");break; - case XML_PARSER_DTD: - xmlGenericError(xmlGenericErrorContext, - "PP: try DTD\n");break; - case XML_PARSER_EPILOG: - xmlGenericError(xmlGenericErrorContext, - "PP: try EPILOG\n");break; - case XML_PARSER_PI: - xmlGenericError(xmlGenericErrorContext, - "PP: try PI\n");break; - case XML_PARSER_IGNORE: - xmlGenericError(xmlGenericErrorContext, - "PP: try IGNORE\n");break; - } -#endif - if ((ctxt->input != NULL) && (ctxt->input->cur - ctxt->input->base > 4096)) { - xmlSHRINK(ctxt); - ctxt->checkIndex = 0; + xmlParserShrink(ctxt); } - xmlParseGetLasts(ctxt, &lastlt, &lastgt); - - while (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) - return(0); - if (ctxt->input == NULL) break; - if (ctxt->input->buf == NULL) - avail = ctxt->input->length - - (ctxt->input->cur - ctxt->input->base); - else { - /* - * If we are operating on converted input, try to flush - * remaining chars to avoid them stalling in the non-converted - * buffer. But do not do this in document start where - * encoding="..." may not have been read and we work on a - * guessed encoding. - */ - if ((ctxt->instate != XML_PARSER_START) && - (ctxt->input->buf->raw != NULL) && - (xmlBufIsEmpty(ctxt->input->buf->raw) == 0)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, - ctxt->input); - size_t current = ctxt->input->cur - ctxt->input->base; - - xmlParserInputBufferPush(ctxt->input->buf, 0, ""); - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, - base, current); - } - avail = xmlBufUse(ctxt->input->buf->buffer) - - (ctxt->input->cur - ctxt->input->base); - } + while (ctxt->disableSAX == 0) { + avail = ctxt->input->end - ctxt->input->cur; if (avail < 1) goto done; switch (ctxt->instate) { @@ -11298,145 +11064,82 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { */ goto done; case XML_PARSER_START: - if (ctxt->charset == XML_CHAR_ENCODING_NONE) { - xmlChar start[4]; - xmlCharEncoding enc; + /* + * Very first chars read from the document flow. + */ + if ((!terminate) && (avail < 4)) + goto done; - /* - * Very first chars read from the document flow. - */ - if (avail < 4) - goto done; + /* + * We need more bytes to detect EBCDIC code pages. + * See xmlDetectEBCDIC. + */ + if ((CMP4(CUR_PTR, 0x4C, 0x6F, 0xA7, 0x94)) && + (!terminate) && (avail < 200)) + goto done; - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines, - * else xmlSwitchEncoding will set to (default) - * UTF8. - */ - start[0] = RAW; - start[1] = NXT(1); - start[2] = NXT(2); - start[3] = NXT(3); - enc = xmlDetectCharEncoding(start, 4); - xmlSwitchEncoding(ctxt, enc); - break; - } + xmlDetectEncoding(ctxt); + ctxt->instate = XML_PARSER_XML_DECL; + break; - if (avail < 2) + case XML_PARSER_XML_DECL: + if ((!terminate) && (avail < 2)) goto done; cur = ctxt->input->cur[0]; next = ctxt->input->cur[1]; - if (cur == 0) { - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); - xmlHaltParser(ctxt); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EOF\n"); -#endif - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); - goto done; - } if ((cur == '<') && (next == '?')) { /* PI or XML decl */ - if (avail < 5) return(ret); if ((!terminate) && - (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) - return(ret); - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); + (!xmlParseLookupString(ctxt, 2, "?>", 2))) + goto done; if ((ctxt->input->cur[2] == 'x') && (ctxt->input->cur[3] == 'm') && (ctxt->input->cur[4] == 'l') && (IS_BLANK_CH(ctxt->input->cur[5]))) { ret += 5; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing XML Decl\n"); -#endif xmlParseXMLDecl(ctxt); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right - * here - */ - xmlHaltParser(ctxt); - return(0); - } - ctxt->standalone = ctxt->input->standalone; - if ((ctxt->encoding == NULL) && - (ctxt->input->encoding != NULL)) - ctxt->encoding = xmlStrdup(ctxt->input->encoding); - if ((ctxt->sax) && (ctxt->sax->startDocument) && - (!ctxt->disableSAX)) - ctxt->sax->startDocument(ctxt->userData); - ctxt->instate = XML_PARSER_MISC; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering MISC\n"); -#endif } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); - if ((ctxt->sax) && (ctxt->sax->startDocument) && - (!ctxt->disableSAX)) - ctxt->sax->startDocument(ctxt->userData); - ctxt->instate = XML_PARSER_MISC; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering MISC\n"); -#endif + if (ctxt->version == NULL) { + xmlErrMemory(ctxt); + break; + } } } else { - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); if (ctxt->version == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); break; } - if ((ctxt->sax) && (ctxt->sax->startDocument) && - (!ctxt->disableSAX)) - ctxt->sax->startDocument(ctxt->userData); - ctxt->instate = XML_PARSER_MISC; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering MISC\n"); -#endif } + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); + } + if ((ctxt->sax) && (ctxt->sax->startDocument) && + (!ctxt->disableSAX)) + ctxt->sax->startDocument(ctxt->userData); + ctxt->instate = XML_PARSER_MISC; break; case XML_PARSER_START_TAG: { const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; int line = ctxt->input->line; - int nsNr = ctxt->nsNr; + int nbNs = 0; - if ((avail < 2) && (ctxt->inputNr == 1)) + if ((!terminate) && (avail < 2)) goto done; cur = ctxt->input->cur[0]; if (cur != '<') { - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); - xmlHaltParser(ctxt); - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, + "Start tag expected, '<' not found"); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); goto done; } - if (!terminate) { - if (ctxt->progressive) { - /* > can be found unescaped in attribute values */ - if ((lastgt == NULL) || (ctxt->input->cur >= lastgt)) - goto done; - } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { - goto done; - } - } + if ((!terminate) && (!xmlParseLookupGt(ctxt))) + goto done; if (ctxt->spaceNr == 0) spacePush(ctxt, -1); else if (*ctxt->space == -2) @@ -11446,18 +11149,15 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { #ifdef LIBXML_SAX1_ENABLED if (ctxt->sax2) #endif /* LIBXML_SAX1_ENABLED */ - name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); + name = xmlParseStartTag2(ctxt, &prefix, &URI, &nbNs); #ifdef LIBXML_SAX1_ENABLED else name = xmlParseStartTag(ctxt); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) - goto done; if (name == NULL) { spacePop(ctxt); - xmlHaltParser(ctxt); - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); goto done; } #ifdef LIBXML_VALID_ENABLED @@ -11483,8 +11183,8 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (!ctxt->disableSAX)) ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); - if (ctxt->nsNr - nsNr > 0) - nsPop(ctxt, ctxt->nsNr - nsNr); + if (nbNs > 0) + xmlParserNsPop(ctxt, nbNs); #ifdef LIBXML_SAX1_ENABLED } else { if ((ctxt->sax != NULL) && @@ -11493,93 +11193,81 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->sax->endElement(ctxt->userData, name); #endif /* LIBXML_SAX1_ENABLED */ } - if (ctxt->instate == XML_PARSER_EOF) - goto done; spacePop(ctxt); - if (ctxt->nameNr == 0) { - ctxt->instate = XML_PARSER_EPILOG; - } else { - ctxt->instate = XML_PARSER_CONTENT; - } - ctxt->progressive = 1; - break; - } - if (RAW == '>') { + } else if (RAW == '>') { NEXT; + nameNsPush(ctxt, name, prefix, URI, line, nbNs); } else { xmlFatalErrMsgStr(ctxt, XML_ERR_GT_REQUIRED, "Couldn't find end of Start Tag %s\n", name); nodePop(ctxt); spacePop(ctxt); + if (nbNs > 0) + xmlParserNsPop(ctxt, nbNs); } - nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->progressive = 1; + if (ctxt->nameNr == 0) + ctxt->instate = XML_PARSER_EPILOG; + else + ctxt->instate = XML_PARSER_CONTENT; break; } case XML_PARSER_CONTENT: { - int id; - unsigned long cons; - if ((avail < 2) && (ctxt->inputNr == 1)) - goto done; cur = ctxt->input->cur[0]; - next = ctxt->input->cur[1]; - id = ctxt->input->id; - cons = CUR_CONSUMED; - if ((cur == '<') && (next == '/')) { - ctxt->instate = XML_PARSER_END_TAG; - break; - } else if ((cur == '<') && (next == '?')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) { - ctxt->progressive = XML_PARSER_PI; - goto done; - } - xmlParsePI(ctxt); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->progressive = 1; - } else if ((cur == '<') && (next != '!')) { - ctxt->instate = XML_PARSER_START_TAG; - break; - } else if ((cur == '<') && (next == '!') && - (ctxt->input->cur[2] == '-') && - (ctxt->input->cur[3] == '-')) { - int term; - - if (avail < 4) - goto done; - ctxt->input->cur += 4; - term = xmlParseLookupSequence(ctxt, '-', '-', '>'); - ctxt->input->cur -= 4; - if ((!terminate) && (term < 0)) { - ctxt->progressive = XML_PARSER_COMMENT; - goto done; + if (cur == '<') { + if ((!terminate) && (avail < 2)) + goto done; + next = ctxt->input->cur[1]; + + if (next == '/') { + ctxt->instate = XML_PARSER_END_TAG; + break; + } else if (next == '?') { + if ((!terminate) && + (!xmlParseLookupString(ctxt, 2, "?>", 2))) + goto done; + xmlParsePI(ctxt); + ctxt->instate = XML_PARSER_CONTENT; + break; + } else if (next == '!') { + if ((!terminate) && (avail < 3)) + goto done; + next = ctxt->input->cur[2]; + + if (next == '-') { + if ((!terminate) && (avail < 4)) + goto done; + if (ctxt->input->cur[3] == '-') { + if ((!terminate) && + (!xmlParseLookupString(ctxt, 4, "-->", 3))) + goto done; + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_CONTENT; + break; + } + } else if (next == '[') { + if ((!terminate) && (avail < 9)) + goto done; + if ((ctxt->input->cur[2] == '[') && + (ctxt->input->cur[3] == 'C') && + (ctxt->input->cur[4] == 'D') && + (ctxt->input->cur[5] == 'A') && + (ctxt->input->cur[6] == 'T') && + (ctxt->input->cur[7] == 'A') && + (ctxt->input->cur[8] == '[')) { + SKIP(9); + ctxt->instate = XML_PARSER_CDATA_SECTION; + break; + } + } } - xmlParseComment(ctxt); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->progressive = 1; - } else if ((cur == '<') && (ctxt->input->cur[1] == '!') && - (ctxt->input->cur[2] == '[') && - (ctxt->input->cur[3] == 'C') && - (ctxt->input->cur[4] == 'D') && - (ctxt->input->cur[5] == 'A') && - (ctxt->input->cur[6] == 'T') && - (ctxt->input->cur[7] == 'A') && - (ctxt->input->cur[8] == '[')) { - SKIP(9); - ctxt->instate = XML_PARSER_CDATA_SECTION; - break; - } else if ((cur == '<') && (next == '!') && - (avail < 9)) { - goto done; } else if (cur == '&') { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0)) + if ((!terminate) && (!xmlParseLookupChar(ctxt, ';'))) goto done; xmlParseReference(ctxt); + break; } else { /* TODO Avoid the extra copy, handle directly !!! */ /* @@ -11593,42 +11281,21 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { * callbacks between the push and pull versions * of the parser. */ - if ((ctxt->inputNr == 1) && - (avail < XML_PARSER_BIG_BUFFER_SIZE)) { - if (!terminate) { - if (ctxt->progressive) { - if ((lastlt == NULL) || - (ctxt->input->cur > lastlt)) - goto done; - } else if (xmlParseLookupSequence(ctxt, - '<', 0, 0) < 0) { - goto done; - } - } + if (avail < XML_PARSER_BIG_BUFFER_SIZE) { + if ((!terminate) && (!xmlParseLookupCharData(ctxt))) + goto done; } - ctxt->checkIndex = 0; - xmlParseCharData(ctxt, 0); - } - if ((cons == CUR_CONSUMED) && (id == ctxt->input->id)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "detected an error in element content\n"); - xmlHaltParser(ctxt); - break; + ctxt->checkIndex = 0; + xmlParseCharDataInternal(ctxt, !terminate); + break; } + + ctxt->instate = XML_PARSER_START_TAG; break; } case XML_PARSER_END_TAG: - if (avail < 2) + if ((!terminate) && (!xmlParseLookupChar(ctxt, '>'))) goto done; - if (!terminate) { - if (ctxt->progressive) { - /* > can be found unescaped in attribute values */ - if ((lastgt == NULL) || (ctxt->input->cur >= lastgt)) - goto done; - } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { - goto done; - } - } if (ctxt->sax2) { xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]); nameNsPop(ctxt); @@ -11637,9 +11304,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { else xmlParseEndTag1(ctxt, 0); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) { - /* Nothing */ - } else if (ctxt->nameNr == 0) { + if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; } else { ctxt->instate = XML_PARSER_CONTENT; @@ -11650,35 +11315,49 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { * The Push mode need to have the SAX callback for * cdataBlock merge back contiguous callbacks. */ - int base; - - base = xmlParseLookupSequence(ctxt, ']', ']', '>'); - if (base < 0) { - if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) { - int tmp; - - tmp = xmlCheckCdataPush(ctxt->input->cur, - XML_PARSER_BIG_BUFFER_SIZE, 0); - if (tmp < 0) { - tmp = -tmp; - ctxt->input->cur += tmp; - goto encoding_error; - } - if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { - if (ctxt->sax->cdataBlock != NULL) - ctxt->sax->cdataBlock(ctxt->userData, - ctxt->input->cur, tmp); - else if (ctxt->sax->characters != NULL) - ctxt->sax->characters(ctxt->userData, - ctxt->input->cur, tmp); - } - if (ctxt->instate == XML_PARSER_EOF) - goto done; - SKIPL(tmp); - ctxt->checkIndex = 0; - } - goto done; + const xmlChar *term; + + if (terminate) { + /* + * Don't call xmlParseLookupString. If 'terminate' + * is set, checkIndex is invalid. + */ + term = BAD_CAST strstr((const char *) ctxt->input->cur, + "]]>"); + } else { + term = xmlParseLookupString(ctxt, 0, "]]>", 3); + } + + if (term == NULL) { + int tmp, size; + + if (terminate) { + /* Unfinished CDATA section */ + size = ctxt->input->end - ctxt->input->cur; + } else { + if (avail < XML_PARSER_BIG_BUFFER_SIZE + 2) + goto done; + ctxt->checkIndex = 0; + /* XXX: Why don't we pass the full buffer? */ + size = XML_PARSER_BIG_BUFFER_SIZE; + } + tmp = xmlCheckCdataPush(ctxt->input->cur, size, 0); + if (tmp <= 0) { + tmp = -tmp; + ctxt->input->cur += tmp; + goto encoding_error; + } + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt->userData, + ctxt->input->cur, tmp); + else if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + ctxt->input->cur, tmp); + } + SKIPL(tmp); } else { + int base = term - CUR_PTR; int tmp; tmp = xmlCheckCdataPush(ctxt->input->cur, base, 1); @@ -11709,352 +11388,94 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->sax->characters(ctxt->userData, ctxt->input->cur, base); } - if (ctxt->instate == XML_PARSER_EOF) - goto done; SKIPL(base + 3); - ctxt->checkIndex = 0; ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif } break; } case XML_PARSER_MISC: - SKIP_BLANKS; - if (ctxt->input->buf == NULL) - avail = ctxt->input->length - - (ctxt->input->cur - ctxt->input->base); - else - avail = xmlBufUse(ctxt->input->buf->buffer) - - (ctxt->input->cur - ctxt->input->base); - if (avail < 2) - goto done; - cur = ctxt->input->cur[0]; - next = ctxt->input->cur[1]; - if ((cur == '<') && (next == '?')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) { - ctxt->progressive = XML_PARSER_PI; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing PI\n"); -#endif - xmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_MISC; - ctxt->progressive = 1; - ctxt->checkIndex = 0; - } else if ((cur == '<') && (next == '!') && - (ctxt->input->cur[2] == '-') && - (ctxt->input->cur[3] == '-')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) { - ctxt->progressive = XML_PARSER_COMMENT; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing Comment\n"); -#endif - xmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_MISC; - ctxt->progressive = 1; - ctxt->checkIndex = 0; - } else if ((cur == '<') && (next == '!') && - (ctxt->input->cur[2] == 'D') && - (ctxt->input->cur[3] == 'O') && - (ctxt->input->cur[4] == 'C') && - (ctxt->input->cur[5] == 'T') && - (ctxt->input->cur[6] == 'Y') && - (ctxt->input->cur[7] == 'P') && - (ctxt->input->cur[8] == 'E')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0)) { - ctxt->progressive = XML_PARSER_DTD; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing internal subset\n"); -#endif - ctxt->inSubset = 1; - ctxt->progressive = 0; - ctxt->checkIndex = 0; - xmlParseDocTypeDecl(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - if (RAW == '[') { - ctxt->instate = XML_PARSER_DTD; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering DTD\n"); -#endif - } else { - /* - * Create and update the external subset. - */ - ctxt->inSubset = 2; - if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && - (ctxt->sax->externalSubset != NULL)) - ctxt->sax->externalSubset(ctxt->userData, - ctxt->intSubName, ctxt->extSubSystem, - ctxt->extSubURI); - ctxt->inSubset = 0; - xmlCleanSpecialAttr(ctxt); - ctxt->instate = XML_PARSER_PROLOG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering PROLOG\n"); -#endif - } - } else if ((cur == '<') && (next == '!') && - (avail < 9)) { - goto done; - } else { - ctxt->instate = XML_PARSER_START_TAG; - ctxt->progressive = XML_PARSER_START_TAG; - xmlParseGetLasts(ctxt, &lastlt, &lastgt); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif - } - break; - case XML_PARSER_PROLOG: - SKIP_BLANKS; - if (ctxt->input->buf == NULL) - avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); - else - avail = xmlBufUse(ctxt->input->buf->buffer) - - (ctxt->input->cur - ctxt->input->base); - if (avail < 2) - goto done; - cur = ctxt->input->cur[0]; - next = ctxt->input->cur[1]; - if ((cur == '<') && (next == '?')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) { - ctxt->progressive = XML_PARSER_PI; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing PI\n"); -#endif - xmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_PROLOG; - ctxt->progressive = 1; - } else if ((cur == '<') && (next == '!') && - (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) { - ctxt->progressive = XML_PARSER_COMMENT; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing Comment\n"); -#endif - xmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_PROLOG; - ctxt->progressive = 1; - } else if ((cur == '<') && (next == '!') && - (avail < 4)) { - goto done; - } else { - ctxt->instate = XML_PARSER_START_TAG; - if (ctxt->progressive == 0) - ctxt->progressive = XML_PARSER_START_TAG; - xmlParseGetLasts(ctxt, &lastlt, &lastgt); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif - } - break; - case XML_PARSER_EPILOG: - SKIP_BLANKS; - if (ctxt->input->buf == NULL) - avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); - else - avail = xmlBufUse(ctxt->input->buf->buffer) - - (ctxt->input->cur - ctxt->input->base); - if (avail < 2) - goto done; - cur = ctxt->input->cur[0]; - next = ctxt->input->cur[1]; - if ((cur == '<') && (next == '?')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) { - ctxt->progressive = XML_PARSER_PI; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing PI\n"); -#endif - xmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_EPILOG; - ctxt->progressive = 1; - } else if ((cur == '<') && (next == '!') && - (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { - if ((!terminate) && - (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) { - ctxt->progressive = XML_PARSER_COMMENT; - goto done; - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing Comment\n"); -#endif - xmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; - ctxt->instate = XML_PARSER_EPILOG; - ctxt->progressive = 1; - } else if ((cur == '<') && (next == '!') && - (avail < 4)) { - goto done; - } else { - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); - xmlHaltParser(ctxt); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EOF\n"); -#endif - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + case XML_PARSER_PROLOG: + case XML_PARSER_EPILOG: + SKIP_BLANKS; + avail = ctxt->input->end - ctxt->input->cur; + if (avail < 1) goto done; + if (ctxt->input->cur[0] == '<') { + if ((!terminate) && (avail < 2)) + goto done; + next = ctxt->input->cur[1]; + if (next == '?') { + if ((!terminate) && + (!xmlParseLookupString(ctxt, 2, "?>", 2))) + goto done; + xmlParsePI(ctxt); + break; + } else if (next == '!') { + if ((!terminate) && (avail < 3)) + goto done; + + if (ctxt->input->cur[2] == '-') { + if ((!terminate) && (avail < 4)) + goto done; + if (ctxt->input->cur[3] == '-') { + if ((!terminate) && + (!xmlParseLookupString(ctxt, 4, "-->", 3))) + goto done; + xmlParseComment(ctxt); + break; + } + } else if (ctxt->instate == XML_PARSER_MISC) { + if ((!terminate) && (avail < 9)) + goto done; + if ((ctxt->input->cur[2] == 'D') && + (ctxt->input->cur[3] == 'O') && + (ctxt->input->cur[4] == 'C') && + (ctxt->input->cur[5] == 'T') && + (ctxt->input->cur[6] == 'Y') && + (ctxt->input->cur[7] == 'P') && + (ctxt->input->cur[8] == 'E')) { + if ((!terminate) && (!xmlParseLookupGt(ctxt))) + goto done; + ctxt->inSubset = 1; + xmlParseDocTypeDecl(ctxt); + if (RAW == '[') { + ctxt->instate = XML_PARSER_DTD; + } else { + /* + * Create and update the external subset. + */ + ctxt->inSubset = 2; + if ((ctxt->sax != NULL) && + (!ctxt->disableSAX) && + (ctxt->sax->externalSubset != NULL)) + ctxt->sax->externalSubset( + ctxt->userData, + ctxt->intSubName, + ctxt->extSubSystem, + ctxt->extSubURI); + ctxt->inSubset = 0; + xmlCleanSpecialAttr(ctxt); + ctxt->instate = XML_PARSER_PROLOG; + } + break; + } + } + } + } + + if (ctxt->instate == XML_PARSER_EPILOG) { + if (ctxt->errNo == XML_ERR_OK) + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); + } else { + ctxt->instate = XML_PARSER_START_TAG; } break; case XML_PARSER_DTD: { - /* - * Sorry but progressive parsing of the internal subset - * is not expected to be supported. We first check that - * the full content of the internal subset is available and - * the parsing is launched only at that point. - * Internal subset ends up with "']' S? '>'" in an unescaped - * section and not in a ']]>' sequence which are conditional - * sections (whoever argued to keep that crap in XML deserve - * a place in hell !). - */ - int base, i; - xmlChar *buf; - xmlChar quote = 0; - size_t use; - - base = ctxt->input->cur - ctxt->input->base; - if (base < 0) return(0); - if (ctxt->checkIndex > base) - base = ctxt->checkIndex; - buf = xmlBufContent(ctxt->input->buf->buffer); - use = xmlBufUse(ctxt->input->buf->buffer); - for (;(unsigned int) base < use; base++) { - if (quote != 0) { - if (buf[base] == quote) - quote = 0; - continue; - } - if ((quote == 0) && (buf[base] == '<')) { - int found = 0; - /* special handling of comments */ - if (((unsigned int) base + 4 < use) && - (buf[base + 1] == '!') && - (buf[base + 2] == '-') && - (buf[base + 3] == '-')) { - for (;(unsigned int) base + 3 < use; base++) { - if ((buf[base] == '-') && - (buf[base + 1] == '-') && - (buf[base + 2] == '>')) { - found = 1; - base += 2; - break; - } - } - if (!found) { -#if 0 - fprintf(stderr, "unfinished comment\n"); -#endif - break; /* for */ - } - continue; - } - } - if (buf[base] == '"') { - quote = '"'; - continue; - } - if (buf[base] == '\'') { - quote = '\''; - continue; - } - if (buf[base] == ']') { -#if 0 - fprintf(stderr, "%c%c%c%c: ", buf[base], - buf[base + 1], buf[base + 2], buf[base + 3]); -#endif - if ((unsigned int) base +1 >= use) - break; - if (buf[base + 1] == ']') { - /* conditional crap, skip both ']' ! */ - base++; - continue; - } - for (i = 1; (unsigned int) base + i < use; i++) { - if (buf[base + i] == '>') { -#if 0 - fprintf(stderr, "found\n"); -#endif - goto found_end_int_subset; - } - if (!IS_BLANK_CH(buf[base + i])) { -#if 0 - fprintf(stderr, "not found\n"); -#endif - goto not_end_of_int_subset; - } - } -#if 0 - fprintf(stderr, "end of stream\n"); -#endif - break; - - } -not_end_of_int_subset: - continue; /* for */ - } - /* - * We didn't found the end of the Internal subset - */ - if (quote == 0) - ctxt->checkIndex = base; - else - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - if (next == 0) - xmlGenericError(xmlGenericErrorContext, - "PP: lookup of int subset end filed\n"); -#endif - goto done; - -found_end_int_subset: - ctxt->checkIndex = 0; + if ((!terminate) && (!xmlParseLookupInternalSubset(ctxt))) + goto done; xmlParseInternalSubset(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->inSubset = 2; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->externalSubset != NULL)) @@ -12062,342 +11483,143 @@ found_end_int_subset: ctxt->extSubSystem, ctxt->extSubURI); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; - ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering PROLOG\n"); -#endif break; } - case XML_PARSER_COMMENT: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == COMMENT\n"); - ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_IGNORE: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == IGNORE"); - ctxt->instate = XML_PARSER_DTD; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering DTD\n"); -#endif - break; - case XML_PARSER_PI: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == PI\n"); - ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif - break; - case XML_PARSER_ENTITY_DECL: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == ENTITY_DECL\n"); - ctxt->instate = XML_PARSER_DTD; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering DTD\n"); -#endif - break; - case XML_PARSER_ENTITY_VALUE: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == ENTITY_VALUE\n"); - ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering DTD\n"); -#endif - break; - case XML_PARSER_ATTRIBUTE_VALUE: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == ATTRIBUTE_VALUE\n"); - ctxt->instate = XML_PARSER_START_TAG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif - break; - case XML_PARSER_SYSTEM_LITERAL: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == SYSTEM_LITERAL\n"); - ctxt->instate = XML_PARSER_START_TAG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif - break; - case XML_PARSER_PUBLIC_LITERAL: - xmlGenericError(xmlGenericErrorContext, - "PP: internal error, state == PUBLIC_LITERAL\n"); - ctxt->instate = XML_PARSER_START_TAG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif + default: + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "PP: internal error\n"); + ctxt->instate = XML_PARSER_EOF; break; } } done: -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "PP: done %d\n", ret); -#endif return(ret); encoding_error: - { - char buffer[150]; - - snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - ctxt->input->cur[0], ctxt->input->cur[1], - ctxt->input->cur[2], ctxt->input->cur[3]); - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n%s", - BAD_CAST buffer, NULL); + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; } return(0); } -/** - * xmlParseCheckTransition: - * @ctxt: an XML parser context - * @chunk: a char array - * @size: the size in byte of the chunk - * - * Check depending on the current parser state if the chunk given must be - * processed immediately or one need more data to advance on parsing. - * - * Returns -1 in case of error, 0 if the push is not needed and 1 if needed - */ -static int -xmlParseCheckTransition(xmlParserCtxtPtr ctxt, const char *chunk, int size) { - if ((ctxt == NULL) || (chunk == NULL) || (size < 0)) - return(-1); - if (ctxt->instate == XML_PARSER_START_TAG) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - if (ctxt->progressive == XML_PARSER_COMMENT) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - if (ctxt->instate == XML_PARSER_CDATA_SECTION) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - if (ctxt->progressive == XML_PARSER_PI) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - if (ctxt->instate == XML_PARSER_END_TAG) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - if ((ctxt->progressive == XML_PARSER_DTD) || - (ctxt->instate == XML_PARSER_DTD)) { - if (memchr(chunk, '>', size) != NULL) - return(1); - return(0); - } - return(1); -} - /** * xmlParseChunk: * @ctxt: an XML parser context - * @chunk: an char array - * @size: the size in byte of the chunk + * @chunk: chunk of memory + * @size: size of chunk in bytes * @terminate: last chunk indicator * - * Parse a Chunk of memory + * Parse a chunk of memory in push parser mode. * - * Returns zero if no error, the xmlParserErrors otherwise. + * Assumes that the parser context was initialized with + * xmlCreatePushParserCtxt. + * + * The last chunk, which will often be empty, must be marked with + * the @terminate flag. With the default SAX callbacks, the resulting + * document will be available in ctxt->myDoc. This pointer will not + * be freed by the library. + * + * If the document isn't well-formed, ctxt->myDoc is set to NULL. + * The push parser doesn't support recovery mode. + * + * Returns an xmlParserErrors code (0 on success). */ int xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate) { + size_t curBase; + size_t maxLength; int end_in_lf = 0; - int remain = 0; - size_t old_avail = 0; - size_t avail = 0; - if (ctxt == NULL) - return(XML_ERR_INTERNAL_ERROR); - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + if ((ctxt == NULL) || (size < 0)) + return(XML_ERR_ARGUMENT); + if (ctxt->disableSAX != 0) return(ctxt->errNo); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); + if (ctxt->input == NULL) + return(XML_ERR_INTERNAL_ERROR); + + ctxt->input->flags |= XML_INPUT_PROGRESSIVE; if (ctxt->instate == XML_PARSER_START) - xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(ctxt); if ((size > 0) && (chunk != NULL) && (!terminate) && (chunk[size - 1] == '\r')) { end_in_lf = 1; size--; } -xmldecl_done: - if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input); - size_t cur = ctxt->input->cur - ctxt->input->base; + (ctxt->input->buf != NULL)) { + size_t pos = ctxt->input->cur - ctxt->input->base; int res; - old_avail = xmlBufUse(ctxt->input->buf->buffer); - /* - * Specific handling if we autodetected an encoding, we should not - * push more than the first line ... which depend on the encoding - * And only push the rest once the final encoding was detected - */ - if ((ctxt->instate == XML_PARSER_START) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL) && (ctxt->input->buf->encoder != NULL)) { - unsigned int len = 45; - - if ((xmlStrcasestr(BAD_CAST ctxt->input->buf->encoder->name, - BAD_CAST "UTF-16")) || - (xmlStrcasestr(BAD_CAST ctxt->input->buf->encoder->name, - BAD_CAST "UTF16"))) - len = 90; - else if ((xmlStrcasestr(BAD_CAST ctxt->input->buf->encoder->name, - BAD_CAST "UCS-4")) || - (xmlStrcasestr(BAD_CAST ctxt->input->buf->encoder->name, - BAD_CAST "UCS4"))) - len = 180; - - if (ctxt->input->buf->rawconsumed < len) - len -= ctxt->input->buf->rawconsumed; - - /* - * Change size for reading the initial declaration only - * if size is greater than len. Otherwise, memmove in xmlBufferAdd - * will blindly copy extra bytes from memory. - */ - if ((unsigned int) size > len) { - remain = size - len; - size = len; - } else { - remain = 0; - } - } res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); + xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { - ctxt->errNo = XML_PARSER_EOF; + xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); - return (XML_PARSER_EOF); - } -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); -#endif - - } else if (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->input != NULL) && ctxt->input->buf != NULL) { - xmlParserInputBufferPtr in = ctxt->input->buf; - if ((in->encoder != NULL) && (in->buffer != NULL) && - (in->raw != NULL)) { - int nbchars; - size_t base = xmlBufGetInputBase(in->buffer, ctxt->input); - size_t current = ctxt->input->cur - ctxt->input->base; - - nbchars = xmlCharEncInput(in, terminate); - xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current); - if (nbchars < 0) { - /* TODO 2.6.0 */ - xmlGenericError(xmlGenericErrorContext, - "xmlParseChunk: encoder error\n"); - xmlHaltParser(ctxt); - return(XML_ERR_INVALID_ENCODING); - } - } + return(ctxt->errNo); } } - if (remain != 0) { - xmlParseTryOrFinish(ctxt, 0); - } else { - if ((ctxt->input != NULL) && (ctxt->input->buf != NULL)) - avail = xmlBufUse(ctxt->input->buf->buffer); - /* - * Depending on the current state it may not be such - * a good idea to try parsing if there is nothing in the chunk - * which would be worth doing a parser state transition and we - * need to wait for more data - */ - if ((terminate) || (avail > XML_MAX_TEXT_LENGTH) || - (old_avail == 0) || (avail == 0) || - (xmlParseCheckTransition(ctxt, - (const char *)&ctxt->input->base[old_avail], - avail - old_avail))) - xmlParseTryOrFinish(ctxt, terminate); - } - if (ctxt->instate == XML_PARSER_EOF) - return(ctxt->errNo); - if ((ctxt->input != NULL) && - (((ctxt->input->end - ctxt->input->cur) > XML_MAX_LOOKUP_LIMIT) || - ((ctxt->input->cur - ctxt->input->base) > XML_MAX_LOOKUP_LIMIT)) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Huge input lookup"); + xmlParseTryOrFinish(ctxt, terminate); + + curBase = ctxt->input->cur - ctxt->input->base; + maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_LOOKUP_LIMIT; + if (curBase > maxLength) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Buffer size limit exceeded, try XML_PARSE_HUGE\n"); xmlHaltParser(ctxt); } - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + + if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX != 0)) return(ctxt->errNo); - if (remain != 0) { - chunk += size; - size = remain; - remain = 0; - goto xmldecl_done; - } if ((end_in_lf == 1) && (ctxt->input != NULL) && (ctxt->input->buf != NULL)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, - ctxt->input); - size_t current = ctxt->input->cur - ctxt->input->base; + size_t pos = ctxt->input->cur - ctxt->input->base; + int res; - xmlParserInputBufferPush(ctxt->input->buf, 1, "\r"); - - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, - base, current); + res = xmlParserInputBufferPush(ctxt->input->buf, 1, "\r"); + xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); + if (res < 0) { + xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL); + xmlHaltParser(ctxt); + return(ctxt->errNo); + } } if (terminate) { /* * Check for termination */ - int cur_avail = 0; - - if (ctxt->input != NULL) { - if (ctxt->input->buf == NULL) - cur_avail = ctxt->input->length - - (ctxt->input->cur - ctxt->input->base); - else - cur_avail = xmlBufUse(ctxt->input->buf->buffer) - - (ctxt->input->cur - ctxt->input->base); - } - - if ((ctxt->instate != XML_PARSER_EOF) && - (ctxt->instate != XML_PARSER_EPILOG)) { - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); - } - if ((ctxt->instate == XML_PARSER_EPILOG) && (cur_avail > 0)) { - xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); - } + if ((ctxt->instate != XML_PARSER_EOF) && + (ctxt->instate != XML_PARSER_EPILOG)) { + if (ctxt->nameNr > 0) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + } else if (ctxt->instate == XML_PARSER_START) { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); + } else { + xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, + "Start tag expected, '<' not found\n"); + } + } else if ((ctxt->input->buf != NULL) && + (ctxt->input->buf->encoder != NULL) && + (ctxt->input->buf->error == 0) && + (!xmlBufIsEmpty(ctxt->input->buf->raw))) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "Truncated multi-byte sequence at EOF\n"); + } if (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); } - ctxt->instate = XML_PARSER_EOF; } if (ctxt->wellFormed == 0) return((xmlParserErrors) ctxt->errNo); @@ -12413,157 +11635,47 @@ xmldecl_done: /** * xmlCreatePushParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks - * @chunk: a pointer to an array of chars - * @size: number of chars in the array - * @filename: an optional file name or URI + * @sax: a SAX handler (optional) + * @user_data: user data for SAX callbacks (optional) + * @chunk: initial chunk (optional, deprecated) + * @size: size of initial chunk in bytes + * @filename: file name or URI (optional) * * Create a parser context for using the XML parser in push mode. - * If @buffer and @size are non-NULL, the data is used to detect - * the encoding. The remaining characters will be parsed so they - * don't need to be fed in again through xmlParseChunk. - * To allow content encoding detection, @size should be >= 4 - * The value of @filename is used for fetching external entities - * and error/warning reports. + * See xmlParseChunk. * - * Returns the new parser context or NULL + * Passing an initial chunk is useless and deprecated. + * + * @filename is used as base URI to fetch external entities and for + * error reports. + * + * Returns the new parser context or NULL in case of error. */ xmlParserCtxtPtr xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; - - /* - * plug some encoding conversion routines - */ - if ((chunk != NULL) && (size >= 4)) - enc = xmlDetectCharEncoding((const xmlChar *) chunk, size); - - buf = xmlAllocParserInputBuffer(enc); - if (buf == NULL) return(NULL); + xmlParserInputPtr input; - ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlErrMemory(NULL, "creating parser: out of memory\n"); - xmlFreeParserInputBuffer(buf); + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) return(NULL); - } + + ctxt->options &= ~XML_PARSE_NODICT; ctxt->dictNames = 1; - if (sax != NULL) { -#ifdef LIBXML_SAX1_ENABLED - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) -#endif /* LIBXML_SAX1_ENABLED */ - xmlFree(ctxt->sax); - ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); - if (ctxt->sax == NULL) { - xmlErrMemory(ctxt, NULL); - xmlFreeParserInputBuffer(buf); - xmlFreeParserCtxt(ctxt); - return(NULL); - } - memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); - if (sax->initialized == XML_SAX2_MAGIC) - memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); - else - memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); - if (user_data != NULL) - ctxt->userData = user_data; - } - if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - } - inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { + input = xmlNewInputPush(ctxt, filename, chunk, size, NULL); + if (input == NULL) { xmlFreeParserCtxt(ctxt); - xmlFreeParserInputBuffer(buf); return(NULL); } - - if (filename == NULL) - inputStream->filename = NULL; - else { - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - if (inputStream->filename == NULL) { - xmlFreeParserCtxt(ctxt); - xmlFreeParserInputBuffer(buf); - return(NULL); - } - } - inputStream->buf = buf; - xmlBufResetInput(inputStream->buf->buffer, inputStream); - inputPush(ctxt, inputStream); - - /* - * If the caller didn't provide an initial 'chunk' for determining - * the encoding, we set the context to XML_CHAR_ENCODING_NONE so - * that it can be automatically determined later - */ - if ((size == 0) || (chunk == NULL)) { - ctxt->charset = XML_CHAR_ENCODING_NONE; - } else if ((ctxt->input != NULL) && (ctxt->input->buf != NULL)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input); - size_t cur = ctxt->input->cur - ctxt->input->base; - - xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); -#endif - } - - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } + inputPush(ctxt, input); return(ctxt); } #endif /* LIBXML_PUSH_ENABLED */ -/** - * xmlHaltParser: - * @ctxt: an XML parser context - * - * Blocks further parser processing don't override error - * for internal use - */ -static void -xmlHaltParser(xmlParserCtxtPtr ctxt) { - if (ctxt == NULL) - return; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - while (ctxt->inputNr > 1) - xmlFreeInputStream(inputPop(ctxt)); - if (ctxt->input != NULL) { - /* - * in case there was a specific allocation deallocate before - * overriding base - */ - if (ctxt->input->free != NULL) { - ctxt->input->free((xmlChar *) ctxt->input->base); - ctxt->input->free = NULL; - } - if (ctxt->input->buf != NULL) { - xmlFreeParserInputBuffer(ctxt->input->buf); - ctxt->input->buf = NULL; - } - ctxt->input->cur = BAD_CAST""; - ctxt->input->length = 0; - ctxt->input->base = ctxt->input->cur; - ctxt->input->end = ctxt->input->cur; - } -} - /** * xmlStopParser: * @ctxt: an XML parser context @@ -12575,17 +11687,18 @@ xmlStopParser(xmlParserCtxtPtr ctxt) { if (ctxt == NULL) return; xmlHaltParser(ctxt); - ctxt->errNo = XML_ERR_USER_STOP; + if (ctxt->errNo != XML_ERR_NO_MEMORY) + ctxt->errNo = XML_ERR_USER_STOP; } /** * xmlCreateIOParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks + * @sax: a SAX handler (optional) + * @user_data: user data for SAX callbacks (optional) * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a parser context for using the XML parser with an existing * I/O stream @@ -12594,53 +11707,24 @@ xmlStopParser(xmlParserCtxtPtr ctxt) { */ xmlParserCtxtPtr xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, - xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, - void *ioctx, xmlCharEncoding enc) { + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, xmlCharEncoding enc) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - - if (ioread == NULL) return(NULL); - - buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc); - if (buf == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } + xmlParserInputPtr input; + const char *encoding; - ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) return(NULL); - } - if (sax != NULL) { -#ifdef LIBXML_SAX1_ENABLED - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) -#endif /* LIBXML_SAX1_ENABLED */ - xmlFree(ctxt->sax); - ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); - if (ctxt->sax == NULL) { - xmlFreeParserInputBuffer(buf); - xmlErrMemory(ctxt, NULL); - xmlFreeParserCtxt(ctxt); - return(NULL); - } - memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); - if (sax->initialized == XML_SAX2_MAGIC) - memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); - else - memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); - if (user_data != NULL) - ctxt->userData = user_data; - } - inputStream = xmlNewIOInputStream(ctxt, buf, enc); - if (inputStream == NULL) { + encoding = xmlGetCharEncodingName(enc); + input = xmlNewInputIO(ctxt, NULL, ioread, ioclose, ioctx, encoding, 0); + if (input == NULL) { xmlFreeParserCtxt(ctxt); - return(NULL); + return (NULL); } - inputPush(ctxt, inputStream); + inputPush(ctxt, input); return(ctxt); } @@ -12670,38 +11754,22 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlDtdPtr ret = NULL; xmlParserCtxtPtr ctxt; xmlParserInputPtr pinput = NULL; - xmlChar start[4]; if (input == NULL) return(NULL); - ctxt = xmlNewParserCtxt(); + ctxt = xmlNewSAXParserCtxt(sax, NULL); if (ctxt == NULL) { xmlFreeParserInputBuffer(input); return(NULL); } - /* We are loading a DTD */ - ctxt->options |= XML_PARSE_DTDLOAD; - - /* - * Set-up the SAX context - */ - if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; - ctxt->userData = ctxt; - } - xmlDetectSAX2(ctxt); - /* * generate a parser input from the I/O handler */ pinput = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (pinput == NULL) { - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); return(NULL); @@ -12711,7 +11779,6 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, * plug some encoding conversion routines here. */ if (xmlPushInput(ctxt, pinput) < 0) { - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); return(NULL); } @@ -12719,43 +11786,18 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlSwitchEncoding(ctxt, enc); } - pinput->filename = NULL; - pinput->line = 1; - pinput->col = 1; - pinput->base = ctxt->input->cur; - pinput->cur = ctxt->input->cur; - pinput->free = NULL; - /* * let's parse that entity knowing it's an external subset. */ - ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); return(NULL); } ctxt->myDoc->properties = XML_DOC_INTERNAL; ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", BAD_CAST "none", BAD_CAST "none"); - if ((enc == XML_CHAR_ENCODING_NONE) && - ((ctxt->input->end - ctxt->input->cur) >= 4)) { - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. - */ - start[0] = RAW; - start[1] = NXT(1); - start[2] = NXT(2); - start[3] = NXT(3); - enc = xmlDetectCharEncoding(start, 4); - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } - } - xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none"); if (ctxt->myDoc != NULL) { @@ -12778,7 +11820,6 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); return(ret); @@ -12790,6 +11831,8 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, * @ExternalID: a NAME* containing the External ID of the DTD * @SystemID: a NAME* containing the URL to the DTD * + * DEPRECATED: Don't use. + * * Load and parse an external subset. * * Returns the resulting xmlDtdPtr or NULL in case of error. @@ -12801,29 +11844,15 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, xmlDtdPtr ret = NULL; xmlParserCtxtPtr ctxt; xmlParserInputPtr input = NULL; - xmlCharEncoding enc; xmlChar* systemIdCanonic; if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL); - ctxt = xmlNewParserCtxt(); + ctxt = xmlNewSAXParserCtxt(sax, NULL); if (ctxt == NULL) { return(NULL); } - /* We are loading a DTD */ - ctxt->options |= XML_PARSE_DTDLOAD; - - /* - * Set-up the SAX context - */ - if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; - ctxt->userData = ctxt; - } - /* * Canonicalise the system ID */ @@ -12841,7 +11870,6 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, systemIdCanonic); if (input == NULL) { - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); if (systemIdCanonic != NULL) xmlFree(systemIdCanonic); @@ -12852,41 +11880,36 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, * plug some encoding conversion routines here. */ if (xmlPushInput(ctxt, input) < 0) { - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); if (systemIdCanonic != NULL) xmlFree(systemIdCanonic); return(NULL); } - if ((ctxt->input->end - ctxt->input->cur) >= 4) { - enc = xmlDetectCharEncoding(ctxt->input->cur, 4); - xmlSwitchEncoding(ctxt, enc); - } + + xmlDetectEncoding(ctxt); if (input->filename == NULL) input->filename = (char *) systemIdCanonic; else xmlFree(systemIdCanonic); - input->line = 1; - input->col = 1; - input->base = ctxt->input->cur; - input->cur = ctxt->input->cur; - input->free = NULL; /* * let's parse that entity knowing it's an external subset. */ - ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); - if (sax != NULL) ctxt->sax = NULL; + xmlErrMemory(ctxt); xmlFreeParserCtxt(ctxt); return(NULL); } - ctxt->myDoc->properties = XML_DOC_INTERNAL; - ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", - ExternalID, SystemID); + ctxt->myDoc->properties = XML_DOC_INTERNAL; + ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", + ExternalID, SystemID); + if (ctxt->myDoc->extSubset == NULL) { + xmlFreeDoc(ctxt->myDoc); + xmlFreeParserCtxt(ctxt); + return(NULL); + } xmlParseExternalSubset(ctxt, ExternalID, SystemID); if (ctxt->myDoc != NULL) { @@ -12909,7 +11932,6 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; } - if (sax != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); return(ret); @@ -12938,293 +11960,211 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { * * ************************************************************************/ -/** - * xmlParseCtxtExternalEntity: - * @ctx: the existing parsing context - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @lst: the return value for the set of parsed nodes - * - * Parse an external general entity within an existing parsing context - * An external general parsed entity is well-formed if it matches the - * production labeled extParsedEnt. - * - * [78] extParsedEnt ::= TextDecl? content - * - * Returns 0 if the entity is well formed, -1 in case of args problem and - * the parser error code otherwise - */ +static xmlNodePtr +xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, + int hasTextDecl, int buildTree) { + xmlNodePtr root = NULL; + xmlNodePtr list = NULL; + xmlChar *rootName = BAD_CAST "#root"; + int result; + + if (buildTree) { + root = xmlNewDocNode(ctxt->myDoc, NULL, rootName, NULL); + if (root == NULL) { + xmlErrMemory(ctxt); + goto error; + } + } -int -xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, - const xmlChar *ID, xmlNodePtr *lst) { - void *userData; + if (xmlPushInput(ctxt, input) < 0) + goto error; - if (ctx == NULL) return(-1); - /* - * If the user provided their own SAX callbacks, then reuse the - * userData callback field, otherwise the expected setup in a - * DOM builder is to have userData == ctxt - */ - if (ctx->userData == ctx) - userData = NULL; - else - userData = ctx->userData; - return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax, - userData, ctx->depth + 1, - URL, ID, lst); -} + nameNsPush(ctxt, rootName, NULL, NULL, 0, 0); + spacePush(ctxt, -1); -/** - * xmlParseExternalEntityPrivate: - * @doc: the document the chunk pertains to - * @oldctxt: the previous parser context if available - * @sax: the SAX handler block (possibly NULL) - * @user_data: The user data returned on SAX callbacks (possibly NULL) - * @depth: Used for loop detection, use 0 - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @list: the return value for the set of parsed nodes - * - * Private version of xmlParseExternalEntity() - * - * Returns 0 if the entity is well formed, -1 in case of args problem and - * the parser error code otherwise - */ + if (buildTree) + nodePush(ctxt, root); -static xmlParserErrors -xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, - xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *URL, - const xmlChar *ID, xmlNodePtr *list) { - xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc; - xmlNodePtr newRoot; - xmlSAXHandlerPtr oldsax = NULL; - xmlParserErrors ret = XML_ERR_OK; - xmlChar start[4]; - xmlCharEncoding enc; + if (hasTextDecl) { + xmlDetectEncoding(ctxt); - if (((depth > 40) && - ((oldctxt == NULL) || (oldctxt->options & XML_PARSE_HUGE) == 0)) || - (depth > 1024)) { - return(XML_ERR_ENTITY_LOOP); + /* + * Parse a possible text declaration first + */ + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && + (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + /* + * An XML-1.0 document can't reference an entity not XML-1.0 + */ + if ((xmlStrEqual(ctxt->version, BAD_CAST "1.0")) && + (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { + xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, + "Version mismatch between document and " + "entity\n"); + } + } } - if (list != NULL) - *list = NULL; - if ((URL == NULL) && (ID == NULL)) - return(XML_ERR_INTERNAL_ERROR); - if (doc == NULL) - return(XML_ERR_INTERNAL_ERROR); + xmlParseContentInternal(ctxt); + + if (ctxt->input->cur < ctxt->input->end) + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { + if (root != NULL) { + xmlNodePtr cur; - ctxt = xmlCreateEntityParserCtxtInternal(URL, ID, NULL, oldctxt); - if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); - ctxt->userData = ctxt; - if (sax != NULL) { - oldsax = ctxt->sax; - ctxt->sax = sax; - if (user_data != NULL) - ctxt->userData = user_data; - } - xmlDetectSAX2(ctxt); - newDoc = xmlNewDoc(BAD_CAST "1.0"); - if (newDoc == NULL) { - xmlFreeParserCtxt(ctxt); - return(XML_ERR_INTERNAL_ERROR); - } - newDoc->properties = XML_DOC_INTERNAL; - if (doc) { - newDoc->intSubset = doc->intSubset; - newDoc->extSubset = doc->extSubset; - if (doc->dict) { - newDoc->dict = doc->dict; - xmlDictReference(newDoc->dict); - } - if (doc->URL != NULL) { - newDoc->URL = xmlStrdup(doc->URL); + /* + * Return the newly created nodeset after unlinking it from + * its pseudo parent. + */ + cur = root->children; + list = cur; + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + root->children = NULL; + root->last = NULL; } } - newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - if (sax != NULL) - ctxt->sax = oldsax; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - return(XML_ERR_INTERNAL_ERROR); - } - xmlAddChild((xmlNodePtr) newDoc, newRoot); - nodePush(ctxt, newDoc->children); - if (doc == NULL) { - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = doc; - newRoot->doc = doc; - } /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. + * Read the rest of the stream in case of errors. We want + * to account for the whole entity size. */ - 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); - } - } + do { + ctxt->input->cur = ctxt->input->end; + xmlParserShrink(ctxt); + result = xmlParserGrow(ctxt); + } while (result > 0); - /* - * Parse a possible text declaration first - */ - if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { - xmlParseTextDecl(ctxt); - /* - * An XML-1.0 document can't reference an entity not XML-1.0 - */ - if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) && - (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { - xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, - "Version mismatch between document and entity\n"); - } - } + if (buildTree) + nodePop(ctxt); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->depth = depth; - if (oldctxt != NULL) { - ctxt->_private = oldctxt->_private; - ctxt->loadsubset = oldctxt->loadsubset; - ctxt->validate = oldctxt->validate; - ctxt->valid = oldctxt->valid; - ctxt->replaceEntities = oldctxt->replaceEntities; - if (oldctxt->validate) { - ctxt->vctxt.error = oldctxt->vctxt.error; - ctxt->vctxt.warning = oldctxt->vctxt.warning; - ctxt->vctxt.userData = oldctxt->vctxt.userData; - } - ctxt->external = oldctxt->external; - if (ctxt->dict) xmlDictFree(ctxt->dict); - ctxt->dict = oldctxt->dict; - ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); - ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); - ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); - ctxt->dictNames = oldctxt->dictNames; - ctxt->attsDefault = oldctxt->attsDefault; - ctxt->attsSpecial = oldctxt->attsSpecial; - ctxt->linenumbers = oldctxt->linenumbers; - ctxt->record_info = oldctxt->record_info; - ctxt->node_seq.maximum = oldctxt->node_seq.maximum; - ctxt->node_seq.length = oldctxt->node_seq.length; - ctxt->node_seq.buffer = oldctxt->node_seq.buffer; - } else { - /* - * Doing validity checking on chunk without context - * doesn't make sense - */ - ctxt->_private = NULL; - ctxt->validate = 0; - ctxt->external = 2; - ctxt->loadsubset = 0; - } + namePop(ctxt); + spacePop(ctxt); - xmlParseContent(ctxt); + /* xmlPopInput would free the stream */ + inputPop(ctxt); - if ((RAW == '<') && (NXT(1) == '/')) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); - } - if (ctxt->node != newDoc->children) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } +error: + xmlFreeNode(root); - if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = XML_ERR_INTERNAL_ERROR; - else - ret = (xmlParserErrors)ctxt->errNo; - } else { - if (list != NULL) { - xmlNodePtr cur; + return(list); +} - /* - * Return the newly created nodeset after unlinking it from - * they pseudo parent. - */ - cur = newDoc->children->children; - *list = cur; - while (cur != NULL) { - cur->parent = NULL; - cur = cur->next; - } - newDoc->children->children = NULL; - } - ret = XML_ERR_OK; +static void +xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) { + xmlParserInputPtr input; + xmlNodePtr list; + unsigned long consumed; + int isExternal; + int buildTree; + int oldMinNsIndex; + int oldNodelen, oldNodemem; + + isExternal = (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY); + buildTree = (ctxt->node != NULL); + + /* + * Recursion check + */ + if (ent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + goto error; } /* - * Record in the parent context the number of entities replacement - * done when parsing that reference. + * Load entity */ - if (oldctxt != NULL) - oldctxt->nbentities += ctxt->nbentities; + input = xmlNewEntityInputStream(ctxt, ent); + if (input == NULL) + goto error; /* - * Also record the size of the entity parsed + * When building a tree, we need to limit the scope of namespace + * declarations, so that entities don't reference xmlNs structs + * from the parent of a reference. */ - if (ctxt->input != NULL && oldctxt != NULL) { - oldctxt->sizeentities += ctxt->input->consumed; - oldctxt->sizeentities += (ctxt->input->cur - ctxt->input->base); - } + oldMinNsIndex = ctxt->nsdb->minNsIndex; + if (buildTree) + ctxt->nsdb->minNsIndex = ctxt->nsNr; + + oldNodelen = ctxt->nodelen; + oldNodemem = ctxt->nodemem; + ctxt->nodelen = 0; + ctxt->nodemem = 0; + /* - * And record the last error if any + * Parse content + * + * This initiates a recursive call chain: + * + * - xmlCtxtParseContent + * - xmlParseContentInternal + * - xmlParseReference + * - xmlCtxtParseEntity + * + * The nesting depth is limited by the maximum number of inputs, + * see xmlPushInput. + * + * It's possible to make this non-recursive (minNsIndex must be + * stored in the input struct) at the expense of code readability. */ - if ((oldctxt != NULL) && (ctxt->lastError.code != XML_ERR_OK)) - xmlCopyError(&ctxt->lastError, &oldctxt->lastError); - if (sax != NULL) - ctxt->sax = oldsax; - if (oldctxt != NULL) { - ctxt->dict = NULL; - ctxt->attsDefault = NULL; - ctxt->attsSpecial = NULL; - oldctxt->validate = ctxt->validate; - oldctxt->valid = ctxt->valid; - oldctxt->node_seq.maximum = ctxt->node_seq.maximum; - oldctxt->node_seq.length = ctxt->node_seq.length; - oldctxt->node_seq.buffer = ctxt->node_seq.buffer; - } - ctxt->node_seq.maximum = 0; - ctxt->node_seq.length = 0; - ctxt->node_seq.buffer = NULL; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); + ent->flags |= XML_ENT_EXPANDING; - return(ret); + list = xmlCtxtParseContent(ctxt, input, isExternal, buildTree); + + ent->flags &= ~XML_ENT_EXPANDING; + + ctxt->nsdb->minNsIndex = oldMinNsIndex; + ctxt->nodelen = oldNodelen; + ctxt->nodemem = oldNodemem; + + /* + * Entity size accounting + */ + consumed = input->consumed; + xmlSaturatedAddSizeT(&consumed, input->end - input->base); + + if ((ent->flags & XML_ENT_CHECKED) == 0) + xmlSaturatedAdd(&ent->expandedSize, consumed); + + if ((ent->flags & XML_ENT_PARSED) == 0) { + if (isExternal) + xmlSaturatedAdd(&ctxt->sizeentities, consumed); + + ent->children = list; + + while (list != NULL) { + list->parent = (xmlNodePtr) ent; + if (list->next == NULL) + ent->last = list; + list = list->next; + } + } else { + xmlFreeNodeList(list); + } + + xmlFreeInputStream(input); + +error: + ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED; } -#ifdef LIBXML_SAX1_ENABLED /** - * xmlParseExternalEntity: - * @doc: the document the chunk pertains to - * @sax: the SAX handler block (possibly NULL) - * @user_data: The user data returned on SAX callbacks (possibly NULL) - * @depth: Used for loop detection, use 0 + * xmlParseCtxtExternalEntity: + * @ctxt: the existing parsing context * @URL: the URL for the entity to load * @ID: the System ID for the entity to load - * @lst: the return value for the set of parsed nodes + * @listOut: the return value for the set of parsed nodes * - * Parse an external general entity + * Parse an external general entity within an existing parsing context * An external general parsed entity is well-formed if it matches the * production labeled extParsedEnt. * @@ -13235,235 +12175,108 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, */ int -xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, - int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) { - return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL, - ID, lst)); -} - -/** - * xmlParseBalancedChunkMemory: - * @doc: the document the chunk pertains to (must not be NULL) - * @sax: the SAX handler block (possibly NULL) - * @user_data: The user data returned on SAX callbacks (possibly NULL) - * @depth: Used for loop detection, use 0 - * @string: the input string in UTF8 or ISO-Latin (zero terminated) - * @lst: the return value for the set of parsed nodes - * - * Parse a well-balanced chunk of an XML document - * called by the parser - * The allowed sequence for the Well Balanced Chunk is the one defined by - * the content production in the XML grammar: - * - * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* - * - * Returns 0 if the chunk is well balanced, -1 in case of args problem and - * the parser error code otherwise - */ - -int -xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst) { - return xmlParseBalancedChunkMemoryRecover( doc, sax, user_data, - depth, string, lst, 0 ); -} -#endif /* LIBXML_SAX1_ENABLED */ - -/** - * xmlParseBalancedChunkMemoryInternal: - * @oldctxt: the existing parsing context - * @string: the input string in UTF8 or ISO-Latin (zero terminated) - * @user_data: the user data field for the parser context - * @lst: the return value for the set of parsed nodes - * - * - * Parse a well-balanced chunk of an XML document - * called by the parser - * The allowed sequence for the Well Balanced Chunk is the one defined by - * the content production in the XML grammar: - * - * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* - * - * Returns XML_ERR_OK if the chunk is well balanced, and the parser - * error code otherwise - * - * In case recover is set to 1, the nodelist will not be empty even if - * the parsed chunk is not well balanced. - */ -static xmlParserErrors -xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, - const xmlChar *string, void *user_data, xmlNodePtr *lst) { - xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc = NULL; - xmlNodePtr newRoot; - xmlSAXHandlerPtr oldsax = NULL; - xmlNodePtr content = NULL; - xmlNodePtr last = NULL; - int size; - xmlParserErrors ret = XML_ERR_OK; -#ifdef SAX2 - int i; -#endif +xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctxt, const xmlChar *URL, + const xmlChar *ID, xmlNodePtr *listOut) { + xmlParserInputPtr input; + xmlNodePtr list; - if (((oldctxt->depth > 40) && ((oldctxt->options & XML_PARSE_HUGE) == 0)) || - (oldctxt->depth > 1024)) { - return(XML_ERR_ENTITY_LOOP); - } + if (listOut != NULL) + *listOut = NULL; + if (ctxt == NULL) + return(XML_ERR_ARGUMENT); - if (lst != NULL) - *lst = NULL; - if (string == NULL) - return(XML_ERR_INTERNAL_ERROR); + input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); + if (input == NULL) + return(ctxt->errNo); - size = xmlStrlen(string); + xmlCtxtInitializeLate(ctxt); - ctxt = xmlCreateMemoryParserCtxt((char *) string, size); - if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); - if (user_data != NULL) - ctxt->userData = user_data; + list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 1, 1); + if (listOut != NULL) + *listOut = list; else - ctxt->userData = ctxt; - if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); - ctxt->dict = oldctxt->dict; - ctxt->input_id = oldctxt->input_id + 1; - 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); - -#ifdef SAX2 - /* propagate namespaces down the entity */ - for (i = 0;i < oldctxt->nsNr;i += 2) { - nsPush(ctxt, oldctxt->nsTab[i], oldctxt->nsTab[i+1]); - } -#endif - - oldsax = ctxt->sax; - ctxt->sax = oldctxt->sax; - xmlDetectSAX2(ctxt); - ctxt->replaceEntities = oldctxt->replaceEntities; - ctxt->options = oldctxt->options; - - ctxt->_private = oldctxt->_private; - if (oldctxt->myDoc == NULL) { - newDoc = xmlNewDoc(BAD_CAST "1.0"); - if (newDoc == NULL) { - ctxt->sax = oldsax; - ctxt->dict = NULL; - xmlFreeParserCtxt(ctxt); - return(XML_ERR_INTERNAL_ERROR); - } - newDoc->properties = XML_DOC_INTERNAL; - newDoc->dict = ctxt->dict; - xmlDictReference(newDoc->dict); - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = oldctxt->myDoc; - content = ctxt->myDoc->children; - last = ctxt->myDoc->last; - } - newRoot = xmlNewDocNode(ctxt->myDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - ctxt->sax = oldsax; - ctxt->dict = NULL; - xmlFreeParserCtxt(ctxt); - if (newDoc != NULL) { - xmlFreeDoc(newDoc); - } - return(XML_ERR_INTERNAL_ERROR); - } - ctxt->myDoc->children = NULL; - ctxt->myDoc->last = NULL; - xmlAddChild((xmlNodePtr) ctxt->myDoc, newRoot); - nodePush(ctxt, ctxt->myDoc->children); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->depth = oldctxt->depth + 1; + xmlFreeNodeList(list); - ctxt->validate = 0; - ctxt->loadsubset = oldctxt->loadsubset; - if ((oldctxt->validate) || (oldctxt->replaceEntities != 0)) { - /* - * ID/IDREF registration will be done in xmlValidateElement below - */ - ctxt->loadsubset |= XML_SKIP_IDS; - } - ctxt->dictNames = oldctxt->dictNames; - ctxt->attsDefault = oldctxt->attsDefault; - ctxt->attsSpecial = oldctxt->attsSpecial; + xmlFreeInputStream(input); + return(ctxt->errNo); +} - xmlParseContent(ctxt); - if ((RAW == '<') && (NXT(1) == '/')) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); - } - if (ctxt->node != ctxt->myDoc->children) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } +#ifdef LIBXML_SAX1_ENABLED +/** + * xmlParseExternalEntity: + * @doc: the document the chunk pertains to + * @sax: the SAX handler block (possibly NULL) + * @user_data: The user data returned on SAX callbacks (possibly NULL) + * @depth: Used for loop detection, use 0 + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @list: the return value for the set of parsed nodes + * + * DEPRECATED: Use xmlParseCtxtExternalEntity. + * + * Parse an external general entity + * An external general parsed entity is well-formed if it matches the + * production labeled extParsedEnt. + * + * [78] extParsedEnt ::= TextDecl? content + * + * Returns 0 if the entity is well formed, -1 in case of args problem and + * the parser error code otherwise + */ - if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = XML_ERR_INTERNAL_ERROR; - else - ret = (xmlParserErrors)ctxt->errNo; - } else { - ret = XML_ERR_OK; - } +int +xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, + int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list) { + xmlParserCtxtPtr ctxt; + int ret; - if ((lst != NULL) && (ret == XML_ERR_OK)) { - xmlNodePtr cur; + if (list != NULL) + *list = NULL; - /* - * Return the newly created nodeset after unlinking it from - * they pseudo parent. - */ - cur = ctxt->myDoc->children->children; - *lst = cur; - while (cur != NULL) { -#ifdef LIBXML_VALID_ENABLED - if ((oldctxt->validate) && (oldctxt->wellFormed) && - (oldctxt->myDoc) && (oldctxt->myDoc->intSubset) && - (cur->type == XML_ELEMENT_NODE)) { - oldctxt->valid &= xmlValidateElement(&oldctxt->vctxt, - oldctxt->myDoc, cur); - } -#endif /* LIBXML_VALID_ENABLED */ - cur->parent = NULL; - cur = cur->next; - } - ctxt->myDoc->children->children = NULL; - } - if (ctxt->myDoc != NULL) { - xmlFreeNode(ctxt->myDoc->children); - ctxt->myDoc->children = content; - ctxt->myDoc->last = last; - } + if (doc == NULL) + return(XML_ERR_ARGUMENT); - /* - * Record in the parent context the number of entities replacement - * done when parsing that reference. - */ - if (oldctxt != NULL) - oldctxt->nbentities += ctxt->nbentities; + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) + return(XML_ERR_NO_MEMORY); - /* - * Also record the last error if any - */ - if (ctxt->lastError.code != XML_ERR_OK) - xmlCopyError(&ctxt->lastError, &oldctxt->lastError); + ctxt->depth = depth; + ctxt->myDoc = doc; + ret = xmlParseCtxtExternalEntity(ctxt, URL, ID, list); - ctxt->sax = oldsax; - ctxt->dict = NULL; - ctxt->attsDefault = NULL; - ctxt->attsSpecial = NULL; xmlFreeParserCtxt(ctxt); - if (newDoc != NULL) { - xmlFreeDoc(newDoc); - } - return(ret); } +/** + * xmlParseBalancedChunkMemory: + * @doc: the document the chunk pertains to (must not be NULL) + * @sax: the SAX handler block (possibly NULL) + * @user_data: The user data returned on SAX callbacks (possibly NULL) + * @depth: Used for loop detection, use 0 + * @string: the input string in UTF8 or ISO-Latin (zero terminated) + * @lst: the return value for the set of parsed nodes + * + * Parse a well-balanced chunk of an XML document + * called by the parser + * The allowed sequence for the Well Balanced Chunk is the one defined by + * the content production in the XML grammar: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * + * Returns 0 if the chunk is well balanced, -1 in case of args problem and + * the parser error code otherwise + */ + +int +xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, + void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst) { + return xmlParseBalancedChunkMemoryRecover( doc, sax, user_data, + depth, string, lst, 0 ); +} +#endif /* LIBXML_SAX1_ENABLED */ + /** * xmlParseInNodeContext: * @node: the context node @@ -13486,7 +12299,6 @@ xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, xmlParserErrors xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, int options, xmlNodePtr *lst) { -#ifdef SAX2 xmlParserCtxtPtr ctxt; xmlDocPtr doc = NULL; xmlNodePtr fake, cur; @@ -13498,7 +12310,7 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, * check all input parameters, grab the document */ if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0)) - return(XML_ERR_INTERNAL_ERROR); + return(XML_ERR_ARGUMENT); switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -13551,37 +12363,30 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, /* * Use input doc's dict if present, else assure XML_PARSE_NODICT is set. - * We need a dictionary for xmlDetectSAX2, so if there's no doc dict + * We need a dictionary for xmlCtxtInitializeLate, so if there's no doc dict * we must wait until the last moment to free the original one. */ if (doc->dict != NULL) { if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); ctxt->dict = doc->dict; - } else + } else { options |= XML_PARSE_NODICT; - - if (doc->encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = xmlStrdup((const xmlChar *) doc->encoding); - - hdlr = xmlFindCharEncodingHandler((const char *) doc->encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } else { - return(XML_ERR_UNSUPPORTED_ENCODING); - } + ctxt->dictNames = 0; } - xmlCtxtUseOptionsInternal(ctxt, options, NULL); - xmlDetectSAX2(ctxt); + if (doc->encoding != NULL) + xmlSwitchEncodingName(ctxt, (const char *) doc->encoding); + + xmlCtxtUseOptions(ctxt, options); + xmlCtxtInitializeLate(ctxt); ctxt->myDoc = doc; /* parsing in context, i.e. as within existing content */ ctxt->input_id = 2; - ctxt->instate = XML_PARSER_CONTENT; + + /* + * TODO: Use xmlCtxtParseContent + */ fake = xmlNewDocComment(node->doc, NULL); if (fake == NULL) { @@ -13590,29 +12395,23 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, } xmlAddChild(node, fake); - if (node->type == XML_ELEMENT_NODE) { + if (node->type == XML_ELEMENT_NODE) nodePush(ctxt, node); + + if ((ctxt->html == 0) && (node->type == XML_ELEMENT_NODE)) { /* * initialize the SAX2 namespaces stack */ cur = node; while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) { xmlNsPtr ns = cur->nsDef; - const xmlChar *iprefix, *ihref; + xmlHashedString hprefix, huri; while (ns != NULL) { - if (ctxt->dict) { - iprefix = xmlDictLookup(ctxt->dict, ns->prefix, -1); - ihref = xmlDictLookup(ctxt->dict, ns->href, -1); - } else { - iprefix = ns->prefix; - ihref = ns->href; - } - - if (xmlGetNamespace(ctxt, iprefix) == NULL) { - nsPush(ctxt, iprefix, ihref); - nsnr++; - } + hprefix = xmlDictLookupHashed(ctxt->dict, ns->prefix, -1); + huri = xmlDictLookupHashed(ctxt->dict, ns->href, -1); + if (xmlParserNsPush(ctxt, &hprefix, &huri, ns, 1) > 0) + nsnr++; ns = ns->next; } cur = cur->parent; @@ -13631,26 +12430,18 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, __htmlParseContent(ctxt); else #endif - xmlParseContent(ctxt); + xmlParseContentInternal(ctxt); - nsPop(ctxt, nsnr); - if ((RAW == '<') && (NXT(1) == '/')) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); - } - if ((ctxt->node != NULL) && (ctxt->node != node)) { + if (ctxt->input->cur < ctxt->input->end) xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - ctxt->wellFormed = 0; - } - if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = XML_ERR_INTERNAL_ERROR; - else - ret = (xmlParserErrors)ctxt->errNo; - } else { + xmlParserNsPop(ctxt, nsnr); + + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { ret = XML_ERR_OK; + } else { + ret = (xmlParserErrors) ctxt->errNo; } /* @@ -13687,9 +12478,6 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, xmlFreeParserCtxt(ctxt); return(ret); -#else /* !SAX2 */ - return(XML_ERR_INTERNAL_ERROR); -#endif } #ifdef LIBXML_SAX1_ENABLED @@ -13700,19 +12488,18 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) - * @lst: the return value for the set of parsed nodes + * @listOut: the return value for the set of parsed nodes * @recover: return nodes even if the data is broken (use 0) * - * * Parse a well-balanced chunk of an XML document - * called by the parser + * * The allowed sequence for the Well Balanced Chunk is the one defined by * the content production in the XML grammar: * * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* * - * Returns 0 if the chunk is well balanced, -1 in case of args problem and - * the parser error code otherwise + * Returns 0 if the chunk is well balanced, or thehe parser error code + * otherwise. * * In case recover is set to 1, the nodelist will not be empty even if * the parsed chunk is not well balanced, assuming the parsing succeeded to @@ -13720,144 +12507,49 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, */ int xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst, + void *user_data, int depth, const xmlChar *string, xmlNodePtr *listOut, int recover) { xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc; - xmlSAXHandlerPtr oldsax = NULL; - xmlNodePtr content, newRoot; - int size; - int ret = 0; - - if (depth > 40) { - return(XML_ERR_ENTITY_LOOP); - } + xmlParserInputPtr input; + xmlNodePtr list; + int ret; + if (listOut != NULL) + *listOut = NULL; - if (lst != NULL) - *lst = NULL; if (string == NULL) - return(-1); + return(XML_ERR_ARGUMENT); - size = xmlStrlen(string); - - ctxt = xmlCreateMemoryParserCtxt((char *) string, size); - if (ctxt == NULL) return(-1); - ctxt->userData = ctxt; - if (sax != NULL) { - oldsax = ctxt->sax; - ctxt->sax = sax; - if (user_data != NULL) - ctxt->userData = user_data; - } - newDoc = xmlNewDoc(BAD_CAST "1.0"); - if (newDoc == NULL) { - xmlFreeParserCtxt(ctxt); - return(-1); - } - newDoc->properties = XML_DOC_INTERNAL; - if ((doc != NULL) && (doc->dict != NULL)) { - xmlDictFree(ctxt->dict); - ctxt->dict = doc->dict; - xmlDictReference(ctxt->dict); - ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); - ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); - ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); - ctxt->dictNames = 1; - } else { - xmlCtxtUseOptionsInternal(ctxt, XML_PARSE_NODICT, NULL); - } - /* doc == NULL is only supported for historic reasons */ - if (doc != NULL) { - newDoc->intSubset = doc->intSubset; - newDoc->extSubset = doc->extSubset; - } - newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - if (sax != NULL) - ctxt->sax = oldsax; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - return(-1); - } - xmlAddChild((xmlNodePtr) newDoc, newRoot); - nodePush(ctxt, newRoot); - /* doc == NULL is only supported for historic reasons */ - if (doc == NULL) { - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = newDoc; - newDoc->children->doc = doc; - /* Ensure that doc has XML spec namespace */ - xmlSearchNsByHref(doc, (xmlNodePtr)doc, XML_XML_NAMESPACE); - newDoc->oldNs = doc->oldNs; - } - ctxt->instate = XML_PARSER_CONTENT; - ctxt->input_id = 2; - ctxt->depth = depth; + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) + return(XML_ERR_NO_MEMORY); - /* - * Doing validity checking on chunk doesn't make sense - */ - ctxt->validate = 0; - ctxt->loadsubset = 0; - xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(ctxt); - if ( doc != NULL ){ - content = doc->children; - doc->children = NULL; - xmlParseContent(ctxt); - doc->children = content; - } - else { - xmlParseContent(ctxt); - } - if ((RAW == '<') && (NXT(1) == '/')) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); - } - if (ctxt->node != newDoc->children) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + ctxt->depth = depth; + ctxt->myDoc = doc; + if (recover) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; } - if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = 1; - else - ret = ctxt->errNo; - } else { - ret = 0; - } + input = xmlNewStringInputStream(ctxt, string); + if (input == NULL) + return(ctxt->errNo); - if ((lst != NULL) && ((ret == 0) || (recover == 1))) { - xmlNodePtr cur; + list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 0, 1); + if (listOut != NULL) + *listOut = list; + else + xmlFreeNodeList(list); - /* - * Return the newly created nodeset after unlinking it from - * they pseudo parent. - */ - cur = newDoc->children->children; - *lst = cur; - while (cur != NULL) { - xmlSetTreeDoc(cur, doc); - cur->parent = NULL; - cur = cur->next; - } - newDoc->children->children = NULL; - } + if (!ctxt->wellFormed) + ret = ctxt->errNo; + else + ret = XML_ERR_OK; - if (sax != NULL) - ctxt->sax = oldsax; + xmlFreeInputStream(input); xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - /* This leaks the namespace list if doc == NULL */ - newDoc->oldNs = NULL; - xmlFreeDoc(newDoc); - return(ret); } @@ -13866,6 +12558,8 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, * @sax: the SAX handler block * @filename: the filename * + * DEPRECATED: Don't use. + * * parse an XML external entity out of context and build a tree. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. @@ -13887,23 +12581,24 @@ xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { return(NULL); } if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = NULL; } xmlParseExtParsedEnt(ctxt); - if (ctxt->wellFormed) + if (ctxt->wellFormed) { ret = ctxt->myDoc; - else { + } else { ret = NULL; xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; } - if (sax != NULL) - ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); return(ret); @@ -13929,11 +12624,12 @@ xmlParseEntity(const char *filename) { #endif /* LIBXML_SAX1_ENABLED */ /** - * xmlCreateEntityParserCtxtInternal: + * xmlCreateEntityParserCtxt: * @URL: the entity URL * @ID: the entity PUBLIC ID * @base: a possible base for the target URI - * @pctx: parser context used to set options on new context + * + * DEPRECATED: Don't use. * * Create a parser context for an external entity * Automatic support for ZLIB/Compress compressed document is provided @@ -13941,84 +12637,38 @@ xmlParseEntity(const char *filename) { * * Returns the new parser context or NULL */ -static xmlParserCtxtPtr -xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, - const xmlChar *base, xmlParserCtxtPtr pctx) { +xmlParserCtxtPtr +xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, + const xmlChar *base) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - char *directory = NULL; - xmlChar *uri; + xmlParserInputPtr input; + xmlChar *uri = NULL; ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { + if (ctxt == NULL) return(NULL); - } - if (pctx != NULL) { - ctxt->options = pctx->options; - ctxt->_private = pctx->_private; - /* - * this is a subparser of pctx, so the input_id should be - * incremented to distinguish from main entity - */ - ctxt->input_id = pctx->input_id + 1; + if (base != NULL) { + if (xmlBuildURISafe(URL, base, &uri) < 0) + goto error; + if (uri != NULL) + URL = uri; } - /* Don't read from stdin. */ - if (xmlStrcmp(URL, BAD_CAST "-") == 0) - URL = BAD_CAST "./-"; - - uri = xmlBuildURI(URL, base); - - if (uri == NULL) { - inputStream = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - inputPush(ctxt, inputStream); - - if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory((char *)URL); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; - } else { - inputStream = xmlLoadExternalEntity((char *)uri, (char *)ID, ctxt); - if (inputStream == NULL) { - xmlFree(uri); - xmlFreeParserCtxt(ctxt); - return(NULL); - } + input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); + if (input == NULL) + goto error; - inputPush(ctxt, inputStream); + if (inputPush(ctxt, input) < 0) + goto error; - if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory((char *)uri); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; - xmlFree(uri); - } + xmlFree(uri); return(ctxt); -} - -/** - * xmlCreateEntityParserCtxt: - * @URL: the entity URL - * @ID: the entity PUBLIC ID - * @base: a possible base for the target URI - * - * Create a parser context for an external entity - * Automatic support for ZLIB/Compress compressed document is provided - * by default if found at compile-time. - * - * Returns the new parser context or NULL - */ -xmlParserCtxtPtr -xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, - const xmlChar *base) { - return xmlCreateEntityParserCtxtInternal(URL, ID, base, NULL); +error: + xmlFree(uri); + xmlFreeParserCtxt(ctxt); + return(NULL); } /************************************************************************ @@ -14032,6 +12682,8 @@ xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, * @filename: the filename or URL * @options: a combination of xmlParserOption * + * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile. + * * Create a parser context for a file or URL content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time and for file accesses @@ -14042,30 +12694,21 @@ xmlParserCtxtPtr xmlCreateURLParserCtxt(const char *filename, int options) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - char *directory = NULL; + xmlParserInputPtr input; ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlErrMemory(NULL, "cannot allocate parser context"); + if (ctxt == NULL) return(NULL); - } - if (options) - xmlCtxtUseOptionsInternal(ctxt, options, NULL); + xmlCtxtUseOptions(ctxt, options); ctxt->linenumbers = 1; - inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (inputStream == NULL) { + input = xmlLoadExternalEntity(filename, NULL, ctxt); + if (input == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); } - - inputPush(ctxt, inputStream); - if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory(filename); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; + inputPush(ctxt, input); return(ctxt); } @@ -14074,6 +12717,8 @@ xmlCreateURLParserCtxt(const char *filename, int options) * xmlCreateFileParserCtxt: * @filename: the filename * + * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile. + * * Create a parser context for a file content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. @@ -14095,6 +12740,8 @@ xmlCreateFileParserCtxt(const char *filename) * documents * @data: the userdata * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. + * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * It use the given SAX function block to handle the parsing callback. @@ -14111,48 +12758,28 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; - xmlInitParser(); - - ctxt = xmlCreateFileParserCtxt(filename); - if (ctxt == NULL) { + ctxt = xmlNewSAXParserCtxt(sax, NULL); + if (ctxt == NULL) return(NULL); - } - if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; - } - xmlDetectSAX2(ctxt); - if (data!=NULL) { - ctxt->_private = data; - } - - if (ctxt->directory == NULL) - ctxt->directory = xmlParserGetDirectory(filename); - ctxt->recovery = recovery; - - xmlParseDocument(ctxt); + if (data != NULL) + ctxt->_private = data; - if ((ctxt->wellFormed) || recovery) { - ret = ctxt->myDoc; - if ((ret != NULL) && (ctxt->input->buf != NULL)) { - if (ctxt->input->buf->compressed > 0) - ret->compression = 9; - else - ret->compression = ctxt->input->buf->compressed; - } - } - else { - ret = NULL; - xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; + if (recovery) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; } - if (sax != NULL) - ctxt->sax = NULL; - xmlFreeParserCtxt(ctxt); + if ((filename != NULL) && (filename[0] == '-') && (filename[1] == 0)) + input = xmlNewInputFd(ctxt, filename, STDIN_FILENO, NULL, 0); + else + input = xmlNewInputURL(ctxt, filename, NULL, NULL, 0); + + ret = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); return(ret); } @@ -14163,6 +12790,8 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. + * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * It use the given SAX function block to handle the parsing callback. @@ -14181,6 +12810,8 @@ xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, * xmlRecoverDoc: * @cur: a pointer to an array of xmlChar * + * DEPRECATED: Use xmlReadDoc with XML_PARSE_RECOVER. + * * parse an XML in-memory document and build a tree. * In the case the document is not Well Formed, a attempt to build a * tree is tried anyway @@ -14197,6 +12828,8 @@ xmlRecoverDoc(const xmlChar *cur) { * xmlParseFile: * @filename: the filename * + * DEPRECATED: Use xmlReadFile. + * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * @@ -14213,6 +12846,8 @@ xmlParseFile(const char *filename) { * xmlRecoverFile: * @filename: the filename * + * DEPRECATED: Use xmlReadFile with XML_PARSE_RECOVER. + * * parse an XML file and build a tree. Automatic support for ZLIB/Compress * compressed document is provided by default if found at compile-time. * In the case the document is not Well Formed, it attempts to build @@ -14233,6 +12868,8 @@ xmlRecoverFile(const char *filename) { * @buffer: a xmlChar * buffer * @filename: a file name * + * DEPRECATED: Don't use. + * * Setup the parser context to parse a new buffer; Clears any prior * contents from the parser context. The buffer parameter must not be * NULL, but the filename parameter can be @@ -14246,19 +12883,11 @@ xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, if ((ctxt == NULL) || (buffer == NULL)) return; - input = xmlNewInputStream(ctxt); - if (input == NULL) { - xmlErrMemory(NULL, "parsing new buffer: out of memory\n"); - xmlClearParserCtxt(ctxt); - return; - } - xmlClearParserCtxt(ctxt); - if (filename != NULL) - input->filename = (char *) xmlCanonicPath((const xmlChar *)filename); - input->base = buffer; - input->cur = buffer; - input->end = &buffer[xmlStrlen(buffer)]; + + input = xmlNewInputString(ctxt, filename, (const char *) buffer, NULL, 0); + if (input == NULL) + return; inputPush(ctxt, input); } @@ -14268,6 +12897,8 @@ xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, * @user_data: The user data returned on SAX callbacks * @filename: a file name * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadFile. + * * parse an XML file and call the given SAX handler routines. * Automatic support for ZLIB/Compress compressed document is provided * @@ -14281,13 +12912,15 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) return -1; - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) - xmlFree(ctxt->sax); - ctxt->sax = sax; - xmlDetectSAX2(ctxt); - - if (user_data != NULL) + if (sax != NULL) { + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = user_data; + } xmlParseDocument(ctxt); @@ -14299,8 +12932,6 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, else ret = -1; } - if (sax != NULL) - ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14322,7 +12953,8 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, * @buffer: a pointer to a char array * @size: the size of the array * - * Create a parser context for an XML in-memory document. + * Create a parser context for an XML in-memory document. The input buffer + * must not contain a terminating null byte. * * Returns the new parser context or NULL */ @@ -14330,36 +12962,21 @@ xmlParserCtxtPtr xmlCreateMemoryParserCtxt(const char *buffer, int size) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf; - if (buffer == NULL) - return(NULL); - if (size <= 0) + if (size < 0) return(NULL); ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return(NULL); - /* TODO: xmlParserInputBufferCreateStatic, requires some serious changes */ - buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (buf == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - input = xmlNewInputStream(ctxt); + input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); } - - input->filename = NULL; - input->buf = buf; - xmlBufResetInput(input->buf->buffer, input); - inputPush(ctxt, input); + return(ctxt); } @@ -14373,6 +12990,8 @@ xmlCreateMemoryParserCtxt(const char *buffer, int size) { * documents * @data: the userdata * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. + * * parse an XML in-memory block and use the given SAX function block * to handle the parsing callback. If sax is NULL, fallback to the default * DOM tree building routines. @@ -14385,38 +13004,32 @@ xmlCreateMemoryParserCtxt(const char *buffer, int size) { xmlDocPtr xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, - int size, int recovery, void *data) { + int size, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; - xmlInitParser(); + if (size < 0) + return(NULL); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); - if (ctxt == NULL) return(NULL); - if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; - } - xmlDetectSAX2(ctxt); - if (data!=NULL) { + ctxt = xmlNewSAXParserCtxt(sax, NULL); + if (ctxt == NULL) + return(NULL); + + if (data != NULL) ctxt->_private=data; + + if (recovery) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; } - ctxt->recovery = recovery; + input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL, + XML_INPUT_BUF_STATIC); - xmlParseDocument(ctxt); + ret = xmlCtxtParseDocument(ctxt, input); - if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; - else { - ret = NULL; - xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; - } - if (sax != NULL) - ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); - return(ret); } @@ -14428,6 +13041,8 @@ xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, * @recovery: work in recovery mode, i.e. tries to read not Well Formed * documents * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. + * * parse an XML in-memory block and use the given SAX function block * to handle the parsing callback. If sax is NULL, fallback to the default * DOM tree building routines. @@ -14445,6 +13060,8 @@ xmlSAXParseMemory(xmlSAXHandlerPtr sax, const char *buffer, * @buffer: an pointer to a char array * @size: the size of the array * + * DEPRECATED: Use xmlReadMemory. + * * parse an XML in-memory block and build a tree. * * Returns the resulting document tree @@ -14459,6 +13076,8 @@ xmlDocPtr xmlParseMemory(const char *buffer, int size) { * @buffer: an pointer to a char array * @size: the size of the array * + * DEPRECATED: Use xmlReadMemory with XML_PARSE_RECOVER. + * * parse an XML in-memory block and build a tree. * In the case the document is not Well Formed, an attempt to * build a tree is tried anyway @@ -14477,7 +13096,8 @@ xmlDocPtr xmlRecoverMemory(const char *buffer, int size) { * @buffer: an in-memory XML document input * @size: the length of the XML document in bytes * - * A better SAX parsing routine. + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadMemory. + * * parse an XML in-memory buffer and call the given SAX handler routines. * * Returns 0 in case of success or a error number otherwise @@ -14487,17 +13107,17 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, int ret = 0; xmlParserCtxtPtr ctxt; - xmlInitParser(); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); if (ctxt == NULL) return -1; - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) - xmlFree(ctxt->sax); - ctxt->sax = sax; - xmlDetectSAX2(ctxt); - - if (user_data != NULL) + if (sax != NULL) { + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = user_data; + } xmlParseDocument(ctxt); @@ -14509,8 +13129,6 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, else ret = -1; } - if (sax != NULL) - ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14523,20 +13141,29 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, /** * xmlCreateDocParserCtxt: - * @cur: a pointer to an array of xmlChar + * @str: a pointer to an array of xmlChar * * Creates a parser context for an XML in-memory document. * * Returns the new parser context or NULL */ xmlParserCtxtPtr -xmlCreateDocParserCtxt(const xmlChar *cur) { - int len; +xmlCreateDocParserCtxt(const xmlChar *str) { + xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; - if (cur == NULL) + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return(NULL); + + input = xmlNewInputString(ctxt, NULL, (const char *) str, NULL, 0); + if (input == NULL) { + xmlFreeParserCtxt(ctxt); return(NULL); - len = xmlStrlen(cur); - return(xmlCreateMemoryParserCtxt((const char *)cur, len)); + } + inputPush(ctxt, input); + + return(ctxt); } #ifdef LIBXML_SAX1_ENABLED @@ -14547,6 +13174,8 @@ xmlCreateDocParserCtxt(const xmlChar *cur) { * @recovery: work in recovery mode, i.e. tries to read no Well Formed * documents * + * DEPRECATED: Use xmlNewSAXParserCtxt and xmlCtxtReadDoc. + * * parse an XML in-memory document and build a tree. * It use the given SAX function block to handle the parsing callback. * If sax is NULL, fallback to the default DOM tree building routines. @@ -14570,7 +13199,6 @@ xmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery) { ctxt->sax = sax; ctxt->userData = NULL; } - xmlDetectSAX2(ctxt); xmlParseDocument(ctxt); if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; @@ -14590,6 +13218,8 @@ xmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery) { * xmlParseDoc: * @cur: a pointer to an array of xmlChar * + * DEPRECATED: Use xmlReadDoc. + * * parse an XML in-memory document and build a tree. * * Returns the resulting document tree @@ -14601,169 +13231,6 @@ xmlParseDoc(const xmlChar *cur) { } #endif /* LIBXML_SAX1_ENABLED */ -#ifdef LIBXML_LEGACY_ENABLED -/************************************************************************ - * * - * Specific function to keep track of entities references * - * and used by the XSLT debugger * - * * - ************************************************************************/ - -static xmlEntityReferenceFunc xmlEntityRefFunc = NULL; - -/** - * xmlAddEntityReference: - * @ent : A valid entity - * @firstNode : A valid first node for children of entity - * @lastNode : A valid last node of children entity - * - * Notify of a reference to an entity of type XML_EXTERNAL_GENERAL_PARSED_ENTITY - */ -static void -xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, - xmlNodePtr lastNode) -{ - if (xmlEntityRefFunc != NULL) { - (*xmlEntityRefFunc) (ent, firstNode, lastNode); - } -} - - -/** - * xmlSetEntityReferenceFunc: - * @func: A valid function - * - * Set the function to call call back when a xml reference has been made - */ -void -xmlSetEntityReferenceFunc(xmlEntityReferenceFunc func) -{ - xmlEntityRefFunc = func; -} -#endif /* LIBXML_LEGACY_ENABLED */ - -/************************************************************************ - * * - * Miscellaneous * - * * - ************************************************************************/ - -#ifdef LIBXML_XPATH_ENABLED -#include -#endif - -extern void XMLCDECL xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...); -static int xmlParserInitialized = 0; - -/** - * xmlInitParser: - * - * Initialization function for the XML parser. - * This is not reentrant. Call once before processing in case of - * use in multithreaded programs. - */ - -void -xmlInitParser(void) { - if (xmlParserInitialized != 0) - return; - -#if defined(_WIN32) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) - if (xmlFree == free) - atexit(xmlCleanupParser); -#endif - -#ifdef LIBXML_THREAD_ENABLED - __xmlGlobalInitMutexLock(); - if (xmlParserInitialized == 0) { -#endif - xmlInitThreads(); - xmlInitGlobals(); - if ((xmlGenericError == xmlGenericErrorDefaultFunc) || - (xmlGenericError == NULL)) - initGenericErrorDefaultFunc(NULL); - xmlInitMemory(); - xmlInitializeDict(); - xmlInitCharEncodingHandlers(); - xmlDefaultSAXHandlerInit(); - xmlRegisterDefaultInputCallbacks(); -#ifdef LIBXML_OUTPUT_ENABLED - xmlRegisterDefaultOutputCallbacks(); -#endif /* LIBXML_OUTPUT_ENABLED */ -#ifdef LIBXML_HTML_ENABLED - htmlInitAutoClose(); - htmlDefaultSAXHandlerInit(); -#endif -#ifdef LIBXML_XPATH_ENABLED - xmlXPathInit(); -#endif - xmlParserInitialized = 1; -#ifdef LIBXML_THREAD_ENABLED - } - __xmlGlobalInitMutexUnlock(); -#endif -} - -/** - * xmlCleanupParser: - * - * This function name is somewhat misleading. It does not clean up - * parser state, it cleans up memory allocated by the library itself. - * It is a cleanup function for the XML library. It tries to reclaim all - * related global memory allocated for the library processing. - * It doesn't deallocate any document related memory. One should - * call xmlCleanupParser() only when the process has finished using - * the library and all XML/HTML documents built with it. - * See also xmlInitParser() which has the opposite function of preparing - * the library for operations. - * - * 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 -xmlCleanupParser(void) { - if (!xmlParserInitialized) - return; - - xmlCleanupCharEncodingHandlers(); -#ifdef LIBXML_CATALOG_ENABLED - xmlCatalogCleanup(); -#endif - xmlDictCleanup(); - xmlCleanupInputCallbacks(); -#ifdef LIBXML_OUTPUT_ENABLED - xmlCleanupOutputCallbacks(); -#endif -#ifdef LIBXML_SCHEMAS_ENABLED - xmlSchemaCleanupTypes(); - xmlRelaxNGCleanupTypes(); -#endif - xmlCleanupGlobals(); - xmlCleanupThreads(); /* must be last if called not from the main thread */ - xmlCleanupMemory(); - xmlParserInitialized = 0; -} - -#if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && !defined(LIBXML_STATIC) && \ - !defined(_WIN32) -static void -ATTRIBUTE_DESTRUCTOR -xmlDestructor(void) { - /* - * Calling custom deallocation functions in a destructor can cause - * problems, for example with Nokogiri. - */ - if (xmlFree == free) - xmlCleanupParser(); -} -#endif - /************************************************************************ * * * New set (2.6.0) of simpler and more flexible APIs * @@ -14821,17 +13288,22 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) ctxt->name = NULL; ctxt->nsNr = 0; + xmlParserNsReset(ctxt->nsdb); DICT_FREE(ctxt->version); ctxt->version = NULL; DICT_FREE(ctxt->encoding); ctxt->encoding = NULL; - DICT_FREE(ctxt->directory); - ctxt->directory = NULL; DICT_FREE(ctxt->extSubURI); ctxt->extSubURI = NULL; DICT_FREE(ctxt->extSubSystem); ctxt->extSubSystem = NULL; + + if (ctxt->directory != NULL) { + xmlFree(ctxt->directory); + ctxt->directory = NULL; + } + if (ctxt->myDoc != NULL) xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14840,9 +13312,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 0; - ctxt->external = 0; ctxt->instate = XML_PARSER_START; - ctxt->token = 0; ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; @@ -14855,12 +13325,11 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) #endif ctxt->record_info = 0; ctxt->checkIndex = 0; + ctxt->endCheckState = 0; ctxt->inSubset = 0; ctxt->errNo = XML_ERR_OK; ctxt->depth = 0; - ctxt->charset = XML_CHAR_ENCODING_UTF8; ctxt->catalogs = NULL; - ctxt->nbentities = 0; ctxt->sizeentities = 0; ctxt->sizeentcopy = 0; xmlInitNodeInfoSeq(&ctxt->node_seq); @@ -14878,6 +13347,8 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) if (ctxt->catalogs != NULL) xmlCatalogFreeLocal(ctxt->catalogs); #endif + ctxt->nbErrors = 0; + ctxt->nbWarnings = 0; if (ctxt->lastError.code != XML_ERR_OK) xmlResetError(&ctxt->lastError); } @@ -14898,224 +13369,258 @@ int xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk, int size, const char *filename, const char *encoding) { - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + xmlParserInputPtr input; if (ctxt == NULL) return(1); - if ((encoding == NULL) && (chunk != NULL) && (size >= 4)) - enc = xmlDetectCharEncoding((const xmlChar *) chunk, size); - - buf = xmlAllocParserInputBuffer(enc); - if (buf == NULL) - return(1); - - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); - return(1); - } - xmlCtxtReset(ctxt); - if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - } - - inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { - xmlFreeParserInputBuffer(buf); + input = xmlNewInputPush(ctxt, filename, chunk, size, encoding); + if (input == NULL) return(1); - } - - if (filename == NULL) - inputStream->filename = NULL; - else - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - inputStream->buf = buf; - xmlBufResetInput(buf->buffer, inputStream); + inputPush(ctxt, input); - inputPush(ctxt, inputStream); + return(0); +} - if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL)) { - size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input); - size_t cur = ctxt->input->cur - ctxt->input->base; +static int +xmlCtxtSetOptionsInternal(xmlParserCtxtPtr ctxt, int options, int keepMask) +{ + int allMask; - xmlParserInputBufferPush(ctxt->input->buf, size, chunk); + if (ctxt == NULL) + return(-1); - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); + /* + * XInclude options aren't handled by the parser. + * + * XML_PARSE_XINCLUDE + * XML_PARSE_NOXINCNODE + * XML_PARSE_NOBASEFIX + */ + allMask = XML_PARSE_RECOVER | + XML_PARSE_NOENT | + XML_PARSE_DTDLOAD | + XML_PARSE_DTDATTR | + XML_PARSE_DTDVALID | + XML_PARSE_NOERROR | + XML_PARSE_NOWARNING | + XML_PARSE_PEDANTIC | + XML_PARSE_NOBLANKS | +#ifdef LIBXML_SAX1_ENABLED + XML_PARSE_SAX1 | #endif - } - - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = xmlStrdup((const xmlChar *) encoding); + XML_PARSE_NONET | + XML_PARSE_NODICT | + XML_PARSE_NSCLEAN | + XML_PARSE_NOCDATA | + XML_PARSE_COMPACT | + XML_PARSE_OLD10 | + XML_PARSE_HUGE | + XML_PARSE_OLDSAX | + XML_PARSE_IGNORE_ENC | + XML_PARSE_BIG_LINES | + XML_PARSE_NO_XXE; + + ctxt->options = (ctxt->options & keepMask) | (options & allMask); + + /* + * For some options, struct members are historically the source + * of truth. The values are initalized from global variables and + * old code could also modify them directly. Several older API + * functions that don't take an options argument rely on these + * deprecated mechanisms. + * + * Once public access to struct members and the globals are + * disabled, we can use the options bitmask as source of + * truth, making all these struct members obsolete. + * + * The XML_DETECT_IDS flags is misnamed. It simply enables + * loading of the external subset. + */ + ctxt->recovery = (options & XML_PARSE_RECOVER) ? 1 : 0; + ctxt->replaceEntities = (options & XML_PARSE_NOENT) ? 1 : 0; + ctxt->loadsubset = (options & XML_PARSE_DTDLOAD) ? XML_DETECT_IDS : 0; + ctxt->loadsubset |= (options & XML_PARSE_DTDATTR) ? XML_COMPLETE_ATTRS : 0; + ctxt->validate = (options & XML_PARSE_DTDVALID) ? 1 : 0; + ctxt->pedantic = (options & XML_PARSE_PEDANTIC) ? 1 : 0; + ctxt->keepBlanks = (options & XML_PARSE_NOBLANKS) ? 0 : 1; + ctxt->dictNames = (options & XML_PARSE_NODICT) ? 0 : 1; - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } else { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", BAD_CAST encoding); - } - } else if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); + /* + * Changing SAX callbacks is a bad idea. This should be fixed. + */ + if (options & XML_PARSE_NOBLANKS) { + ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + } + if (options & XML_PARSE_NOCDATA) { + ctxt->sax->cdataBlock = NULL; + } + if (options & XML_PARSE_HUGE) { + if (ctxt->dict != NULL) + xmlDictSetLimit(ctxt->dict, 0); } - return(0); -} + ctxt->linenumbers = 1; + return(options & ~allMask); +} /** - * xmlCtxtUseOptionsInternal: + * xmlCtxtSetOptions: * @ctxt: an XML parser context - * @options: a combination of xmlParserOption - * @encoding: the user provided encoding to use + * @options: a bitmask of xmlParserOption values + * + * Applies the options to the parser context. Unset options are + * cleared. + * + * Available since 2.13.0. With older versions, you can use + * xmlCtxtUseOptions. + * + * XML_PARSE_RECOVER + * + * Enable "recovery" mode which allows non-wellformed documents. + * How this mode behaves exactly is unspecified and may change + * without further notice. Use of this feature is DISCOURAGED. + * + * XML_PARSE_NOENT + * + * Despite the confusing name, this option enables substitution + * of entities. The resulting tree won't contain any entity + * reference nodes. + * + * This option also enables loading of external entities (both + * general and parameter entities) which is dangerous. If you + * process untrusted data, it's recommended to set the + * XML_PARSE_NO_XXE option to disable loading of external + * entities. + * + * XML_PARSE_DTDLOAD + * + * Enables loading of an external DTD and the loading and + * substitution of external parameter entities. Has no effect + * if XML_PARSE_NO_XXE is set. + * + * XML_PARSE_DTDATTR + * + * Adds default attributes from the DTD to the result document. + * + * Implies XML_PARSE_DTDLOAD, but loading of external content + * can be disabled with XML_PARSE_NO_XXE. + * + * XML_PARSE_DTDVALID + * + * This option enables DTD validation which requires to load + * external DTDs and external entities (both general and + * parameter entities) unless XML_PARSE_NO_XXE was set. + * + * XML_PARSE_NO_XXE + * + * Disables loading of external DTDs or entities. + * + * XML_PARSE_NOERROR + * + * Disable error and warning reports to the error handlers. + * Errors are still accessible with xmlCtxtGetLastError. + * + * XML_PARSE_NOWARNING + * + * Disable warning reports. + * + * XML_PARSE_PEDANTIC + * + * Enable some pedantic warnings. + * + * XML_PARSE_NOBLANKS + * + * Remove some text nodes containing only whitespace from the + * result document. Which nodes are removed depends on DTD + * element declarations or a conservative heuristic. The + * reindenting feature of the serialization code relies on this + * option to be set when parsing. Use of this option is + * DISCOURAGED. + * + * XML_PARSE_SAX1 + * + * Always invoke the deprecated SAX1 startElement and endElement + * handlers. This option is DEPRECATED. + * + * XML_PARSE_NONET + * + * Disable network access with the builtin HTTP and FTP clients. + * + * XML_PARSE_NODICT + * + * Create a document without interned strings, making all + * strings separate memory allocations. + * + * XML_PARSE_NSCLEAN + * + * Remove redundant namespace declarations from the result + * document. + * + * XML_PARSE_NOCDATA + * + * Output normal text nodes instead of CDATA nodes. + * + * XML_PARSE_COMPACT + * + * Store small strings directly in the node struct to save + * memory. + * + * XML_PARSE_OLD10 + * + * Use old Name productions from before XML 1.0 Fifth Edition. + * This options is DEPRECATED. + * + * XML_PARSE_HUGE + * + * Relax some internal limits. + * + * Maximum size of text nodes, tags, comments, processing instructions, + * CDATA sections, entity values + * + * normal: 10M + * huge: 1B + * + * Maximum size of names, system literals, pubid literals * - * Applies the options to the parser context + * normal: 50K + * huge: 10M + * + * Maximum nesting depth of elements + * + * normal: 256 + * huge: 2048 + * + * Maximum nesting depth of entities + * + * normal: 20 + * huge: 40 + * + * XML_PARSE_OLDSAX + * + * Enable an unspecified legacy mode for SAX parsers. This + * option is DEPRECATED. + * + * XML_PARSE_IGNORE_ENC + * + * Ignore the encoding in the XML declaration. This option is + * mostly unneeded these days. The only effect is to enforce + * UTF-8 decoding of ASCII-like data. + * + * XML_PARSE_BIG_LINES + * + * Enable reporting of line numbers larger than 65535. * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. */ -static int -xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, const char *encoding) +int +xmlCtxtSetOptions(xmlParserCtxtPtr ctxt, int options) { - if (ctxt == NULL) - return(-1); - if (encoding != NULL) { - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = xmlStrdup((const xmlChar *) encoding); - } - if (options & XML_PARSE_RECOVER) { - ctxt->recovery = 1; - options -= XML_PARSE_RECOVER; - ctxt->options |= XML_PARSE_RECOVER; - } else - ctxt->recovery = 0; - if (options & XML_PARSE_DTDLOAD) { - ctxt->loadsubset = XML_DETECT_IDS; - options -= XML_PARSE_DTDLOAD; - ctxt->options |= XML_PARSE_DTDLOAD; - } else - ctxt->loadsubset = 0; - if (options & XML_PARSE_DTDATTR) { - ctxt->loadsubset |= XML_COMPLETE_ATTRS; - options -= XML_PARSE_DTDATTR; - ctxt->options |= XML_PARSE_DTDATTR; - } - if (options & XML_PARSE_NOENT) { - ctxt->replaceEntities = 1; - /* ctxt->loadsubset |= XML_DETECT_IDS; */ - options -= XML_PARSE_NOENT; - ctxt->options |= XML_PARSE_NOENT; - } else - ctxt->replaceEntities = 0; - if (options & XML_PARSE_PEDANTIC) { - ctxt->pedantic = 1; - options -= XML_PARSE_PEDANTIC; - ctxt->options |= XML_PARSE_PEDANTIC; - } else - ctxt->pedantic = 0; - if (options & XML_PARSE_NOBLANKS) { - ctxt->keepBlanks = 0; - ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; - options -= XML_PARSE_NOBLANKS; - ctxt->options |= XML_PARSE_NOBLANKS; - } else - ctxt->keepBlanks = 1; - if (options & XML_PARSE_DTDVALID) { - ctxt->validate = 1; - if (options & XML_PARSE_NOWARNING) - ctxt->vctxt.warning = NULL; - if (options & XML_PARSE_NOERROR) - ctxt->vctxt.error = NULL; - options -= XML_PARSE_DTDVALID; - ctxt->options |= XML_PARSE_DTDVALID; - } else - ctxt->validate = 0; - if (options & XML_PARSE_NOWARNING) { - ctxt->sax->warning = NULL; - options -= XML_PARSE_NOWARNING; - } - if (options & XML_PARSE_NOERROR) { - ctxt->sax->error = NULL; - ctxt->sax->fatalError = NULL; - options -= XML_PARSE_NOERROR; - } -#ifdef LIBXML_SAX1_ENABLED - if (options & XML_PARSE_SAX1) { - ctxt->sax->startElement = xmlSAX2StartElement; - ctxt->sax->endElement = xmlSAX2EndElement; - ctxt->sax->startElementNs = NULL; - ctxt->sax->endElementNs = NULL; - ctxt->sax->initialized = 1; - options -= XML_PARSE_SAX1; - ctxt->options |= XML_PARSE_SAX1; - } -#endif /* LIBXML_SAX1_ENABLED */ - if (options & XML_PARSE_NODICT) { - ctxt->dictNames = 0; - options -= XML_PARSE_NODICT; - ctxt->options |= XML_PARSE_NODICT; - } else { - ctxt->dictNames = 1; - } - if (options & XML_PARSE_NOCDATA) { - ctxt->sax->cdataBlock = NULL; - options -= XML_PARSE_NOCDATA; - ctxt->options |= XML_PARSE_NOCDATA; - } - if (options & XML_PARSE_NSCLEAN) { - ctxt->options |= XML_PARSE_NSCLEAN; - options -= XML_PARSE_NSCLEAN; - } - if (options & XML_PARSE_NONET) { - ctxt->options |= XML_PARSE_NONET; - options -= XML_PARSE_NONET; - } - if (options & XML_PARSE_COMPACT) { - ctxt->options |= XML_PARSE_COMPACT; - options -= XML_PARSE_COMPACT; - } - if (options & XML_PARSE_OLD10) { - ctxt->options |= XML_PARSE_OLD10; - options -= XML_PARSE_OLD10; - } - if (options & XML_PARSE_NOBASEFIX) { - ctxt->options |= XML_PARSE_NOBASEFIX; - options -= XML_PARSE_NOBASEFIX; - } - if (options & XML_PARSE_HUGE) { - ctxt->options |= XML_PARSE_HUGE; - options -= XML_PARSE_HUGE; - if (ctxt->dict != NULL) - xmlDictSetLimit(ctxt->dict, 0); - } - if (options & XML_PARSE_OLDSAX) { - ctxt->options |= XML_PARSE_OLDSAX; - options -= XML_PARSE_OLDSAX; - } - if (options & XML_PARSE_IGNORE_ENC) { - ctxt->options |= XML_PARSE_IGNORE_ENC; - options -= XML_PARSE_IGNORE_ENC; - } - if (options & XML_PARSE_BIG_LINES) { - ctxt->options |= XML_PARSE_BIG_LINES; - options -= XML_PARSE_BIG_LINES; - } - ctxt->linenumbers = 1; - return (options); + return(xmlCtxtSetOptionsInternal(ctxt, options, 0)); } /** @@ -15123,7 +13628,22 @@ xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, const char *encodi * @ctxt: an XML parser context * @options: a combination of xmlParserOption * - * Applies the options to the parser context + * DEPRECATED: Use xmlCtxtSetOptions. + * + * Applies the options to the parser context. The following options + * are never cleared and can only be enabled: + * + * XML_PARSE_NOERROR + * XML_PARSE_NOWARNING + * XML_PARSE_NONET + * XML_PARSE_NSCLEAN + * XML_PARSE_NOCDATA + * XML_PARSE_COMPACT + * XML_PARSE_OLD10 + * XML_PARSE_HUGE + * XML_PARSE_OLDSAX + * XML_PARSE_IGNORE_ENC + * XML_PARSE_BIG_LINES * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. @@ -15131,88 +13651,142 @@ xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, const char *encodi int xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options) { - return(xmlCtxtUseOptionsInternal(ctxt, options, NULL)); + int keepMask; + + /* + * For historic reasons, some options can only be enabled. + */ + keepMask = XML_PARSE_NOERROR | + XML_PARSE_NOWARNING | + XML_PARSE_NONET | + XML_PARSE_NSCLEAN | + XML_PARSE_NOCDATA | + XML_PARSE_COMPACT | + XML_PARSE_OLD10 | + XML_PARSE_HUGE | + XML_PARSE_OLDSAX | + XML_PARSE_IGNORE_ENC | + XML_PARSE_BIG_LINES; + + return(xmlCtxtSetOptionsInternal(ctxt, options, keepMask)); +} + +/** + * xmlCtxtSetMaxAmplification: + * @ctxt: an XML parser context + * @maxAmpl: maximum amplification factor + * + * To protect against exponential entity expansion ("billion laughs"), the + * size of serialized output is (roughly) limited to the input size + * multiplied by this factor. The default value is 5. + * + * When working with documents making heavy use of entity expansion, it can + * be necessary to increase the value. For security reasons, this should only + * be considered when processing trusted input. + */ +void +xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, unsigned maxAmpl) +{ + ctxt->maxAmpl = maxAmpl; } /** - * xmlDoRead: + * xmlCtxtParseDocument: * @ctxt: an XML parser context - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of xmlParserOption - * @reuse: keep the context for reuse + * @input: parser input * - * Common front-end for the xmlRead functions + * Parse an XML document and return the resulting document tree. + * Takes ownership of the input object. + * + * Available since 2.13.0. * * Returns the resulting document tree or NULL */ -static xmlDocPtr -xmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding, - int options, int reuse) +xmlDocPtr +xmlCtxtParseDocument(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { - xmlDocPtr ret; + xmlDocPtr ret = NULL; + + if ((ctxt == NULL) || (input == NULL)) + return(NULL); - xmlCtxtUseOptionsInternal(ctxt, options, encoding); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; + /* assert(ctxt->inputNr == 0); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) - xmlSwitchToEncoding(ctxt, hdlr); + if (inputPush(ctxt, input) < 0) { + xmlFreeInputStream(input); + return(NULL); } - if ((URL != NULL) && (ctxt->input != NULL) && - (ctxt->input->filename == NULL)) - ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + xmlParseDocument(ctxt); - if ((ctxt->wellFormed) || ctxt->recovery) + + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { ret = ctxt->myDoc; - else { + } else { + if (ctxt->errNo == XML_ERR_OK) + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "unknown error\n"); + ret = NULL; - if (ctxt->myDoc != NULL) { - xmlFreeDoc(ctxt->myDoc); - } + xmlFreeDoc(ctxt->myDoc); } ctxt->myDoc = NULL; - if (!reuse) { - xmlFreeParserCtxt(ctxt); - } - return (ret); + /* assert(ctxt->inputNr == 1); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + return(ret); } /** * xmlReadDoc: * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an XML document from a + * zero-terminated string. + * + * See xmlCtxtReadDoc for details. * * Returns the resulting document tree */ xmlDocPtr -xmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) +xmlReadDoc(const xmlChar *cur, const char *URL, const char *encoding, + int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc; - if (cur == NULL) - return (NULL); - xmlInitParser(); - - ctxt = xmlCreateDocParserCtxt(cur); + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, URL, (const char *) cur, encoding, + XML_INPUT_BUF_STATIC); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); } /** * xmlReadFile: * @filename: a file or URL - * @encoding: the document encoding, or NULL + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML file from the filesystem or the network. + * Convenience function to parse an XML file from the filesystem, + * the network or a global user-define resource loader. + * + * See xmlCtxtReadFile for details. * * Returns the resulting document tree */ @@ -15220,48 +13794,85 @@ xmlDocPtr xmlReadFile(const char *filename, const char *encoding, int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc; - xmlInitParser(); - ctxt = xmlCreateURLParserCtxt(filename, options); + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, NULL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + /* + * Backward compatibility for users of command line utilities like + * xmlstarlet expecting "-" to mean stdin. This is dangerous and + * should be removed at some point. + */ + if ((filename != NULL) && (filename[0] == '-') && (filename[1] == 0)) + input = xmlNewInputFd(ctxt, filename, STDIN_FILENO, encoding, 0); + else + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); } /** * xmlReadMemory: * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @url: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. + * Parse an XML in-memory document and build a tree. The input buffer must + * not contain a terminating null byte. + * + * See xmlCtxtReadMemory for details. * * Returns the resulting document tree */ xmlDocPtr -xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) +xmlReadMemory(const char *buffer, int size, const char *url, + const char *encoding, int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc; - xmlInitParser(); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (size < 0) + return(NULL); + + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, + XML_INPUT_BUF_STATIC); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); } /** * xmlReadFd: * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML from a file descriptor and build a tree. + * Parse an XML from a file descriptor and build a tree. + * + * See xmlCtxtReadFd for details. + * * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. * * Returns the resulting document tree */ @@ -15269,42 +13880,35 @@ xmlDocPtr xmlReadFd(int fd, const char *URL, const char *encoding, int options) { xmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; - - if (fd < 0) - return (NULL); - xmlInitParser(); + xmlParserInputPtr input; + xmlDocPtr doc; - input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); - if (input == NULL) - return (NULL); - input->closecallback = NULL; ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - xmlFreeParserCtxt(ctxt); - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + if (ctxt == NULL) + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputFd(ctxt, URL, fd, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); } /** * xmlReadIO: * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML document from I/O functions and source and build a tree. + * Parse an XML document from I/O functions and context and build a tree. + * + * See xmlCtxtReadIO for details. * * Returns the resulting document tree */ @@ -15313,67 +13917,67 @@ xmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, const char *URL, const char *encoding, int options) { xmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; - - if (ioread == NULL) - return (NULL); - xmlInitParser(); + xmlParserInputPtr input; + xmlDocPtr doc; - input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - xmlFreeParserCtxt(ctxt); - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + if (ctxt == NULL) + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); } /** * xmlCtxtReadDoc: * @ctxt: an XML parser context - * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @str: a pointer to a zero terminated string + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML in-memory document and build a tree. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ xmlDocPtr -xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar * cur, +xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar *str, const char *URL, const char *encoding, int options) { - if (cur == NULL) - return (NULL); - return (xmlCtxtReadMemory(ctxt, (const char *) cur, xmlStrlen(cur), URL, - encoding, options)); + xmlParserInputPtr input; + + if (ctxt == NULL) + return(NULL); + + xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, URL, (const char *) str, encoding, + XML_INPUT_BUF_STATIC); + + return(xmlCtxtParseDocument(ctxt, input)); } /** * xmlCtxtReadFile: * @ctxt: an XML parser context * @filename: a file or URL - * @encoding: the document encoding, or NULL + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML file from the filesystem or the network. - * This reuses the existing @ctxt parser context + * Parse an XML file from the filesystem, the network or a user-defined + * resource loader. * * Returns the resulting document tree */ @@ -15381,22 +13985,17 @@ xmlDocPtr xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options) { - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (filename == NULL) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL); xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options); - stream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (stream == NULL) { - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, NULL, encoding, options, 1)); + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + return(xmlCtxtParseDocument(ctxt, input)); } /** @@ -15404,12 +14003,17 @@ xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, * @ctxt: an XML parser context * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML in-memory document and build a tree. The input buffer must + * not contain a terminating null byte. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -15417,44 +14021,37 @@ xmlDocPtr xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (ctxt == NULL) - return (NULL); - if (buffer == NULL) - return (NULL); - xmlInitParser(); + if ((ctxt == NULL) || (size < 0)) + return(NULL); xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options); - input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (input == NULL) { - return(NULL); - } - - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return(NULL); - } + input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding, + XML_INPUT_BUF_STATIC); - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 1)); + return(xmlCtxtParseDocument(ctxt, input)); } /** * xmlCtxtReadFd: * @ctxt: an XML parser context * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML from a file descriptor and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML document from a file descriptor and build a tree. + * * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -15462,29 +14059,17 @@ xmlDocPtr xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (fd < 0) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL); xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options); + input = xmlNewInputFd(ctxt, URL, fd, encoding, 0); - input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); - if (input == NULL) - return (NULL); - input->closecallback = NULL; - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 1)); + return(xmlCtxtParseDocument(ctxt, input)); } /** @@ -15500,6 +14085,11 @@ xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, * parse an XML document from I/O functions and source and build a tree. * This reuses the existing @ctxt parser context * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. + * * Returns the resulting document tree */ xmlDocPtr @@ -15508,30 +14098,16 @@ xmlCtxtReadIO(xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; - if (ioread == NULL) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL); xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options); - input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 1)); + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + return(xmlCtxtParseDocument(ctxt, input)); } diff --git a/parserInternals.c b/parserInternals.c index 31d94680a55..6ddd28e7858 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -24,27 +24,35 @@ #include #include #include -#include #include #include #include -#include #include #include #include -#include +#include #ifdef LIBXML_CATALOG_ENABLED #include #endif -#include #include +#include #define CUR(ctxt) ctxt->input->cur #define END(ctxt) ctxt->input->end -#define VALID_CTXT(ctxt) (CUR(ctxt) <= END(ctxt)) -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" +#include "private/io.h" +#include "private/parser.h" + +#define XML_MAX_ERRORS 100 + +/* + * XML_MAX_AMPLIFICATION_DEFAULT is the default maximum allowed amplification + * factor of serialized output after entity expansion. + */ +#define XML_MAX_AMPLIFICATION_DEFAULT 5 /* * Various global defaults for parsing @@ -55,24 +63,19 @@ * @version: the include version number * * check the compiled lib version against the include one. - * This can warn or immediately kill the application */ void xmlCheckVersion(int version) { - int myversion = (int) LIBXML_VERSION; + int myversion = LIBXML_VERSION; xmlInitParser(); if ((myversion / 10000) != (version / 10000)) { - xmlGenericError(xmlGenericErrorContext, - "Fatal: program compiled against libxml %d using libxml %d\n", - (version / 10000), (myversion / 10000)); fprintf(stderr, "Fatal: program compiled against libxml %d using libxml %d\n", (version / 10000), (myversion / 10000)); - } - if ((myversion / 100) < (version / 100)) { - xmlGenericError(xmlGenericErrorContext, + } else if ((myversion / 100) < (version / 100)) { + fprintf(stderr, "Warning: program compiled against libxml %d using older %d\n", (version / 100), (myversion / 100)); } @@ -87,116 +90,290 @@ xmlCheckVersion(int version) { /** - * xmlErrMemory: + * xmlCtxtSetErrorHandler: * @ctxt: an XML parser context - * @extra: extra information + * @handler: error handler + * @data: data for error handler * - * Handle a redefinition of attribute error + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * This is the recommended way to collect errors from the parser and + * takes precedence over all other error reporting mechanisms. + * These are (in order of precedence): + * + * - per-context structured handler (xmlCtxtSetErrorHandler) + * - per-context structured "serror" SAX handler + * - global structured handler (xmlSetStructuredErrorFunc) + * - per-context generic "error" and "warning" SAX handlers + * - global generic handler (xmlSetGenericErrorFunc) + * - print to stderr + * + * Available since 2.13.0. */ void -xmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra) +xmlCtxtSetErrorHandler(xmlParserCtxtPtr ctxt, xmlStructuredErrorFunc handler, + void *data) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } - if (extra) - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + if (ctxt == NULL) + return; + ctxt->errorHandler = handler; + ctxt->errorCtxt = data; } /** - * __xmlErrEncoding: + * xmlCtxtErrMemory: * @ctxt: an XML parser context - * @xmlerr: the error number - * @msg: the error message - * @str1: an string info - * @str2: an string info * - * Handle an encoding error + * Handle an out-of-memory error. + * + * Available since 2.13.0. */ void -__xmlErrEncoding(xmlParserCtxtPtr ctxt, xmlParserErrors xmlerr, - const char *msg, const xmlChar * str1, const xmlChar * str2) +xmlCtxtErrMemory(xmlParserCtxtPtr ctxt) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = xmlerr; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, xmlerr, XML_ERR_FATAL, - NULL, 0, (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data; + + if (ctxt == NULL) + return; + + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; /* TODO: Remove after refactoring */ + ctxt->wellFormed = 0; + ctxt->disableSAX = 2; + + if (ctxt->errorHandler) { + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) && + (ctxt->sax->serror != NULL)) { + schannel = ctxt->sax->serror; + data = ctxt->userData; + } else { + channel = ctxt->sax->error; + data = ctxt->userData; } + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_PARSER, + &ctxt->lastError); } /** - * xmlErrInternal: - * @ctxt: an XML parser context - * @msg: the error message - * @str: error information + * xmlCtxtErrIO: + * @ctxt: parser context + * @code: xmlParserErrors code + * @uri: filename or URI (optional) + * + * If filename is empty, use the one from context input if available. * - * Handle an internal error + * Report an IO error to the parser context. + */ +void +xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri) +{ + const char *errstr, *msg, *str1, *str2; + xmlErrorLevel level; + + if (ctxt == NULL) + return; + + /* + * Only report a warning if a file could not be found. This should + * only be done for external entities, but the external entity loader + * of xsltproc can try multiple paths and assumes that ENOENT doesn't + * raise an error and aborts parsing. + */ + if (((code == XML_IO_ENOENT) || + (code == XML_IO_NETWORK_ATTEMPT) || + (code == XML_IO_UNKNOWN))) { + if (ctxt->validate == 0) + level = XML_ERR_WARNING; + else + level = XML_ERR_ERROR; + } else { + level = XML_ERR_FATAL; + } + + errstr = xmlErrString(code); + + if (uri == NULL) { + msg = "%s\n"; + str1 = errstr; + str2 = NULL; + } else { + msg = "failed to load \"%s\": %s\n"; + str1 = uri; + str2 = errstr; + } + + xmlCtxtErr(ctxt, NULL, XML_FROM_IO, code, level, + (const xmlChar *) uri, NULL, NULL, 0, + msg, str1, str2); +} + +/** + * xmlCtxtVErr: + * @ctxt: a parser context + * @node: the current node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @msg: the message to display/transmit + * @ap: extra parameters for the message display + * + * Raise a parser error. */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlErrInternal(xmlParserCtxtPtr ctxt, const char *msg, const xmlChar * str) +void +xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, va_list ap) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + const char *file = NULL; + int line = 0; + int col = 0; + int res; + + if (code == XML_ERR_NO_MEMORY) { + xmlCtxtErrMemory(ctxt); + return; + } + + if (PARSER_STOPPED(ctxt)) return; - if (ctxt != NULL) - ctxt->errNo = XML_ERR_INTERNAL_ERROR; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_INTERNAL_ERROR, - XML_ERR_FATAL, NULL, 0, (const char *) str, NULL, NULL, - 0, 0, msg, str); - if (ctxt != NULL) { + + if (level == XML_ERR_WARNING) { + if (ctxt->nbWarnings >= XML_MAX_ERRORS) + goto done; + ctxt->nbWarnings += 1; + } else { + /* Report at least one fatal error. */ + if ((ctxt->nbErrors >= XML_MAX_ERRORS) && + ((level < XML_ERR_FATAL) || (ctxt->wellFormed == 0))) + goto done; + ctxt->nbErrors += 1; + } + + if (((ctxt->options & XML_PARSE_NOERROR) == 0) && + ((level != XML_ERR_WARNING) || + ((ctxt->options & XML_PARSE_NOWARNING) == 0))) { + if (ctxt->errorHandler) { + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) && + (ctxt->sax->serror != NULL)) { + schannel = ctxt->sax->serror; + data = ctxt->userData; + } else if ((domain == XML_FROM_VALID) || (domain == XML_FROM_DTD)) { + if (level == XML_ERR_WARNING) + channel = ctxt->vctxt.warning; + else + channel = ctxt->vctxt.error; + data = ctxt->vctxt.userData; + } else { + if (level == XML_ERR_WARNING) + channel = ctxt->sax->warning; + else + channel = ctxt->sax->error; + data = ctxt->userData; + } + } + + if (ctxt->input != NULL) { + xmlParserInputPtr input = ctxt->input; + + if ((input->filename == NULL) && + (ctxt->inputNr > 1)) { + input = ctxt->inputTab[ctxt->inputNr - 2]; + } + file = input->filename; + line = input->line; + col = input->col; + } + + res = xmlVRaiseError(schannel, channel, data, ctxt, node, domain, code, + level, file, line, (const char *) str1, + (const char *) str2, (const char *) str3, int1, col, + msg, ap); + + if (res < 0) { + xmlCtxtErrMemory(ctxt); + return; + } + +done: + if (level >= XML_ERR_ERROR) + ctxt->errNo = code; + if (level == XML_ERR_FATAL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; } + + return; +} + +/** + * xmlCtxtErr: + * @ctxt: a parser context + * @node: the current node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Raise a parser error. + */ +void +xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + xmlCtxtVErr(ctxt, node, domain, code, level, + str1, str2, str3, int1, msg, ap); + va_end(ap); } /** - * xmlErrEncodingInt: + * xmlFatalErr: * @ctxt: an XML parser context - * @error: the error number - * @msg: the error message - * @val: an integer value + * @code: the error number + * @info: extra information string * - * n encoding error + * Handle a fatal parser error, i.e. violating Well-Formedness constraints */ -static void LIBXML_ATTR_FORMAT(3,0) -xmlErrEncodingInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, - const char *msg, int val) +void +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors code, const char *info) { - 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; + const char *errmsg; + + errmsg = xmlErrString(code); + + if (info == NULL) { + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, XML_ERR_FATAL, + NULL, NULL, NULL, 0, "%s\n", errmsg); + } else { + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, XML_ERR_FATAL, + (const xmlChar *) info, NULL, NULL, 0, + "%s: %s\n", errmsg, info); } } @@ -220,47 +397,30 @@ xmlIsLetter(int c) { * * ************************************************************************/ -/* #define DEBUG_INPUT */ -/* #define DEBUG_STACK */ -/* #define DEBUG_PUSH */ - - /* we need to keep enough input to show errors in context */ #define LINE_LEN 80 -#ifdef DEBUG_INPUT -#define CHECK_BUFFER(in) check_buffer(in) - -static -void check_buffer(xmlParserInputPtr in) { - if (in->base != xmlBufContent(in->buf->buffer)) { - xmlGenericError(xmlGenericErrorContext, - "xmlParserInput: base mismatch problem\n"); - } - if (in->cur < in->base) { - xmlGenericError(xmlGenericErrorContext, - "xmlParserInput: cur < base problem\n"); - } - if (in->cur > in->base + xmlBufUse(in->buf->buffer)) { - xmlGenericError(xmlGenericErrorContext, - "xmlParserInput: cur > base + use problem\n"); - } - xmlGenericError(xmlGenericErrorContext,"buffer %x : content %x, cur %d, use %d\n", - (int) in, (int) xmlBufContent(in->buf->buffer), in->cur - in->base, - xmlBufUse(in->buf->buffer)); +/** + * xmlHaltParser: + * @ctxt: an XML parser context + * + * Blocks further parser processing don't override error + * for internal use + */ +void +xmlHaltParser(xmlParserCtxtPtr ctxt) { + if (ctxt == NULL) + return; + ctxt->instate = XML_PARSER_EOF; /* TODO: Remove after refactoring */ + ctxt->disableSAX = 2; } -#else -#define CHECK_BUFFER(in) -#endif - - /** * xmlParserInputRead: * @in: an XML parser input * @len: an indicative size for the lookahead * - * This function was internal and is deprecated. + * DEPRECATED: This function was internal and is deprecated. * * Returns -1 as this is an error to use it. */ @@ -269,11 +429,63 @@ xmlParserInputRead(xmlParserInputPtr in ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUS return(-1); } +/** + * xmlParserGrow: + * @ctxt: an XML parser context + * + * Grow the input buffer. + * + * Returns the number of bytes read or -1 in case of error. + */ +int +xmlParserGrow(xmlParserCtxtPtr ctxt) { + xmlParserInputPtr in = ctxt->input; + xmlParserInputBufferPtr buf = in->buf; + size_t curEnd = in->end - in->cur; + size_t curBase = in->cur - in->base; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_LOOKUP_LIMIT; + int ret; + + if (buf == NULL) + return(0); + /* Don't grow push parser buffer. */ + if (PARSER_PROGRESSIVE(ctxt)) + return(0); + /* Don't grow memory buffers. */ + if ((buf->encoder == NULL) && (buf->readcallback == NULL)) + return(0); + if (buf->error != 0) + return(-1); + + if (curBase > maxLength) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Buffer size limit exceeded, try XML_PARSE_HUGE\n"); + xmlHaltParser(ctxt); + return(-1); + } + + if (curEnd >= INPUT_CHUNK) + return(0); + + ret = xmlParserInputBufferGrow(buf, INPUT_CHUNK); + xmlBufUpdateInput(buf->buffer, in, curBase); + + if (ret < 0) { + xmlCtxtErrIO(ctxt, buf->error, NULL); + } + + return(ret); +} + /** * xmlParserInputGrow: * @in: an XML parser input * @len: an indicative size for the lookahead * + * DEPRECATED: Don't use. + * * This function increase the input for the parser. It tries to * preserve pointers to the input buffer, and keep already read data * @@ -286,41 +498,81 @@ xmlParserInputGrow(xmlParserInputPtr in, int len) { size_t indx; if ((in == NULL) || (len < 0)) return(-1); -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, "Grow\n"); -#endif if (in->buf == NULL) return(-1); if (in->base == NULL) return(-1); if (in->cur == NULL) return(-1); if (in->buf->buffer == NULL) return(-1); - CHECK_BUFFER(in); + /* Don't grow memory buffers. */ + if ((in->buf->encoder == NULL) && (in->buf->readcallback == NULL)) + return(0); indx = in->cur - in->base; if (xmlBufUse(in->buf->buffer) > (unsigned int) indx + INPUT_CHUNK) { - - CHECK_BUFFER(in); - return(0); } - if (in->buf->readcallback != NULL) { - ret = xmlParserInputBufferGrow(in->buf, len); - } else - return(0); + ret = xmlParserInputBufferGrow(in->buf, len); in->base = xmlBufContent(in->buf->buffer); + if (in->base == NULL) { + in->base = BAD_CAST ""; + in->cur = in->base; + in->end = in->base; + return(-1); + } in->cur = in->base + indx; in->end = xmlBufEnd(in->buf->buffer); - CHECK_BUFFER(in); - return(ret); } +/** + * xmlParserShrink: + * @ctxt: an XML parser context + * + * Shrink the input buffer. + */ +void +xmlParserShrink(xmlParserCtxtPtr ctxt) { + xmlParserInputPtr in = ctxt->input; + xmlParserInputBufferPtr buf = in->buf; + size_t used; + + if (buf == NULL) + return; + /* Don't shrink pull parser memory buffers. */ + if ((!PARSER_PROGRESSIVE(ctxt)) && + (buf->encoder == NULL) && + (buf->readcallback == NULL)) + return; + + used = in->cur - in->base; + /* + * Do not shrink on large buffers whose only a tiny fraction + * was consumed + */ + if (used > INPUT_CHUNK) { + size_t res = xmlBufShrink(buf->buffer, used - LINE_LEN); + + if (res > 0) { + used -= res; + if ((res > ULONG_MAX) || + (in->consumed > ULONG_MAX - (unsigned long)res)) + in->consumed = ULONG_MAX; + else + in->consumed += res; + } + } + + xmlBufUpdateInput(buf->buffer, in, used); +} + /** * xmlParserInputShrink: * @in: an XML parser input * + * DEPRECATED: Don't use. + * * This function removes used input for the parser. */ void @@ -328,17 +580,12 @@ xmlParserInputShrink(xmlParserInputPtr in) { size_t used; size_t ret; -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, "Shrink\n"); -#endif if (in == NULL) return; if (in->buf == NULL) return; if (in->base == NULL) return; if (in->cur == NULL) return; if (in->buf->buffer == NULL) return; - CHECK_BUFFER(in); - used = in->cur - in->base; /* * Do not shrink on large buffers whose only a tiny fraction @@ -348,7 +595,11 @@ xmlParserInputShrink(xmlParserInputPtr in) { ret = xmlBufShrink(in->buf->buffer, used - LINE_LEN); if (ret > 0) { used -= ret; - in->consumed += ret; + if ((ret > ULONG_MAX) || + (in->consumed > ULONG_MAX - (unsigned long)ret)) + in->consumed = ULONG_MAX; + else + in->consumed += ret; } } @@ -357,10 +608,15 @@ xmlParserInputShrink(xmlParserInputPtr in) { } in->base = xmlBufContent(in->buf->buffer); + if (in->base == NULL) { + /* TODO: raise error */ + in->base = BAD_CAST ""; + in->cur = in->base; + in->end = in->base; + return; + } in->cur = in->base + used; in->end = xmlBufEnd(in->buf->buffer); - - CHECK_BUFFER(in); } /************************************************************************ @@ -373,149 +629,95 @@ xmlParserInputShrink(xmlParserInputPtr in) { * xmlNextChar: * @ctxt: the XML parser context * + * DEPRECATED: Internal function, do not use. + * * Skip to the next char input char. */ void xmlNextChar(xmlParserCtxtPtr ctxt) { - if ((ctxt == NULL) || (ctxt->instate == XML_PARSER_EOF) || - (ctxt->input == NULL)) + const unsigned char *cur; + size_t avail; + int c; + + if ((ctxt == NULL) || (ctxt->input == NULL)) return; - if (!(VALID_CTXT(ctxt))) { - xmlErrInternal(ctxt, "Parser input data memory error\n", NULL); - ctxt->errNo = XML_ERR_INTERNAL_ERROR; - xmlStopParser(ctxt); - return; - } + avail = ctxt->input->end - ctxt->input->cur; - if ((*ctxt->input->cur == 0) && - (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) { - return; + if (avail < INPUT_CHUNK) { + xmlParserGrow(ctxt); + if (ctxt->input->cur >= ctxt->input->end) + return; + avail = ctxt->input->end - ctxt->input->cur; } - if (ctxt->charset == XML_CHAR_ENCODING_UTF8) { - const unsigned char *cur; - unsigned char c; + cur = ctxt->input->cur; + c = *cur; - /* - * 2.11 End-of-Line Handling - * the literal two-character sequence "#xD#xA" or a standalone - * literal #xD, an XML processor must pass to the application - * the single character #xA. - */ - if (*(ctxt->input->cur) == '\n') { - ctxt->input->line++; ctxt->input->col = 1; - } else + if (c < 0x80) { + if (c == '\n') { + ctxt->input->cur++; + ctxt->input->line++; + ctxt->input->col = 1; + } else if (c == '\r') { + /* + * 2.11 End-of-Line Handling + * the literal two-character sequence "#xD#xA" or a standalone + * literal #xD, an XML processor must pass to the application + * the single character #xA. + */ + ctxt->input->cur += ((cur[1] == '\n') ? 2 : 1); + ctxt->input->line++; + ctxt->input->col = 1; + return; + } else { + ctxt->input->cur++; ctxt->input->col++; + } + } else { + ctxt->input->col++; - /* - * 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 - */ - cur = ctxt->input->cur; - - c = *cur; - if (c & 0x80) { - if (c == 0xC0) - goto encoding_error; - if (cur[1] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if ((cur[1] & 0xc0) != 0x80) + if ((avail < 2) || (cur[1] & 0xc0) != 0x80) + goto encoding_error; + + if (c < 0xe0) { + /* 2-byte code */ + if (c < 0xc2) goto encoding_error; - if ((c & 0xe0) == 0xe0) { - unsigned int val; + ctxt->input->cur += 2; + } else { + unsigned int val = (c << 8) | cur[1]; - if (cur[2] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if ((cur[2] & 0xc0) != 0x80) + if ((avail < 3) || (cur[2] & 0xc0) != 0x80) + goto encoding_error; + + if (c < 0xf0) { + /* 3-byte code */ + if ((val < 0xe0a0) || ((val >= 0xeda0) && (val < 0xee00))) + goto encoding_error; + ctxt->input->cur += 3; + } else { + if ((avail < 4) || ((cur[3] & 0xc0) != 0x80)) goto encoding_error; - if ((c & 0xf0) == 0xf0) { - if (cur[3] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if (((c & 0xf8) != 0xf0) || - ((cur[3] & 0xc0) != 0x80)) - goto encoding_error; - /* 4-byte code */ - ctxt->input->cur += 4; - val = (cur[0] & 0x7) << 18; - val |= (cur[1] & 0x3f) << 12; - val |= (cur[2] & 0x3f) << 6; - val |= cur[3] & 0x3f; - } else { - /* 3-byte code */ - ctxt->input->cur += 3; - val = (cur[0] & 0xf) << 12; - val |= (cur[1] & 0x3f) << 6; - val |= cur[2] & 0x3f; - } - if (((val > 0xd7ff) && (val < 0xe000)) || - ((val > 0xfffd) && (val < 0x10000)) || - (val >= 0x110000)) { - xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", - val); - } - } else - /* 2-byte code */ - ctxt->input->cur += 2; - } else - /* 1-byte code */ - ctxt->input->cur++; - } else { - /* - * Assume it's a fixed length encoding (1) with - * a compatible encoding for the ASCII set, since - * XML constructs only use < 128 chars - */ - if (*(ctxt->input->cur) == '\n') { - ctxt->input->line++; ctxt->input->col = 1; - } else - ctxt->input->col++; - ctxt->input->cur++; + /* 4-byte code */ + if ((val < 0xf090) || (val >= 0xf490)) + goto encoding_error; + ctxt->input->cur += 4; + } + } } - if (*ctxt->input->cur == 0) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + return; -encoding_error: - /* - * If we detect an UTF8 error that probably mean 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 !) - */ - if ((ctxt == NULL) || (ctxt->input == NULL) || - (ctxt->input->end - ctxt->input->cur < 4)) { - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n", - NULL, NULL); - } else { - char buffer[150]; - snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - ctxt->input->cur[0], ctxt->input->cur[1], - ctxt->input->cur[2], ctxt->input->cur[3]); - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n%s", - BAD_CAST buffer, NULL); +encoding_error: + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; } - ctxt->charset = XML_CHAR_ENCODING_8859_1; ctxt->input->cur++; return; } @@ -525,6 +727,8 @@ encoding_error: * @ctxt: the XML parser context * @len: pointer to the length of the char read * + * DEPRECATED: Internal function, do not use. + * * The current char value, if using UTF-8 this may actually span multiple * bytes in the input buffer. Implement the end of line normalization: * 2.11 End-of-Line Handling @@ -540,260 +744,157 @@ encoding_error: int xmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { + const unsigned char *cur; + size_t avail; + int c; + if ((ctxt == NULL) || (len == NULL) || (ctxt->input == NULL)) return(0); - if (ctxt->instate == XML_PARSER_EOF) - return(0); - if ((*ctxt->input->cur >= 0x20) && (*ctxt->input->cur <= 0x7F)) { - *len = 1; - return((int) *ctxt->input->cur); + avail = ctxt->input->end - ctxt->input->cur; + + if (avail < INPUT_CHUNK) { + xmlParserGrow(ctxt); + avail = ctxt->input->end - ctxt->input->cur; } - if (ctxt->charset == XML_CHAR_ENCODING_UTF8) { - /* - * 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 - */ - const unsigned char *cur = ctxt->input->cur; - unsigned char c; - unsigned int val; - - c = *cur; - if (c & 0x80) { - if (((c & 0x40) == 0) || (c == 0xC0)) - goto encoding_error; - if (cur[1] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - if ((cur[1] & 0xc0) != 0x80) - goto encoding_error; - if ((c & 0xe0) == 0xe0) { - if (cur[2] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; + + cur = ctxt->input->cur; + c = *cur; + + if (c < 0x80) { + /* 1-byte code */ + if (c < 0x20) { + /* + * 2.11 End-of-Line Handling + * the literal two-character sequence "#xD#xA" or a standalone + * literal #xD, an XML processor must pass to the application + * the single character #xA. + */ + if (c == '\r') { + /* + * TODO: This function shouldn't change the 'cur' pointer + * as side effect, but the NEXTL macro in parser.c relies + * on this behavior when incrementing line numbers. + */ + if (cur[1] == '\n') + ctxt->input->cur++; + *len = 1; + c = '\n'; + } else if (c == 0) { + if (ctxt->input->cur >= ctxt->input->end) { + *len = 0; + } else { + *len = 1; + /* + * TODO: Null bytes should be handled by callers, + * but this can be tricky. + */ + xmlFatalErr(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x0 out of allowed range\n"); } - if ((cur[2] & 0xc0) != 0x80) - goto encoding_error; - if ((c & 0xf0) == 0xf0) { - if (cur[3] == 0) { - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - cur = ctxt->input->cur; - } - 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; - if (val < 0x10000) - goto encoding_error; - } else { - /* 3-byte code */ - *len = 3; - val = (cur[0] & 0xf) << 12; - val |= (cur[1] & 0x3f) << 6; - val |= cur[2] & 0x3f; - if (val < 0x800) - goto encoding_error; - } - } else { - /* 2-byte code */ - *len = 2; - val = (cur[0] & 0x1f) << 6; - val |= cur[1] & 0x3f; - if (val < 0x80) - goto encoding_error; - } - if (!IS_CHAR(val)) { - xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", val); - } - return(val); - } else { - /* 1-byte code */ - *len = 1; - if (*ctxt->input->cur == 0) - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); - if ((*ctxt->input->cur == 0) && - (ctxt->input->end > ctxt->input->cur)) { - xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x0 out of allowed range\n", 0); - } - if (*ctxt->input->cur == 0xD) { - if (ctxt->input->cur[1] == 0xA) { - ctxt->input->cur++; - } - return(0xA); - } - return((int) *ctxt->input->cur); - } - } - /* - * Assume it's a fixed length encoding (1) with - * a compatible encoding for the ASCII set, since - * XML constructs only use < 128 chars - */ - *len = 1; - if (*ctxt->input->cur == 0xD) { - if (ctxt->input->cur[1] == 0xA) { - ctxt->input->cur++; - } - return(0xA); - } - return((int) *ctxt->input->cur); -encoding_error: - /* - * An encoding problem may arise from a truncated input buffer - * splitting a character in the middle. In that case do not raise - * an error but return 0 to indicate an end of stream problem - */ - if (ctxt->input->end - ctxt->input->cur < 4) { - *len = 0; - return(0); - } + } else { + *len = 1; + } + } else { + *len = 1; + } - /* - * If we detect an UTF8 error that probably mean 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 !) - */ - { - char buffer[150]; + return(c); + } else { + int val; - snprintf(&buffer[0], 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - ctxt->input->cur[0], ctxt->input->cur[1], - ctxt->input->cur[2], ctxt->input->cur[3]); - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n%s", - BAD_CAST buffer, NULL); - } - ctxt->charset = XML_CHAR_ENCODING_8859_1; - *len = 1; - return((int) *ctxt->input->cur); -} + if (avail < 2) + goto incomplete_sequence; + if ((cur[1] & 0xc0) != 0x80) + goto encoding_error; -/** - * xmlStringCurrentChar: - * @ctxt: the XML 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 - */ - -int -xmlStringCurrentChar(xmlParserCtxtPtr ctxt, const xmlChar * cur, int *len) -{ - if ((len == NULL) || (cur == NULL)) return(0); - if ((ctxt == NULL) || (ctxt->charset == XML_CHAR_ENCODING_UTF8)) { - /* - * 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 - */ - unsigned char c; - unsigned int val; - - c = *cur; - if (c & 0x80) { - if ((cur[1] & 0xc0) != 0x80) + if (c < 0xe0) { + /* 2-byte code */ + if (c < 0xc2) + goto encoding_error; + val = (c & 0x1f) << 6; + val |= cur[1] & 0x3f; + *len = 2; + } else { + if (avail < 3) + goto incomplete_sequence; + if ((cur[2] & 0xc0) != 0x80) goto encoding_error; - if ((c & 0xe0) == 0xe0) { - if ((cur[2] & 0xc0) != 0x80) + if (c < 0xf0) { + /* 3-byte code */ + val = (c & 0xf) << 12; + val |= (cur[1] & 0x3f) << 6; + val |= cur[2] & 0x3f; + if ((val < 0x800) || ((val >= 0xd800) && (val < 0xe000))) 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; - } + *len = 3; } else { - /* 2-byte code */ - *len = 2; - val = (cur[0] & 0x1f) << 6; - val |= cur[1] & 0x3f; - } - if (!IS_CHAR(val)) { - xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", val); + if (avail < 4) + goto incomplete_sequence; + if ((cur[3] & 0xc0) != 0x80) + goto encoding_error; + + /* 4-byte code */ + val = (c & 0x0f) << 18; + val |= (cur[1] & 0x3f) << 12; + val |= (cur[2] & 0x3f) << 6; + val |= cur[3] & 0x3f; + if ((val < 0x10000) || (val >= 0x110000)) + goto encoding_error; + *len = 4; } - return (val); - } else { - /* 1-byte code */ - *len = 1; - return ((int) *cur); } + + return(val); } - /* - * Assume it's a fixed length encoding (1) with - * a compatible encoding for the ASCII set, since - * XML constructs only use < 128 chars - */ - *len = 1; - return ((int) *cur); + encoding_error: + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; + } + *len = 1; + return(0xFFFD); /* U+FFFD Replacement Character */ +incomplete_sequence: /* * An encoding problem may arise from a truncated input buffer * splitting a character in the middle. In that case do not raise - * an error but return 0 to indicate an end of stream problem + * an error but return 0. This should only happen when push parsing + * char data. */ - if ((ctxt == NULL) || (ctxt->input == NULL) || - (ctxt->input->end - ctxt->input->cur < 4)) { - *len = 0; - return(0); - } - /* - * If we detect an UTF8 error that probably mean 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 !) - */ - { - char buffer[150]; + *len = 0; + return(0); +} - snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", - ctxt->input->cur[0], ctxt->input->cur[1], - ctxt->input->cur[2], ctxt->input->cur[3]); - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n%s", - BAD_CAST buffer, NULL); - } - *len = 1; - return ((int) *cur); +/** + * xmlStringCurrentChar: + * @ctxt: the XML parser context + * @cur: pointer to the beginning of the char + * @len: pointer to the length of the char read + * + * DEPRECATED: Internal function, do not use. + * + * 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 + */ + +int +xmlStringCurrentChar(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *cur, int *len) { + int c; + + if ((cur == NULL) || (len == NULL)) + return(0); + + /* cur is zero-terminated, so we can lie about its length. */ + *len = 4; + c = xmlGetUTF8Char(cur, len); + + return((c < 0) ? 0 : c); } /** @@ -807,7 +908,7 @@ encoding_error: */ int xmlCopyCharMultiByte(xmlChar *out, int val) { - if (out == NULL) return(0); + if ((out == NULL) || (val < 0)) return(0); /* * We are supposed to handle UTF8, check it's valid * From rfc2044: encoding of the Unicode values on UTF-8: @@ -824,16 +925,17 @@ xmlCopyCharMultiByte(xmlChar *out, int val) { else if (val < 0x10000) { *out++= (val >> 12) | 0xE0; bits= 6;} else if (val < 0x110000) { *out++= (val >> 18) | 0xF0; bits= 12; } else { - xmlErrEncodingInt(NULL, XML_ERR_INVALID_CHAR, - "Internal error, xmlCopyCharMultiByte 0x%X out of bound\n", - val); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + fprintf(stderr, "xmlCopyCharMultiByte: codepoint out of range\n"); + abort(); +#endif return(0); } for ( ; bits >= 0; bits-= 6) *out++= ((val >> bits) & 0x3F) | 0x80 ; return (out - savedout); } - *out = (xmlChar) val; + *out = val; return 1; } @@ -850,12 +952,12 @@ xmlCopyCharMultiByte(xmlChar *out, int val) { int xmlCopyChar(int len ATTRIBUTE_UNUSED, xmlChar *out, int val) { - if (out == NULL) return(0); + if ((out == NULL) || (val < 0)) return(0); /* the len parameter is ignored */ if (val >= 0x80) { return(xmlCopyCharMultiByte (out, val)); } - *out = (xmlChar) val; + *out = val; return 1; } @@ -866,314 +968,521 @@ xmlCopyChar(int len ATTRIBUTE_UNUSED, xmlChar *out, int val) { ************************************************************************/ static int -xmlSwitchInputEncodingInt(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, - xmlCharEncodingHandlerPtr handler, int len); +xmlDetectEBCDIC(xmlParserInputPtr input, xmlCharEncodingHandlerPtr *hout) { + xmlChar out[200]; + xmlCharEncodingHandlerPtr handler; + int inlen, outlen, res, i; + + *hout = NULL; + + /* + * To detect the EBCDIC code page, we convert the first 200 bytes + * to EBCDIC-US and try to find the encoding declaration. + */ + res = xmlLookupCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC, &handler); + if (res != 0) + return(res); + outlen = sizeof(out) - 1; + inlen = input->end - input->cur; + res = xmlEncInputChunk(handler, out, &outlen, input->cur, &inlen); + /* + * Return the EBCDIC handler if decoding failed. The error will + * be reported later. + */ + if (res < 0) + goto done; + out[outlen] = 0; + + for (i = 0; i < outlen; i++) { + if (out[i] == '>') + break; + if ((out[i] == 'e') && + (xmlStrncmp(out + i, BAD_CAST "encoding", 8) == 0)) { + int start, cur, quote; + + i += 8; + while (IS_BLANK_CH(out[i])) + i += 1; + if (out[i++] != '=') + break; + while (IS_BLANK_CH(out[i])) + i += 1; + quote = out[i++]; + if ((quote != '\'') && (quote != '"')) + break; + start = i; + cur = out[i]; + while (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z')) || + ((cur >= '0') && (cur <= '9')) || + (cur == '.') || (cur == '_') || + (cur == '-')) + cur = out[++i]; + if (cur != quote) + break; + out[i] = 0; + xmlCharEncCloseFunc(handler); + res = xmlOpenCharEncodingHandler((char *) out + start, + /* output */ 0, &handler); + if (res != 0) + return(res); + *hout = handler; + return(0); + } + } + +done: + /* + * Encoding handlers are stateful, so we have to recreate them. + */ + xmlCharEncCloseFunc(handler); + res = xmlLookupCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC, &handler); + if (res != 0) + return(res); + *hout = handler; + return(0); +} + /** * xmlSwitchEncoding: * @ctxt: the parser context * @enc: the encoding value (number) * - * change the input functions when discovering the character encoding - * of a given entity. + * Use encoding specified by enum to decode input data. This overrides + * the encoding found in the XML declaration. + * + * This function can also be used to override the encoding of chunks + * passed to xmlParseChunk. * * Returns 0 in case of success, -1 otherwise */ int xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc) { - xmlCharEncodingHandlerPtr handler; - int len = -1; + xmlCharEncodingHandlerPtr handler = NULL; int ret; + int res; + + if ((ctxt == NULL) || (ctxt->input == NULL)) + return(-1); - if (ctxt == NULL) return(-1); switch (enc) { - case XML_CHAR_ENCODING_ERROR: - __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, - "encoding unknown\n", NULL, NULL); - return(-1); case XML_CHAR_ENCODING_NONE: - /* let's assume it's UTF-8 without the XML decl */ - ctxt->charset = XML_CHAR_ENCODING_UTF8; - return(0); case XML_CHAR_ENCODING_UTF8: - /* default encoding, no conversion should be needed */ - ctxt->charset = XML_CHAR_ENCODING_UTF8; - - /* - * Errata on XML-1.0 June 20 2001 - * Specific handling of the Byte Order Mark for - * UTF-8 - */ - if ((ctxt->input != NULL) && - (ctxt->input->cur[0] == 0xEF) && - (ctxt->input->cur[1] == 0xBB) && - (ctxt->input->cur[2] == 0xBF)) { - ctxt->input->cur += 3; - } - return(0); - case XML_CHAR_ENCODING_UTF16LE: - case XML_CHAR_ENCODING_UTF16BE: - /*The raw input characters are encoded - *in UTF-16. As we expect this function - *to be called after xmlCharEncInFunc, we expect - *ctxt->input->cur to contain UTF-8 encoded characters. - *So the raw UTF16 Byte Order Mark - *has also been converted into - *an UTF-8 BOM. Let's skip that BOM. - */ - if ((ctxt->input != NULL) && (ctxt->input->cur != NULL) && - (ctxt->input->cur[0] == 0xEF) && - (ctxt->input->cur[1] == 0xBB) && - (ctxt->input->cur[2] == 0xBF)) { - ctxt->input->cur += 3; - } - len = 90; - break; - case XML_CHAR_ENCODING_UCS2: - len = 90; - break; - case XML_CHAR_ENCODING_UCS4BE: - case XML_CHAR_ENCODING_UCS4LE: - case XML_CHAR_ENCODING_UCS4_2143: - case XML_CHAR_ENCODING_UCS4_3412: - len = 180; - break; - case XML_CHAR_ENCODING_EBCDIC: - case XML_CHAR_ENCODING_8859_1: - case XML_CHAR_ENCODING_8859_2: - case XML_CHAR_ENCODING_8859_3: - case XML_CHAR_ENCODING_8859_4: - case XML_CHAR_ENCODING_8859_5: - case XML_CHAR_ENCODING_8859_6: - case XML_CHAR_ENCODING_8859_7: - case XML_CHAR_ENCODING_8859_8: - case XML_CHAR_ENCODING_8859_9: - case XML_CHAR_ENCODING_ASCII: - case XML_CHAR_ENCODING_2022_JP: - case XML_CHAR_ENCODING_SHIFT_JIS: - case XML_CHAR_ENCODING_EUC_JP: - len = 45; - break; - } - handler = xmlGetCharEncodingHandler(enc); - if (handler == NULL) { - /* - * Default handlers. - */ - switch (enc) { - case XML_CHAR_ENCODING_ASCII: - /* default encoding, no conversion should be needed */ - ctxt->charset = XML_CHAR_ENCODING_UTF8; - return(0); - case XML_CHAR_ENCODING_8859_1: - if ((ctxt->inputNr == 1) && - (ctxt->encoding == NULL) && - (ctxt->input != NULL) && - (ctxt->input->encoding != NULL)) { - ctxt->encoding = xmlStrdup(ctxt->input->encoding); - } - ctxt->charset = enc; - return(0); - default: - __xmlErrEncoding(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "encoding not supported: %s\n", - BAD_CAST xmlGetCharEncodingName(enc), NULL); - /* - * TODO: We could recover from errors in external entities - * if we didn't stop the parser. But most callers of this - * function don't check the return value. - */ - xmlStopParser(ctxt); - return(-1); - } + case XML_CHAR_ENCODING_ASCII: + res = 0; + break; + case XML_CHAR_ENCODING_EBCDIC: + res = xmlDetectEBCDIC(ctxt->input, &handler); + break; + default: + res = xmlLookupCharEncodingHandler(enc, &handler); + break; } - ret = xmlSwitchInputEncodingInt(ctxt, ctxt->input, handler, len); - if ((ret < 0) || (ctxt->errNo == XML_I18N_CONV_FAILED)) { - /* - * on encoding conversion errors, stop the parser - */ - xmlStopParser(ctxt); - ctxt->errNo = XML_I18N_CONV_FAILED; + + if (res != 0) { + const char *name = xmlGetCharEncodingName(enc); + + xmlFatalErr(ctxt, res, (name ? name : "")); + return(-1); + } + + ret = xmlSwitchInputEncoding(ctxt, ctxt->input, handler); + + if ((ret >= 0) && (enc == XML_CHAR_ENCODING_NONE)) { + ctxt->input->flags &= ~XML_INPUT_HAS_ENCODING; } + return(ret); } /** - * xmlSwitchInputEncodingInt: + * xmlSwitchEncodingName: + * @ctxt: the parser context, only for error reporting + * @input: the input strea, + * @encoding: the encoding name + * + * Available since 2.13.0. + * + * Returns 0 in case of success, -1 otherwise + */ +static int +xmlSwitchInputEncodingName(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, + const char *encoding) { + xmlCharEncodingHandlerPtr handler; + int res; + + if (encoding == NULL) + return(-1); + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 0, &handler); + if (res == XML_ERR_UNSUPPORTED_ENCODING) { + xmlWarningMsg(ctxt, XML_ERR_UNSUPPORTED_ENCODING, + "Unsupported encoding: %s\n", BAD_CAST encoding, NULL); + return(-1); + } else if (res != XML_ERR_OK) { + xmlFatalErr(ctxt, res, encoding); + return(-1); + } + + return(xmlSwitchInputEncoding(ctxt, input, handler)); +} + +/** + * xmlSwitchEncodingName: * @ctxt: the parser context + * @encoding: the encoding name + * + * Use specified encoding to decode input data. This overrides the + * encoding found in the XML declaration. + * + * This function can also be used to override the encoding of chunks + * passed to xmlParseChunk. + * + * Available since 2.13.0. + * + * Returns 0 in case of success, -1 otherwise + */ +int +xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding) { + if (ctxt == NULL) + return(-1); + + return(xmlSwitchInputEncodingName(ctxt, ctxt->input, encoding)); +} + +/** + * xmlSwitchInputEncoding: + * @ctxt: the parser context, only for error reporting * @input: the input stream * @handler: the encoding handler - * @len: the number of bytes to convert for the first line or -1 * - * change the input functions when discovering the character encoding - * of a given entity. + * DEPRECATED: Internal function, don't use. + * + * Use encoding handler to decode input data. * * Returns 0 in case of success, -1 otherwise */ -static int -xmlSwitchInputEncodingInt(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, - xmlCharEncodingHandlerPtr handler, int len) +int +xmlSwitchInputEncoding(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, + xmlCharEncodingHandlerPtr handler) { int nbchars; + xmlParserInputBufferPtr in; - if (handler == NULL) - return (-1); - if (input == NULL) - return (-1); - if (input->buf != NULL) { - ctxt->charset = XML_CHAR_ENCODING_UTF8; + if ((input == NULL) || (input->buf == NULL)) { + xmlCharEncCloseFunc(handler); + return (-1); + } + in = input->buf; - if (input->buf->encoder != NULL) { - /* - * Check in case the auto encoding detection triggered - * in already. - */ - if (input->buf->encoder == handler) - return (0); + input->flags |= XML_INPUT_HAS_ENCODING; - /* - * "UTF-16" can be used for both LE and BE - if ((!xmlStrncmp(BAD_CAST input->buf->encoder->name, - BAD_CAST "UTF-16", 6)) && - (!xmlStrncmp(BAD_CAST handler->name, - BAD_CAST "UTF-16", 6))) { - return(0); - } - */ + /* + * UTF-8 requires no encoding handler. + */ + if ((handler != NULL) && + (xmlStrcasecmp(BAD_CAST handler->name, BAD_CAST "UTF-8") == 0)) { + xmlCharEncCloseFunc(handler); + handler = NULL; + } - /* - * Note: this is a bit dangerous, but that's what it - * takes to use nearly compatible signature for different - * encodings. - * - * FIXME: Encoders might buffer partial byte sequences, so - * this probably can't work. We should return an error and - * make sure that callers never try to switch the encoding - * twice. - */ - xmlCharEncCloseFunc(input->buf->encoder); - input->buf->encoder = handler; - return (0); - } - input->buf->encoder = handler; + if (in->encoder == handler) + return (0); + if (in->encoder != NULL) { /* - * Is there already some content down the pipe to convert ? + * Switching encodings during parsing is a really bad idea, + * but Chromium can switch between ISO-8859-1 and UTF-16 before + * separate calls to xmlParseChunk. + * + * TODO: We should check whether the "raw" input buffer is empty and + * convert the old content using the old encoder. */ - if (xmlBufIsEmpty(input->buf->buffer) == 0) { - int processed; - unsigned int use; - /* - * Specific handling of the Byte Order Mark for - * UTF-16 - */ - if ((handler->name != NULL) && - (!strcmp(handler->name, "UTF-16LE") || - !strcmp(handler->name, "UTF-16")) && - (input->cur[0] == 0xFF) && (input->cur[1] == 0xFE)) { - input->cur += 2; - } - if ((handler->name != NULL) && - (!strcmp(handler->name, "UTF-16BE")) && - (input->cur[0] == 0xFE) && (input->cur[1] == 0xFF)) { - input->cur += 2; - } - /* - * Errata on XML-1.0 June 20 2001 - * Specific handling of the Byte Order Mark for - * UTF-8 - */ - if ((handler->name != NULL) && - (!strcmp(handler->name, "UTF-8")) && - (input->cur[0] == 0xEF) && - (input->cur[1] == 0xBB) && (input->cur[2] == 0xBF)) { - input->cur += 3; - } + xmlCharEncCloseFunc(in->encoder); + in->encoder = handler; + return (0); + } - /* - * Shrink the current input buffer. - * Move it as the raw buffer and create a new input buffer - */ - processed = input->cur - input->base; - xmlBufShrink(input->buf->buffer, processed); - input->buf->raw = input->buf->buffer; - input->buf->buffer = xmlBufCreate(); - input->buf->rawconsumed = processed; - use = xmlBufUse(input->buf->raw); - - if (ctxt->html) { - /* - * convert as much as possible of the buffer - */ - nbchars = xmlCharEncInput(input->buf, 1); - } else { - /* - * convert just enough to get - * '' - * parsed with the autodetected encoding - * into the parser reading buffer. - */ - nbchars = xmlCharEncFirstLineInput(input->buf, len); - } - xmlBufResetInput(input->buf->buffer, input); - if (nbchars < 0) { - xmlErrInternal(ctxt, - "switching encoding: encoder error\n", - NULL); - return (-1); - } - input->buf->rawconsumed += use - xmlBufUse(input->buf->raw); + in->encoder = handler; + + /* + * Is there already some content down the pipe to convert ? + */ + if (xmlBufIsEmpty(in->buffer) == 0) { + xmlBufPtr buf; + size_t processed; + + buf = xmlBufCreate(); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(-1); } - return (0); - } else { - xmlErrInternal(ctxt, - "static memory buffer doesn't support encoding\n", NULL); + /* - * Callers assume that the input buffer takes ownership of the - * encoding handler. xmlCharEncCloseFunc frees unregistered - * handlers and avoids a memory leak. + * Shrink the current input buffer. + * Move it as the raw buffer and create a new input buffer */ - xmlCharEncCloseFunc(handler); - return (-1); + processed = input->cur - input->base; + xmlBufShrink(in->buffer, processed); + input->consumed += processed; + in->raw = in->buffer; + in->buffer = buf; + in->rawconsumed = processed; + + nbchars = xmlCharEncInput(in); + xmlBufResetInput(in->buffer, input); + if (nbchars == XML_ENC_ERR_MEMORY) { + xmlCtxtErrMemory(ctxt); + } else if (nbchars < 0) { + xmlCtxtErrIO(ctxt, in->error, NULL); + xmlHaltParser(ctxt); + return (-1); + } } + return (0); } /** - * xmlSwitchInputEncoding: + * xmlSwitchToEncoding: * @ctxt: the parser context - * @input: the input stream * @handler: the encoding handler * - * DEPRECATED: Use xmlSwitchToEncoding + * Use encoding handler to decode input data. * - * change the input functions when discovering the character encoding - * of a given entity. + * This function can be used to enforce the encoding of chunks passed + * to xmlParseChunk. * * Returns 0 in case of success, -1 otherwise */ int -xmlSwitchInputEncoding(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, - xmlCharEncodingHandlerPtr handler) { - return(xmlSwitchInputEncodingInt(ctxt, input, handler, -1)); +xmlSwitchToEncoding(xmlParserCtxtPtr ctxt, xmlCharEncodingHandlerPtr handler) +{ + if (ctxt == NULL) + return(-1); + return(xmlSwitchInputEncoding(ctxt, ctxt->input, handler)); } /** - * xmlSwitchToEncoding: + * xmlDetectEncoding: * @ctxt: the parser context - * @handler: the encoding handler * - * change the input functions when discovering the character encoding - * of a given entity. + * Handle optional BOM, detect and switch to encoding. * - * Returns 0 in case of success, -1 otherwise + * Assumes that there are at least four bytes in the input buffer. */ -int -xmlSwitchToEncoding(xmlParserCtxtPtr ctxt, xmlCharEncodingHandlerPtr handler) -{ - if (ctxt == NULL) - return(-1); - return(xmlSwitchInputEncodingInt(ctxt, ctxt->input, handler, -1)); +void +xmlDetectEncoding(xmlParserCtxtPtr ctxt) { + const xmlChar *in; + xmlCharEncoding enc; + int bomSize; + int autoFlag = 0; + + if (xmlParserGrow(ctxt) < 0) + return; + in = ctxt->input->cur; + if (ctxt->input->end - in < 4) + return; + + if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) { + /* + * If the encoding was already set, only skip the BOM which was + * possibly decoded to UTF-8. + */ + if ((in[0] == 0xEF) && (in[1] == 0xBB) && (in[2] == 0xBF)) { + ctxt->input->cur += 3; + } + + return; + } + + enc = XML_CHAR_ENCODING_NONE; + bomSize = 0; + + switch (in[0]) { + case 0x00: + if ((in[1] == 0x00) && (in[2] == 0x00) && (in[3] == 0x3C)) { + enc = XML_CHAR_ENCODING_UCS4BE; + autoFlag = XML_INPUT_AUTO_OTHER; + } else if ((in[1] == 0x3C) && (in[2] == 0x00) && (in[3] == 0x3F)) { + enc = XML_CHAR_ENCODING_UTF16BE; + autoFlag = XML_INPUT_AUTO_UTF16BE; + } + break; + + case 0x3C: + if (in[1] == 0x00) { + if ((in[2] == 0x00) && (in[3] == 0x00)) { + enc = XML_CHAR_ENCODING_UCS4LE; + autoFlag = XML_INPUT_AUTO_OTHER; + } else if ((in[2] == 0x3F) && (in[3] == 0x00)) { + enc = XML_CHAR_ENCODING_UTF16LE; + autoFlag = XML_INPUT_AUTO_UTF16LE; + } + } + break; + + case 0x4C: + if ((in[1] == 0x6F) && (in[2] == 0xA7) && (in[3] == 0x94)) { + enc = XML_CHAR_ENCODING_EBCDIC; + autoFlag = XML_INPUT_AUTO_OTHER; + } + break; + + case 0xEF: + if ((in[1] == 0xBB) && (in[2] == 0xBF)) { + enc = XML_CHAR_ENCODING_UTF8; + autoFlag = XML_INPUT_AUTO_UTF8; + bomSize = 3; + } + break; + + case 0xFE: + if (in[1] == 0xFF) { + enc = XML_CHAR_ENCODING_UTF16BE; + autoFlag = XML_INPUT_AUTO_UTF16BE; + bomSize = 2; + } + break; + + case 0xFF: + if (in[1] == 0xFE) { + enc = XML_CHAR_ENCODING_UTF16LE; + autoFlag = XML_INPUT_AUTO_UTF16LE; + bomSize = 2; + } + break; + } + + if (bomSize > 0) { + ctxt->input->cur += bomSize; + } + + if (enc != XML_CHAR_ENCODING_NONE) { + ctxt->input->flags |= autoFlag; + xmlSwitchEncoding(ctxt, enc); + } +} + +/** + * xmlSetDeclaredEncoding: + * @ctxt: the parser context + * @encoding: declared encoding + * + * Set the encoding from a declaration in the document. + * + * If no encoding was set yet, switch the encoding. Otherwise, only warn + * about encoding mismatches. + * + * Takes ownership of 'encoding'. + */ +void +xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding) { + if (((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) && + ((ctxt->options & XML_PARSE_IGNORE_ENC) == 0)) { + xmlCharEncodingHandlerPtr handler; + int res; + + /* + * xmlSwitchInputEncodingName treats unsupported encodings as + * warnings, but we want it to be an error in an encoding + * declaration. + */ + res = xmlOpenCharEncodingHandler((const char *) encoding, + /* output */ 0, &handler); + if (res != XML_ERR_OK) { + xmlFatalErr(ctxt, res, (const char *) encoding); + xmlFree(encoding); + return; + } + + res = xmlSwitchInputEncoding(ctxt, ctxt->input, handler); + if (res != XML_ERR_OK) { + xmlFree(encoding); + return; + } + + ctxt->input->flags |= XML_INPUT_USES_ENC_DECL; + } else if (ctxt->input->flags & XML_INPUT_AUTO_ENCODING) { + static const char *allowedUTF8[] = { + "UTF-8", "UTF8", NULL + }; + static const char *allowedUTF16LE[] = { + "UTF-16", "UTF-16LE", "UTF16", NULL + }; + static const char *allowedUTF16BE[] = { + "UTF-16", "UTF-16BE", "UTF16", NULL + }; + const char **allowed = NULL; + const char *autoEnc = NULL; + + switch (ctxt->input->flags & XML_INPUT_AUTO_ENCODING) { + case XML_INPUT_AUTO_UTF8: + allowed = allowedUTF8; + autoEnc = "UTF-8"; + break; + case XML_INPUT_AUTO_UTF16LE: + allowed = allowedUTF16LE; + autoEnc = "UTF-16LE"; + break; + case XML_INPUT_AUTO_UTF16BE: + allowed = allowedUTF16BE; + autoEnc = "UTF-16BE"; + break; + } + + if (allowed != NULL) { + const char **p; + int match = 0; + + for (p = allowed; *p != NULL; p++) { + if (xmlStrcasecmp(encoding, BAD_CAST *p) == 0) { + match = 1; + break; + } + } + + if (match == 0) { + xmlWarningMsg(ctxt, XML_WAR_ENCODING_MISMATCH, + "Encoding '%s' doesn't match " + "auto-detected '%s'\n", + encoding, BAD_CAST autoEnc); + xmlFree(encoding); + encoding = xmlStrdup(BAD_CAST autoEnc); + if (encoding == NULL) + xmlCtxtErrMemory(ctxt); + } + } + } + + if (ctxt->encoding != NULL) + xmlFree((xmlChar *) ctxt->encoding); + ctxt->encoding = encoding; +} + +/** + * xmlGetActualEncoding: + * @ctxt: the parser context + * + * Returns the actual used to parse the document. This can differ from + * the declared encoding. + */ +const xmlChar * +xmlGetActualEncoding(xmlParserCtxtPtr ctxt) { + const xmlChar *encoding = NULL; + + if ((ctxt->input->flags & XML_INPUT_USES_ENC_DECL) || + (ctxt->input->flags & XML_INPUT_AUTO_ENCODING)) { + /* Preserve encoding exactly */ + encoding = ctxt->encoding; + } else if ((ctxt->input->buf) && (ctxt->input->buf->encoder)) { + encoding = BAD_CAST ctxt->input->buf->encoder->name; + } else if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) { + encoding = BAD_CAST "UTF-8"; + } + + return(encoding); } /************************************************************************ @@ -1193,8 +1502,6 @@ xmlFreeInputStream(xmlParserInputPtr input) { if (input == NULL) return; if (input->filename != NULL) xmlFree((char *) input->filename); - if (input->directory != NULL) xmlFree((char *) input->directory); - if (input->encoding != NULL) xmlFree((char *) input->encoding); if (input->version != NULL) xmlFree((char *) input->version); if ((input->free != NULL) && (input->base != NULL)) input->free((xmlChar *) input->base); @@ -1217,21 +1524,304 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) { input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput)); if (input == NULL) { - xmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); + xmlCtxtErrMemory(ctxt); + return(NULL); + } + memset(input, 0, sizeof(xmlParserInput)); + input->line = 1; + input->col = 1; + + /* + * If the context is NULL the id cannot be initialized, but that + * should not happen while parsing which is the situation where + * the id is actually needed. + */ + if (ctxt != NULL) { + if (input->id >= INT_MAX) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + input->id = ctxt->input_id++; + } + + return(input); +} + +/** + * xmlNewInputURL: + * @ctxt: parser context + * @url: filename or URL + * @publicId: publid ID from doctype (optional) + * @encoding: character encoding (optional) + * @flags: unused, pass 0 + * + * Creates a new parser input from the filesystem, the network or + * a user-defined resource loader. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId, + const char *encoding, int flags ATTRIBUTE_UNUSED) { + xmlParserInputPtr input; + + if ((ctxt == NULL) || (url == NULL)) + return(NULL); + + input = xmlLoadExternalEntity(url, publicId, ctxt); + if (input == NULL) + return(NULL); + + if (encoding != NULL) + xmlSwitchInputEncodingName(ctxt, input, encoding); + + return(input); +} + +/** + * xmlNewInputInternal: + * @ctxt: parser context + * @buf: parser input buffer + * @filename: filename or URL + * @encoding: character encoding (optional) + * + * Internal helper function. + * + * Returns a new parser input. + */ +static xmlParserInputPtr +xmlNewInputInternal(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf, + const char *filename, const char *encoding) { + xmlParserInputPtr input; + + input = xmlNewInputStream(ctxt); + if (input == NULL) { + xmlFreeParserInputBuffer(buf); + return(NULL); + } + + input->buf = buf; + xmlBufResetInput(input->buf->buffer, input); + + if (filename != NULL) { + input->filename = xmlMemStrdup(filename); + if (input->filename == NULL) { + xmlCtxtErrMemory(ctxt); + xmlFreeInputStream(input); + return(NULL); + } + } + + if (encoding != NULL) + xmlSwitchInputEncodingName(ctxt, input, encoding); + + return(input); +} + +/** + * xmlNewInputMemory: + * @ctxt: parser context + * @url: base URL (optional) + * @mem: pointer to char array + * @size: size of array + * @encoding: character encoding (optional) + * @flags: optimization hints + * + * Creates a new parser input to read from a memory area. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * If the XML_INPUT_BUF_STATIC flag is set, the memory area must + * stay unchanged until parsing has finished. This can avoid + * temporary copies. + * + * If the XML_INPUT_BUF_ZERO_TERMINATED flag is set, the memory + * area must contain a zero byte after the buffer at position @size. + * This can avoid temporary copies. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url, + const void *mem, size_t size, + const char *encoding, int flags) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (mem == NULL)) + return(NULL); + + buf = xmlNewInputBufferMemory(mem, size, flags, XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputString: + * @ctxt: parser context + * @url: base URL (optional) + * @str: zero-terminated string + * @encoding: character encoding (optional) + * @flags: optimization hints + * + * Creates a new parser input to read from a zero-terminated string. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * If the XML_INPUT_BUF_STATIC flag is set, the string must + * stay unchanged until parsing has finished. This can avoid + * temporary copies. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url, + const char *str, const char *encoding, int flags) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (str == NULL)) + return(NULL); + + buf = xmlNewInputBufferString(str, flags); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputFd: + * @ctxt: parser context + * @url: base URL (optional) + * @fd: file descriptor + * @encoding: character encoding (optional) + * @flags: unused, pass 0 + * + * Creates a new parser input to read from a zero-terminated string. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * @fd is closed after parsing has finished. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *url, + int fd, const char *encoding, int flags ATTRIBUTE_UNUSED) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (fd < 0)) + return(NULL); + + buf = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputIO: + * @ctxt: parser context + * @url: base URL (optional) + * @ioRead: read callback + * @ioClose: close callback (optional) + * @ioCtxt: IO context + * @encoding: character encoding (optional) + * @flags: unused, pass 0 + * + * Creates a new parser input to read from input callbacks and + * cintext. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * @ioRead is called to read new data into a provided buffer. + * It must return the number of bytes written into the buffer + * ot a negative xmlParserErrors code on failure. + * + * @ioClose is called after parsing has finished. + * + * @ioCtxt is an opaque pointer passed to the callbacks. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url, + xmlInputReadCallback ioRead, xmlInputCloseCallback ioClose, + void *ioCtxt, + const char *encoding, int flags ATTRIBUTE_UNUSED) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (ioRead == NULL)) return(NULL); + + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + if (ioClose != NULL) + ioClose(ioCtxt); + return(NULL); + } + + buf->context = ioCtxt; + buf->readcallback = ioRead; + buf->closecallback = ioClose; + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputPush: + * @ctxt: parser context + * @url: base URL (optional) + * @chunk: pointer to char array + * @size: size of array + * @encoding: character encoding (optional) + * + * Creates a new parser input for a push parser. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url, + const char *chunk, int size, const char *encoding) { + xmlParserInputBufferPtr buf; + xmlParserInputPtr input; + + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); } - memset(input, 0, sizeof(xmlParserInput)); - input->line = 1; - input->col = 1; - input->standalone = -1; - /* - * If the context is NULL the id cannot be initialized, but that - * should not happen while parsing which is the situation where - * the id is actually needed. - */ - if (ctxt != NULL) - input->id = ctxt->input_id++; + input = xmlNewInputInternal(ctxt, buf, url, encoding); + if (input == NULL) + return(NULL); + + input->flags |= XML_INPUT_PROGRESSIVE; + + if ((size > 0) && (chunk != NULL)) { + int res; + + res = xmlParserInputBufferPush(input->buf, size, chunk); + xmlBufResetInput(input->buf->buffer, input); + if (res < 0) { + xmlCtxtErrIO(ctxt, input->buf->error, NULL); + xmlFreeInputStream(input); + return(NULL); + } + } return(input); } @@ -1239,7 +1829,7 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) { /** * xmlNewIOInputStream: * @ctxt: an XML parser context - * @input: an I/O Input + * @buf: an input buffer * @enc: the charset encoding if known * * Create a new input stream structure encapsulating the @input into @@ -1248,89 +1838,50 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) { * Returns the new input stream or NULL */ xmlParserInputPtr -xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr input, +xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf, xmlCharEncoding enc) { - xmlParserInputPtr inputStream; - - if (input == NULL) return(NULL); - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, "new input from I/O\n"); - inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { - return(NULL); - } - inputStream->filename = NULL; - inputStream->buf = input; - xmlBufResetInput(inputStream->buf->buffer, inputStream); + const char *encoding; - if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } + if (buf == NULL) + return(NULL); - return(inputStream); + encoding = xmlGetCharEncodingName(enc); + return(xmlNewInputInternal(ctxt, buf, NULL, encoding)); } /** * xmlNewEntityInputStream: * @ctxt: an XML parser context - * @entity: an Entity pointer + * @ent: an Entity pointer + * + * DEPRECATED: Internal function, do not use. * * Create a new input stream based on an xmlEntityPtr * * Returns the new input stream or NULL */ xmlParserInputPtr -xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { +xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) { xmlParserInputPtr input; - if (entity == NULL) { - xmlErrInternal(ctxt, "xmlNewEntityInputStream entity = NULL\n", - NULL); - return(NULL); - } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new input from entity: %s\n", entity->name); - if (entity->content == NULL) { - switch (entity->etype) { - case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: - xmlErrInternal(ctxt, "Cannot parse entity %s\n", - entity->name); - break; - case XML_EXTERNAL_GENERAL_PARSED_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - return(xmlLoadExternalEntity((char *) entity->URI, - (char *) entity->ExternalID, ctxt)); - case XML_INTERNAL_GENERAL_ENTITY: - xmlErrInternal(ctxt, - "Internal entity %s without content !\n", - entity->name); - break; - case XML_INTERNAL_PARAMETER_ENTITY: - xmlErrInternal(ctxt, - "Internal parameter entity %s without content !\n", - entity->name); - break; - case XML_INTERNAL_PREDEFINED_ENTITY: - xmlErrInternal(ctxt, - "Predefined entity %s without content !\n", - entity->name); - break; - } - return(NULL); - } - input = xmlNewInputStream(ctxt); - if (input == NULL) { + if ((ctxt == NULL) || (ent == NULL)) return(NULL); + + if (ent->content != NULL) { + input = xmlNewInputString(ctxt, NULL, (const char *) ent->content, + NULL, XML_INPUT_BUF_STATIC); + } else if (ent->URI != NULL) { + input = xmlLoadExternalEntity((char *) ent->URI, + (char *) ent->ExternalID, ctxt); + } else { + return(NULL); } - if (entity->URI != NULL) - input->filename = (char *) xmlStrdup((xmlChar *) entity->URI); - input->base = entity->content; - if (entity->length == 0) - entity->length = xmlStrlen(entity->content); - input->cur = entity->content; - input->length = entity->length; - input->end = &entity->content[input->length]; + + if (input == NULL) + return(NULL); + + input->entity = ent; + return(input); } @@ -1340,30 +1891,159 @@ xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { * @buffer: an memory buffer * * Create a new input stream based on a memory buffer. + * * Returns the new input stream */ xmlParserInputPtr xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) { - xmlParserInputPtr input; + return(xmlNewInputString(ctxt, NULL, (const char *) buffer, NULL, 0)); +} - if (buffer == NULL) { - xmlErrInternal(ctxt, "xmlNewStringInputStream string = NULL\n", - NULL); - return(NULL); + +/**************************************************************** + * * + * External entities loading * + * * + ****************************************************************/ + +#ifdef LIBXML_CATALOG_ENABLED + +/** + * xmlResolveResourceFromCatalog: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * Resolves the URL and ID against the appropriate catalog. + * This function is used by xmlDefaultExternalEntityLoader and + * xmlNoNetExternalEntityLoader. + * + * Returns a new allocated URL, or NULL. + */ +static xmlChar * +xmlResolveResourceFromCatalog(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlChar *resource = NULL; + xmlCatalogAllow pref; + + /* + * If the resource doesn't exists as a file, + * try to load it from the resource pointed in the catalogs + */ + pref = xmlCatalogGetDefaults(); + + if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { + /* + * Do a local lookup + */ + if ((ctxt != NULL) && (ctxt->catalogs != NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_DOCUMENT))) { + resource = xmlCatalogLocalResolve(ctxt->catalogs, + (const xmlChar *)ID, + (const xmlChar *)URL); + } + /* + * Try a global lookup + */ + if ((resource == NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_GLOBAL))) { + resource = xmlCatalogResolve((const xmlChar *)ID, + (const xmlChar *)URL); + } + if ((resource == NULL) && (URL != NULL)) + resource = xmlStrdup((const xmlChar *) URL); + + /* + * TODO: do an URI lookup on the reference + */ + if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { + xmlChar *tmp = NULL; + + if ((ctxt != NULL) && (ctxt->catalogs != NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_DOCUMENT))) { + tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); + } + if ((tmp == NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_GLOBAL))) { + tmp = xmlCatalogResolveURI(resource); + } + + if (tmp != NULL) { + xmlFree(resource); + resource = tmp; + } + } } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new fixed input: %.30s\n", buffer); - input = xmlNewInputStream(ctxt); - if (input == NULL) { - xmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); - return(NULL); + + return resource; +} + +#endif + +/** + * xmlCheckHTTPInput: + * @ctxt: an XML parser context + * @ret: an XML parser input + * + * DEPRECATED: Internal function, don't use. + * + * Check an input in case it was created from an HTTP stream, in that + * case it will handle encoding and update of the base URL in case of + * redirection. It also checks for HTTP errors in which case the input + * is cleanly freed up and an appropriate error is raised in context + * + * Returns the input or NULL in case of HTTP error. + */ +xmlParserInputPtr +xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { + /* Avoid unused variable warning if features are disabled. */ + (void) ctxt; + +#ifdef LIBXML_HTTP_ENABLED + if ((ret != NULL) && (ret->buf != NULL) && + (ret->buf->readcallback == xmlIOHTTPRead) && + (ret->buf->context != NULL)) { + const char *encoding; + const char *redir; + const char *mime; + int code; + + code = xmlNanoHTTPReturnCode(ret->buf->context); + if (code >= 400) { + /* fatal error */ + if (ret->filename != NULL) + xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, ret->filename); + else + xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, ""); + xmlFreeInputStream(ret); + ret = NULL; + } else { + + mime = xmlNanoHTTPMimeType(ret->buf->context); + if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || + (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { + encoding = xmlNanoHTTPEncoding(ret->buf->context); + if (encoding != NULL) + xmlSwitchEncodingName(ctxt, encoding); +#if 0 + } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { +#endif + } + redir = xmlNanoHTTPRedir(ret->buf->context); + if (redir != NULL) { + if (ret->filename != NULL) + xmlFree((xmlChar *) ret->filename); + ret->filename = + (char *) xmlStrdup((const xmlChar *) redir); + } + } } - input->base = buffer; - input->cur = buffer; - input->length = xmlStrlen(buffer); - input->end = &buffer[input->length]; - return(input); +#endif + return(ret); } /** @@ -1379,22 +2059,17 @@ xmlParserInputPtr xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) { xmlParserInputBufferPtr buf; xmlParserInputPtr inputStream; - char *directory = NULL; - xmlChar *URI = NULL; - - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new input from file: %s\n", filename); - if (ctxt == NULL) return(NULL); - buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE); + const xmlChar *URI; + xmlChar *canonic; + int code; + + if ((ctxt == NULL) || (filename == NULL)) + return(NULL); + + code = xmlParserInputBufferCreateFilenameSafe(filename, + XML_CHAR_ENCODING_NONE, &buf); if (buf == NULL) { - if (filename == NULL) - __xmlLoaderErr(ctxt, - "failed to load external entity: NULL filename \n", - NULL); - else - __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", - (const char *) filename); + xmlCtxtErrIO(ctxt, code, filename); return(NULL); } @@ -1410,21 +2085,189 @@ xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) { return(NULL); if (inputStream->filename == NULL) - URI = xmlStrdup((xmlChar *) filename); + URI = (xmlChar *) filename; else - URI = xmlStrdup((xmlChar *) inputStream->filename); - directory = xmlParserGetDirectory((const char *) URI); - if (inputStream->filename != NULL) xmlFree((char *)inputStream->filename); - inputStream->filename = (char *) xmlCanonicPath((const xmlChar *) URI); - if (URI != NULL) xmlFree((char *) URI); - inputStream->directory = directory; + URI = (xmlChar *) inputStream->filename; + canonic = xmlCanonicPath(URI); + if (canonic == NULL) { + xmlCtxtErrMemory(ctxt); + xmlFreeInputStream(inputStream); + return(NULL); + } + if (inputStream->filename != NULL) + xmlFree((char *) inputStream->filename); + inputStream->filename = (char *) canonic; xmlBufResetInput(inputStream->buf->buffer, inputStream); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = (char *) xmlStrdup((const xmlChar *) directory); + return(inputStream); } +/** + * xmlDefaultExternalEntityLoader: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * By default we don't load external entities, yet. + * + * Returns a new allocated xmlParserInputPtr, or NULL. + */ +static xmlParserInputPtr +xmlDefaultExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret = NULL; + xmlChar *resource = NULL; + + if (URL == NULL) + return(NULL); + + if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { + int options = ctxt->options; + + ctxt->options -= XML_PARSE_NONET; + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + ctxt->options = options; + return(ret); + } +#ifdef LIBXML_CATALOG_ENABLED + resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); +#endif + + if (resource == NULL) + resource = (xmlChar *) URL; + + ret = xmlNewInputFromFile(ctxt, (const char *) resource); + if ((resource != NULL) && (resource != (xmlChar *) URL)) + xmlFree(resource); + return (ret); +} + +/** + * xmlNoNetExternalEntityLoader: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * A specific entity loader disabling network accesses, though still + * allowing local catalog accesses for resolution. + * + * Returns a new allocated xmlParserInputPtr, or NULL. + */ +xmlParserInputPtr +xmlNoNetExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr input = NULL; + xmlChar *resource = NULL; + +#ifdef LIBXML_CATALOG_ENABLED + resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); +#endif + + if (resource == NULL) + resource = (xmlChar *) URL; + + if (resource != NULL) { + if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || + (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { + xmlCtxtErrIO(ctxt, XML_IO_NETWORK_ATTEMPT, + (const char *) resource); + /* + * Also forward the error directly to the global error + * handler, which the XML::LibXML test suite expects. + */ + __xmlIOErr(XML_FROM_IO, XML_IO_NETWORK_ATTEMPT, + (const char *) resource); + if (resource != (xmlChar *) URL) + xmlFree(resource); + return(NULL); + } + } + input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); + if (resource != (xmlChar *) URL) + xmlFree(resource); + return(input); +} + +/* + * This global has to die eventually + */ +static xmlExternalEntityLoader +xmlCurrentExternalEntityLoader = xmlDefaultExternalEntityLoader; + +/** + * xmlSetExternalEntityLoader: + * @f: the new entity resolver function + * + * Changes the defaultexternal entity resolver function for the application + */ +void +xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { + xmlCurrentExternalEntityLoader = f; +} + +/** + * xmlGetExternalEntityLoader: + * + * Get the default external entity resolver function for the application + * + * Returns the xmlExternalEntityLoader function pointer + */ +xmlExternalEntityLoader +xmlGetExternalEntityLoader(void) { + return(xmlCurrentExternalEntityLoader); +} + +/** + * xmlLoadExternalEntity: + * @URL: the URL for the entity to load + * @ID: the Public ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * @URL is a filename or URL. If if contains the substring "://", + * it is assumed to be a Legacy Extended IRI. Otherwise, it is + * treated as a filesystem path. + * + * @ID is an optional XML public ID, typically from a doctype + * declaration. It is used for catalog lookups. + * + * The following resource loaders will be called if they were + * registered (in order of precedence): + * + * - the global external entity loader set with + * xmlSetExternalEntityLoader + * - the per-thread xmlParserInputBufferCreateFilenameFunc set with + * xmlParserInputBufferCreateFilenameDefault + * - the default loader which will return + * - the result from a matching global input callback set with + * xmlRegisterInputCallbacks + * - a HTTP resource if support is compiled in. + * - a file opened from the filesystem, with automatic detection + * of compressed files if support is compiled in. + * + * Returns the xmlParserInputPtr or NULL + */ +xmlParserInputPtr +xmlLoadExternalEntity(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + char *canonicFilename; + xmlParserInputPtr ret; + + if (URL == NULL) + return(NULL); + + canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); + if (canonicFilename == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); + xmlFree(canonicFilename); + return(ret); +} + /************************************************************************ * * * Commodity functions to handle parser contexts * @@ -1432,42 +2275,48 @@ xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) { ************************************************************************/ /** - * xmlInitParserCtxt: - * @ctxt: an XML parser context + * xmlInitSAXParserCtxt: + * @ctxt: XML parser context + * @sax: SAX handlert + * @userData: user data * - * Initialize a parser context + * Initialize a SAX parser context * * Returns 0 in case of success and -1 in case of error */ -int -xmlInitParserCtxt(xmlParserCtxtPtr ctxt) +static int +xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, + void *userData) { xmlParserInputPtr input; - if(ctxt==NULL) { - xmlErrInternal(NULL, "Got NULL parser context\n", NULL); + if (ctxt == NULL) return(-1); - } - - xmlInitParser(); if (ctxt->dict == NULL) ctxt->dict = xmlDictCreate(); - if (ctxt->dict == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); + if (ctxt->dict == NULL) return(-1); - } xmlDictSetLimit(ctxt->dict, XML_MAX_DICTIONARY_LIMIT); if (ctxt->sax == NULL) ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); - if (ctxt->sax == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); + if (ctxt->sax == NULL) return(-1); - } - else + if (sax == NULL) { + memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); xmlSAXVersion(ctxt->sax, 2); + ctxt->userData = ctxt; + } else { + if (sax->initialized == XML_SAX2_MAGIC) { + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); + } else { + memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } + ctxt->userData = userData ? userData : ctxt; + } ctxt->maxatts = 0; ctxt->atts = NULL; @@ -1477,13 +2326,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) xmlMalloc(5 * sizeof(xmlParserInputPtr)); ctxt->inputMax = 5; } - if (ctxt->inputTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->inputTab == NULL) return(-1); - } while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ xmlFreeInputStream(input); } @@ -1496,26 +2340,15 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 0; - ctxt->external = 0; ctxt->instate = XML_PARSER_START; - ctxt->token = 0; - ctxt->directory = NULL; /* Allocate the Node stack */ if (ctxt->nodeTab == NULL) { ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr)); ctxt->nodeMax = 10; } - if (ctxt->nodeTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nodeTab == NULL) return(-1); - } ctxt->nodeNr = 0; ctxt->node = NULL; @@ -1524,19 +2357,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); ctxt->nameMax = 10; } - if (ctxt->nameTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; + if (ctxt->nameTab == NULL) return(-1); - } ctxt->nameNr = 0; ctxt->name = NULL; @@ -1545,36 +2367,33 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int)); ctxt->spaceMax = 10; } - if (ctxt->spaceTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; - ctxt->spaceNr = 0; - ctxt->spaceMax = 0; - ctxt->space = NULL; + if (ctxt->spaceTab == NULL) return(-1); - } ctxt->spaceNr = 1; ctxt->spaceMax = 10; ctxt->spaceTab[0] = -1; ctxt->space = &ctxt->spaceTab[0]; - ctxt->userData = ctxt; ctxt->myDoc = NULL; ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; ctxt->valid = 1; + + ctxt->options = XML_PARSE_NODICT; + + /* + * Initialize some parser options from deprecated global variables. + * Note that the "modern" API taking options arguments or + * xmlCtxtSetOptions will ignore these defaults. They're only + * relevant if old API functions like xmlParseFile are used. + */ ctxt->loadsubset = xmlLoadExtDtdDefaultValue; if (ctxt->loadsubset) { ctxt->options |= XML_PARSE_DTDLOAD; } ctxt->validate = xmlDoValidityCheckingDefaultValue; + if (ctxt->validate) { + ctxt->options |= XML_PARSE_DTDVALID; + } ctxt->pedantic = xmlPedanticParserDefaultValue; if (ctxt->pedantic) { ctxt->options |= XML_PARSE_PEDANTIC; @@ -1585,38 +2404,59 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; ctxt->options |= XML_PARSE_NOBLANKS; } + ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue; + if (ctxt->replaceEntities) { + ctxt->options |= XML_PARSE_NOENT; + } + if (xmlGetWarningsDefaultValue == 0) + ctxt->options |= XML_PARSE_NOWARNING; ctxt->vctxt.flags = XML_VCTXT_USE_PCTXT; ctxt->vctxt.userData = ctxt; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning; - if (ctxt->validate) { - if (xmlGetWarningsDefaultValue == 0) - ctxt->vctxt.warning = NULL; - else - ctxt->vctxt.warning = xmlParserValidityWarning; - ctxt->vctxt.nodeMax = 0; - ctxt->options |= XML_PARSE_DTDVALID; - } - ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue; - if (ctxt->replaceEntities) { - ctxt->options |= XML_PARSE_NOENT; - } + ctxt->record_info = 0; ctxt->checkIndex = 0; ctxt->inSubset = 0; ctxt->errNo = XML_ERR_OK; ctxt->depth = 0; - ctxt->charset = XML_CHAR_ENCODING_UTF8; ctxt->catalogs = NULL; - ctxt->nbentities = 0; ctxt->sizeentities = 0; ctxt->sizeentcopy = 0; ctxt->input_id = 1; + ctxt->maxAmpl = XML_MAX_AMPLIFICATION_DEFAULT; xmlInitNodeInfoSeq(&ctxt->node_seq); + + if (ctxt->nsdb == NULL) { + ctxt->nsdb = xmlParserNsCreate(); + if (ctxt->nsdb == NULL) { + xmlCtxtErrMemory(ctxt); + return(-1); + } + } + return(0); } +/** + * xmlInitParserCtxt: + * @ctxt: an XML parser context + * + * DEPRECATED: Internal function which will be made private in a future + * version. + * + * Initialize a parser context + * + * Returns 0 in case of success and -1 in case of error + */ + +int +xmlInitParserCtxt(xmlParserCtxtPtr ctxt) +{ + return(xmlInitSAXParserCtxt(ctxt, NULL, NULL)); +} + /** * xmlFreeParserCtxt: * @ctxt: an XML parser context @@ -1651,11 +2491,13 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) if (ctxt->sax != NULL) #endif /* LIBXML_SAX1_ENABLED */ xmlFree(ctxt->sax); - if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory); + if (ctxt->directory != NULL) xmlFree(ctxt->directory); if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab); if (ctxt->atts != NULL) xmlFree((xmlChar * *)ctxt->atts); if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); - if (ctxt->nsTab != NULL) xmlFree((char *) ctxt->nsTab); + if (ctxt->nsTab != NULL) xmlFree(ctxt->nsTab); + if (ctxt->nsdb != NULL) xmlParserNsFree(ctxt->nsdb); + if (ctxt->attrHash != NULL) xmlFree(ctxt->attrHash); if (ctxt->pushTab != NULL) xmlFree(ctxt->pushTab); if (ctxt->attallocs != NULL) xmlFree(ctxt->attallocs); if (ctxt->attsDefault != NULL) @@ -1713,16 +2555,37 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) xmlParserCtxtPtr xmlNewParserCtxt(void) +{ + return(xmlNewSAXParserCtxt(NULL, NULL)); +} + +/** + * xmlNewSAXParserCtxt: + * @sax: SAX handler + * @userData: user data + * + * Allocate and initialize a new SAX parser context. If userData is NULL, + * the parser context will be passed as user data. + * + * Available since 2.11.0. If you want support older versions, + * it's best to invoke xmlNewParserCtxt and set ctxt->sax with + * struct assignment. + * + * Returns the xmlParserCtxtPtr or NULL if memory allocation failed. + */ + +xmlParserCtxtPtr +xmlNewSAXParserCtxt(const xmlSAXHandler *sax, void *userData) { xmlParserCtxtPtr ctxt; + xmlInitParser(); + ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); - if (ctxt == NULL) { - xmlErrMemory(NULL, "cannot allocate parser context\n"); + if (ctxt == NULL) return(NULL); - } memset(ctxt, 0, sizeof(xmlParserCtxt)); - if (xmlInitParserCtxt(ctxt) < 0) { + if (xmlInitSAXParserCtxt(ctxt, sax, userData) < 0) { xmlFreeParserCtxt(ctxt); return(NULL); } @@ -1757,12 +2620,14 @@ xmlClearParserCtxt(xmlParserCtxtPtr ctxt) * @ctx: an XML parser context * @node: an XML node within the tree * + * DEPRECATED: Don't use. + * * Find the parser node info struct for a given node * * Returns an xmlParserNodeInfo block pointer or NULL */ const xmlParserNodeInfo * -xmlParserFindNodeInfo(const xmlParserCtxtPtr ctx, const xmlNodePtr node) +xmlParserFindNodeInfo(xmlParserCtxtPtr ctx, xmlNodePtr node) { unsigned long pos; @@ -1782,6 +2647,8 @@ xmlParserFindNodeInfo(const xmlParserCtxtPtr ctx, const xmlNodePtr node) * xmlInitNodeInfoSeq: * @seq: a node info sequence pointer * + * DEPRECATED: Don't use. + * * -- Initialize (set to initial state) node info sequence */ void @@ -1798,6 +2665,8 @@ xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq) * xmlClearNodeInfoSeq: * @seq: a node info sequence pointer * + * DEPRECATED: Don't use. + * * -- Clear (release memory and reinitialize) node * info sequence */ @@ -1816,6 +2685,7 @@ xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq) * @seq: a node info sequence pointer * @node: an XML node pointer * + * DEPRECATED: Don't use. * * xmlParserFindNodeInfoIndex : Find the index that the info record for * the given node is or should be at in a sorted sequence @@ -1823,8 +2693,8 @@ xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq) * Returns a long indicating the position of the record */ unsigned long -xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, - const xmlNodePtr node) +xmlParserFindNodeInfoIndex(xmlParserNodeInfoSeqPtr seq, + xmlNodePtr node) { unsigned long upper, lower, middle; int found = 0; @@ -1859,11 +2729,13 @@ xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, * @ctxt: an XML parser context * @info: a node info sequence pointer * + * DEPRECATED: Don't use. + * * Insert node info record into the sorted sequence */ void xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, - const xmlParserNodeInfoPtr info) + xmlParserNodeInfoPtr info) { unsigned long pos; @@ -1899,7 +2771,7 @@ xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, byte_size); if (tmp_buffer == NULL) { - xmlErrMemory(ctxt, "failed to allocate buffer\n"); + xmlCtxtErrMemory(ctxt); return; } ctxt->node_seq.buffer = tmp_buffer; @@ -1929,6 +2801,8 @@ xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, * xmlPedanticParserDefault: * @val: int 0 or 1 * + * DEPRECATED: Use the modern options API with XML_PARSE_PEDANTIC. + * * Set and return the previous value for enabling pedantic warnings. * * Returns the last value for 0 for no substitution, 1 for substitution. @@ -1946,6 +2820,8 @@ xmlPedanticParserDefault(int val) { * xmlLineNumbersDefault: * @val: int 0 or 1 * + * DEPRECATED: The modern options API always enables line numbers. + * * Set and return the previous value for enabling line numbers in elements * contents. This may break on old application and is turned off by default. * @@ -1964,6 +2840,8 @@ xmlLineNumbersDefault(int val) { * xmlSubstituteEntitiesDefault: * @val: int 0 or 1 * + * DEPRECATED: Use the modern options API with XML_PARSE_NOENT. + * * Set and return the previous value for default entity support. * Initially the parser always keep entity references instead of substituting * entity values in the output. This function has to be used to change the @@ -1986,6 +2864,8 @@ xmlSubstituteEntitiesDefault(int val) { * xmlKeepBlanksDefault: * @val: int 0 or 1 * + * DEPRECATED: Use the modern options API with XML_PARSE_NOBLANKS. + * * Set and return the previous value for default blanks text nodes support. * The 1.x version of the parser used an heuristic to try to detect * ignorable white spaces. As a result the SAX callback was generating @@ -2011,7 +2891,10 @@ xmlKeepBlanksDefault(int val) { int old = xmlKeepBlanksDefaultValue; xmlKeepBlanksDefaultValue = val; - if (!val) xmlIndentTreeOutput = 1; +#ifdef LIBXML_OUTPUT_ENABLED + if (!val) + xmlIndentTreeOutput = 1; +#endif return(old); } diff --git a/pattern.c b/pattern.c index cff4469c61d..23b52744ac5 100644 --- a/pattern.c +++ b/pattern.c @@ -27,18 +27,15 @@ #include "libxml.h" #include +#include #include #include -#include #include #include #include -#include #ifdef LIBXML_PATTERN_ENABLED -/* #define DEBUG_STREAMING */ - #ifdef ERROR #undef ERROR #endif @@ -347,9 +344,8 @@ xmlFreePatParserContext(xmlPatParserContextPtr ctxt) { * Returns -1 in case of failure, 0 otherwise. */ static int -xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED, - xmlPatternPtr comp, - xmlPatOp op, xmlChar * value, xmlChar * value2) +xmlPatternAdd(xmlPatParserContextPtr ctxt, xmlPatternPtr comp, + xmlPatOp op, xmlChar * value, xmlChar * value2) { if (comp->nbStep >= comp->maxStep) { xmlStepOpPtr temp; @@ -358,6 +354,7 @@ xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED, if (temp == NULL) { ERROR(ctxt, NULL, NULL, "xmlPatternAdd: realloc failed\n"); + ctxt->error = -1; return (-1); } comp->steps = temp; @@ -700,10 +697,6 @@ rollback: * * ************************************************************************/ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); #define CUR (*ctxt->cur) #define SKIP(val) ctxt->cur += (val) #define NXT(val) ctxt->cur[(val)] @@ -720,14 +713,6 @@ rollback: #define PUSH(op, val, val2) \ if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error; -#define XSLT_ERROR(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ - ctxt->error = (X); return; } - -#define XSLT_ERROR0(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ - ctxt->error = (X); return(0); } - #if 0 /** * xmlPatScanLiteral: @@ -872,6 +857,8 @@ xmlPatScanNCName(xmlPatParserContextPtr ctxt) { ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q); else ret = xmlStrndup(q, cur - q); + if (ret == NULL) + ctxt->error = -1; CUR_PTR = cur; return(ret); } @@ -916,6 +903,8 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { SKIP_BLANKS; name = xmlPatScanNCName(ctxt); + if (ctxt->error < 0) + return; if (name == NULL) { if (CUR == '*') { PUSH(XML_OP_ATTR, NULL, NULL); @@ -935,7 +924,6 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { if (IS_BLANK_CH(CUR)) { ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL); - XML_PAT_FREE_STRING(ctxt, prefix); ctxt->error = 1; goto error; } @@ -960,12 +948,12 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { ERROR5(NULL, NULL, NULL, "xmlCompileAttributeTest : no namespace bound to prefix %s\n", prefix); - XML_PAT_FREE_STRING(ctxt, prefix); ctxt->error = 1; goto error; } } - XML_PAT_FREE_STRING(ctxt, prefix); + XML_PAT_FREE_STRING(ctxt, name); + name = NULL; if (token == NULL) { if (CUR == '*') { NEXT; @@ -984,6 +972,8 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) { } return; error: + if (name != NULL) + XML_PAT_FREE_STRING(ctxt, name); if (URL != NULL) XML_PAT_FREE_STRING(ctxt, URL) if (token != NULL) @@ -1034,6 +1024,8 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { return; } name = xmlPatScanNCName(ctxt); + if (ctxt->error < 0) + return; if (name == NULL) { if (CUR == '*') { NEXT; @@ -1250,6 +1242,8 @@ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) { if (CUR == '@') { NEXT; xmlCompileAttributeTest(ctxt); + if (ctxt->error != 0) + goto error; SKIP_BLANKS; /* TODO: check for incompleteness */ if (CUR != 0) { @@ -1415,62 +1409,6 @@ error_unfinished: * * ************************************************************************/ -#ifdef DEBUG_STREAMING -static void -xmlDebugStreamComp(xmlStreamCompPtr stream) { - int i; - - if (stream == NULL) { - printf("Stream: NULL\n"); - return; - } - printf("Stream: %d steps\n", stream->nbStep); - for (i = 0;i < stream->nbStep;i++) { - if (stream->steps[i].ns != NULL) { - printf("{%s}", stream->steps[i].ns); - } - if (stream->steps[i].name == NULL) { - printf("* "); - } else { - printf("%s ", stream->steps[i].name); - } - if (stream->steps[i].flags & XML_STREAM_STEP_ROOT) - printf("root "); - if (stream->steps[i].flags & XML_STREAM_STEP_DESC) - printf("// "); - if (stream->steps[i].flags & XML_STREAM_STEP_FINAL) - printf("final "); - printf("\n"); - } -} -static void -xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) { - int i; - - if (ctxt == NULL) { - printf("Stream: NULL\n"); - return; - } - printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState); - if (match) - printf("matches\n"); - else - printf("\n"); - for (i = 0;i < ctxt->nbState;i++) { - if (ctxt->states[2 * i] < 0) - printf(" %d: free\n", i); - else { - printf(" %d: step %d, level %d", i, ctxt->states[2 * i], - ctxt->states[(2 * i) + 1]); - if (ctxt->comp->steps[ctxt->states[2 * i]].flags & - XML_STREAM_STEP_DESC) - printf(" //\n"); - else - printf("\n"); - } - } -} -#endif /** * xmlNewStreamComp: * @size: the number of expected steps @@ -1729,9 +1667,6 @@ xmlStreamCompile(xmlPatternPtr comp) { stream->steps[s].flags |= XML_STREAM_STEP_FINAL; if (root) stream->steps[0].flags |= XML_STREAM_STEP_ROOT; -#ifdef DEBUG_STREAMING - xmlDebugStreamComp(stream); -#endif comp->stream = stream; return(0); error: @@ -1849,12 +1784,9 @@ static int xmlStreamPushInternal(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns, int nodeType) { - int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc; + int ret = 0, final = 0, tmp, i, m, match, stepNr, desc; xmlStreamCompPtr comp; xmlStreamStep step; -#ifdef DEBUG_STREAMING - xmlStreamCtxtPtr orig = stream; -#endif if ((stream == NULL) || (stream->nbState < 0)) return(-1); @@ -1883,10 +1815,8 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, */ ret = 1; } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) { - /* TODO: Do we need this ? */ - tmp = xmlStreamCtxtAddState(stream, 0, 0); - if (tmp < 0) - err++; + if (xmlStreamCtxtAddState(stream, 0, 0) < 0) + return(-1); } } } @@ -2039,22 +1969,12 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, #endif /* if 0 ------------------------------------------------------- */ if (match) { final = step.flags & XML_STREAM_STEP_FINAL; - if (desc) { - if (final) { - ret = 1; - } else { - /* descending match create a new state */ - xmlStreamCtxtAddState(stream, stepNr + 1, - stream->level + 1); - } - } else { - if (final) { - ret = 1; - } else { - xmlStreamCtxtAddState(stream, stepNr + 1, - stream->level + 1); - } - } + if (final) { + ret = 1; + } else if (xmlStreamCtxtAddState(stream, stepNr + 1, + stream->level + 1) < 0) { + return(-1); + } if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) { /* * Check if we have a special case like "foo/bar//.", where @@ -2155,10 +2075,11 @@ compare: } final = step.flags & XML_STREAM_STEP_FINAL; if (match) { - if (final) + if (final) { ret = 1; - else - xmlStreamCtxtAddState(stream, 1, stream->level); + } else if (xmlStreamCtxtAddState(stream, 1, stream->level) < 0) { + return(-1); + } if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) { /* * Check if we have a special case like "foo//.", where @@ -2180,11 +2101,6 @@ stream_next: stream = stream->next; } /* while stream != NULL */ - if (err > 0) - ret = -1; -#ifdef DEBUG_STREAMING - xmlDebugStreamCtxt(orig, ret); -#endif return(ret); } @@ -2207,7 +2123,7 @@ stream_next: int xmlStreamPush(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns) { - return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE)); + return (xmlStreamPushInternal(stream, name, ns, XML_ELEMENT_NODE)); } /** @@ -2257,7 +2173,7 @@ xmlStreamPushNode(xmlStreamCtxtPtr stream, int xmlStreamPushAttr(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns) { - return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE)); + return (xmlStreamPushInternal(stream, name, ns, XML_ATTRIBUTE_NODE)); } /** @@ -2336,28 +2252,37 @@ xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt) ************************************************************************/ /** - * xmlPatterncompile: + * xmlPatternCompileSafe: * @pattern: the pattern to compile * @dict: an optional dictionary for interned strings * @flags: compilation flags, see xmlPatternFlags * @namespaces: the prefix definitions, array of [URI, prefix] or NULL + * @patternOut: output pattern * * Compile a pattern. * - * Returns the compiled form of the pattern or NULL in case of error + * Available since 2.13.0. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -xmlPatternPtr -xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, - const xmlChar **namespaces) { +int +xmlPatternCompileSafe(const xmlChar *pattern, xmlDict *dict, int flags, + const xmlChar **namespaces, xmlPatternPtr *patternOut) { xmlPatternPtr ret = NULL, cur; xmlPatParserContextPtr ctxt = NULL; const xmlChar *or, *start; xmlChar *tmp = NULL; int type = 0; int streamable = 1; + int error; - if (pattern == NULL) - return(NULL); + if (patternOut == NULL) + return(1); + + if (pattern == NULL) { + error = 1; + goto error; + } start = pattern; or = start; @@ -2373,9 +2298,15 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, } or++; } - if (ctxt == NULL) goto error; + if (ctxt == NULL) { + error = -1; + goto error; + } cur = xmlNewPattern(); - if (cur == NULL) goto error; + if (cur == NULL) { + error = -1; + goto error; + } /* * Assign string dict. */ @@ -2396,8 +2327,10 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, xmlCompileIDCXPathPath(ctxt); else xmlCompilePathPattern(ctxt); - if (ctxt->error != 0) + if (ctxt->error != 0) { + error = ctxt->error; goto error; + } xmlFreePatParserContext(ctxt); ctxt = NULL; @@ -2413,9 +2346,13 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, streamable = 0; } } - if (streamable) - xmlStreamCompile(cur); - if (xmlReversePattern(cur) < 0) + if (streamable) { + error = xmlStreamCompile(cur); + if (error != 0) + goto error; + } + error = xmlReversePattern(cur); + if (error != 0) goto error; if (tmp != NULL) { xmlFree(tmp); @@ -2434,12 +2371,33 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, } } - return(ret); + *patternOut = ret; + return(0); error: if (ctxt != NULL) xmlFreePatParserContext(ctxt); if (ret != NULL) xmlFreePattern(ret); if (tmp != NULL) xmlFree(tmp); - return(NULL); + *patternOut = NULL; + return(error); +} + +/** + * xmlPatterncompile: + * @pattern: the pattern to compile + * @dict: an optional dictionary for interned strings + * @flags: compilation flags, see xmlPatternFlags + * @namespaces: the prefix definitions, array of [URI, prefix] or NULL + * + * Compile a pattern. + * + * Returns the compiled form of the pattern or NULL in case of error + */ +xmlPatternPtr +xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, + const xmlChar **namespaces) { + xmlPatternPtr ret; + xmlPatternCompileSafe(pattern, dict, flags, namespaces, &ret); + return(ret); } /** diff --git a/relaxng.c b/relaxng.c index 7f0f2e741ed..24c3e51056c 100644 --- a/relaxng.c +++ b/relaxng.c @@ -34,6 +34,10 @@ #include #include +#include "private/error.h" +#include "private/regexp.h" +#include "private/string.h" + /* * The Relax-NG namespace */ @@ -47,37 +51,8 @@ static const xmlChar *xmlRelaxNGNs = (const xmlChar *) (xmlStrEqual(node->ns->href, xmlRelaxNGNs))) -#if 0 -#define DEBUG 1 - -#define DEBUG_GRAMMAR 1 - -#define DEBUG_CONTENT 1 - -#define DEBUG_TYPE 1 - -#define DEBUG_VALID 1 - -#define DEBUG_INTERLEAVE 1 - -#define DEBUG_LIST 1 - -#define DEBUG_INCLUDE 1 - -#define DEBUG_ERROR 1 - -#define DEBUG_COMPILE 1 - -#define DEBUG_PROGRESSIVE 1 -#endif - #define MAX_ERROR 5 -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; @@ -435,7 +410,7 @@ struct _xmlRelaxNGDocument { * Handle a redefinition of attribute error */ static void -xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) +xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt) { xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; @@ -449,17 +424,8 @@ xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) data = ctxt->userData; ctxt->nbErrors++; } - if (extra) - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_RELAXNGP, NULL); } /** @@ -470,7 +436,7 @@ xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) * Handle a redefinition of attribute error */ static void -xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) +xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt) { xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; @@ -484,17 +450,8 @@ xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) data = ctxt->userData; ctxt->nbErrors++; } - if (extra) - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGV, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGV, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_RELAXNGV, NULL); } /** @@ -515,6 +472,7 @@ xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; void *data = NULL; + int res; if (ctxt != NULL) { if (ctxt->serror != NULL) @@ -524,11 +482,18 @@ xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, data = ctxt->userData; ctxt->nbErrors++; } - __xmlRaiseError(schannel, channel, data, - NULL, node, XML_FROM_RELAXNGP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, NULL, node, + XML_FROM_RELAXNGP, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, NULL, 0, 0, + msg, str1, str2); + if (res < 0) + xmlRngPErrMemory(ctxt); } /** @@ -549,6 +514,7 @@ xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; void *data = NULL; + int res; if (ctxt != NULL) { if (ctxt->serror != NULL) @@ -558,11 +524,18 @@ xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, data = ctxt->userData; ctxt->nbErrors++; } - __xmlRaiseError(schannel, channel, data, - NULL, node, XML_FROM_RELAXNGV, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, NULL, node, + XML_FROM_RELAXNGV, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, NULL, 0, 0, + msg, str1, str2); + if (res < 0) + xmlRngVErrMemory(ctxt); } /************************************************************************ @@ -764,7 +737,7 @@ xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, NULL); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNG)); @@ -843,7 +816,7 @@ xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, NULL); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGGrammar)); @@ -899,7 +872,7 @@ xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) ctxt->defTab = (xmlRelaxNGDefinePtr *) xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); if (ctxt->defTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } } else if (ctxt->defMax <= ctxt->defNr) { @@ -911,14 +884,14 @@ xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) sizeof (xmlRelaxNGDefinePtr)); if (tmp == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } ctxt->defTab = tmp; } ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGDefine)); @@ -1024,7 +997,7 @@ xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) 1) * sizeof(xmlRelaxNGValidStatePtr)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } ret->nbState = 0; @@ -1033,7 +1006,7 @@ xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) sizeof (xmlRelaxNGValidStatePtr)); if (ret->tabState == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); xmlFree(ret); return (NULL); } @@ -1069,7 +1042,7 @@ xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidStatePtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "adding states\n"); + xmlRngVErrMemory(ctxt); return (-1); } states->tabState = tmp; @@ -1109,7 +1082,7 @@ xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidStatePtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "adding states\n"); + xmlRngVErrMemory(ctxt); return (-1); } states->tabState = tmp; @@ -1144,7 +1117,7 @@ xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, ctxt->freeStates = (xmlRelaxNGStatesPtr *) xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); if (ctxt->freeStates == NULL) { - xmlRngVErrMemory(ctxt, "storing states\n"); + xmlRngVErrMemory(ctxt); } } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { @@ -1155,7 +1128,7 @@ xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGStatesPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "storing states\n"); + xmlRngVErrMemory(ctxt); xmlFree(states->tabState); xmlFree(states); return; @@ -1211,7 +1184,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidState)); @@ -1235,7 +1208,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * sizeof(xmlAttrPtr)); if (ret->attrs == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (ret); } } else if (ret->maxAttrs < nbAttrs) { @@ -1244,7 +1217,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * sizeof(xmlAttrPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (ret); } ret->attrs = tmp; @@ -1293,7 +1266,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidState)); @@ -1309,7 +1282,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * sizeof(xmlAttrPtr)); if (ret->attrs == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); ret->nbAttrs = 0; return (ret); } @@ -1319,7 +1292,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * sizeof(xmlAttrPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); ret->nbAttrs = 0; return (ret); } @@ -1438,6 +1411,42 @@ xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc); +static xmlDoc * +xmlRelaxReadFile(xmlRelaxNGParserCtxtPtr ctxt, const char *filename) { + xmlParserCtxtPtr pctxt; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) { + xmlRngPErrMemory(ctxt); + return(NULL); + } + if (ctxt->serror != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->serror, ctxt->userData); + doc = xmlCtxtReadFile(pctxt, filename, NULL, 0); + xmlFreeParserCtxt(pctxt); + + return(doc); +} + +static xmlDoc * +xmlRelaxReadMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *buf, int size) { + xmlParserCtxtPtr pctxt; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) { + xmlRngPErrMemory(ctxt); + return(NULL); + } + if (ctxt->serror != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->serror, ctxt->userData); + doc = xmlCtxtReadMemory(pctxt, buf, size, NULL, NULL, 0); + xmlFreeParserCtxt(pctxt); + + return(doc); +} + /** * xmlRelaxNGIncludePush: * @ctxt: the parser context @@ -1458,7 +1467,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1469,7 +1478,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1523,15 +1532,6 @@ xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr tmp, tmp2; xmlChar *name2; -#ifdef DEBUG_INCLUDE - if (name == NULL) - xmlGenericError(xmlGenericErrorContext, - "Elimination of start from %s\n", URL); - else - xmlGenericError(xmlGenericErrorContext, - "Elimination of define %s from %s\n", - name, URL); -#endif tmp = target; while (tmp != NULL) { tmp2 = tmp->next; @@ -1559,18 +1559,11 @@ xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, if (xmlStrEqual (inc->doc->children->name, BAD_CAST "grammar")) { -#ifdef DEBUG_INCLUDE - href = xmlGetProp(tmp, BAD_CAST "href"); -#endif if (xmlRelaxNGRemoveRedefine(ctxt, href, xmlDocGetRootElement(inc->doc)->children, name) == 1) { found = 1; } -#ifdef DEBUG_INCLUDE - if (href != NULL) - xmlFree(href); -#endif } } if (xmlRelaxNGRemoveRedefine(ctxt, URL, tmp->children, name) == 1) { @@ -1604,11 +1597,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, int i; xmlNodePtr root, cur; -#ifdef DEBUG_INCLUDE - xmlGenericError(xmlGenericErrorContext, - "xmlRelaxNGLoadInclude(%s)\n", URL); -#endif - /* * check against recursion in the stack */ @@ -1624,22 +1612,19 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, /* * load the document */ - doc = xmlReadFile((const char *) URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) URL); if (doc == NULL) { xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, "xmlRelaxNG: could not load %s\n", URL, NULL); return (NULL); } -#ifdef DEBUG_INCLUDE - xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL); -#endif /* * Allocate the document structures and register it first. */ ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); xmlFreeDoc(doc); return (NULL); } @@ -1670,9 +1655,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, * Some preprocessing of the document content, this include recursing * in the include stack. */ -#ifdef DEBUG_INCLUDE - xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL); -#endif doc = xmlRelaxNGCleanupDoc(ctxt, doc); if (doc == NULL) { @@ -1685,9 +1667,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, */ xmlRelaxNGIncludePop(ctxt); -#ifdef DEBUG_INCLUDE - xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL); -#endif /* * Check that the top element is a grammar */ @@ -1779,10 +1758,6 @@ xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, { xmlRelaxNGValidErrorPtr cur; -#ifdef DEBUG_ERROR - xmlGenericError(xmlGenericErrorContext, - "Pushing error %d at %d on stack\n", err, ctxt->errNr); -#endif if (ctxt->errTab == NULL) { ctxt->errMax = 8; ctxt->errNr = 0; @@ -1791,7 +1766,7 @@ xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidError)); if (ctxt->errTab == NULL) { - xmlRngVErrMemory(ctxt, "pushing error\n"); + xmlRngVErrMemory(ctxt); return (0); } ctxt->err = NULL; @@ -1804,7 +1779,7 @@ xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidError)); if (ctxt->errTab == NULL) { - xmlRngVErrMemory(ctxt, "pushing error\n"); + xmlRngVErrMemory(ctxt); return (0); } ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; @@ -1886,7 +1861,7 @@ xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { - xmlRngPErrMemory(ctxt, "adding document\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1897,7 +1872,7 @@ xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { - xmlRngPErrMemory(ctxt, "adding document\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1967,7 +1942,7 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, /* * load the document */ - doc = xmlReadFile((const char *) URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) URL); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNG: could not load %s\n", URL, NULL); @@ -1979,8 +1954,7 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, */ ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); if (ret == NULL) { - xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, - "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); + xmlRngPErrMemory(ctxt); xmlFreeDoc(doc); return (NULL); } @@ -2257,9 +2231,6 @@ xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, if (ctxt->flags & FLAGS_NOERROR) return; -#ifdef DEBUG_ERROR - xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err); -#endif msg = xmlRelaxNGGetErrorString(err, arg1, arg2); if (msg == NULL) return; @@ -2284,10 +2255,6 @@ xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) int i; xmlRelaxNGValidErrorPtr err; -#ifdef DEBUG_ERROR - xmlGenericError(xmlGenericErrorContext, - "Pop errors till level %d\n", level); -#endif for (i = level; i < ctxt->errNr; i++) { err = &ctxt->errTab[i]; if (err->flags & ERROR_IS_DUP) { @@ -2317,10 +2284,6 @@ xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) int i, j, k; xmlRelaxNGValidErrorPtr err, dup; -#ifdef DEBUG_ERROR - xmlGenericError(xmlGenericErrorContext, - "Dumping error stack %d errors\n", ctxt->errNr); -#endif for (i = 0, k = 0; i < ctxt->errNr; i++) { err = &ctxt->errTab[i]; if (k < MAX_ERROR) { @@ -2371,9 +2334,6 @@ xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, if (ctxt->flags & FLAGS_NOERROR) return; -#ifdef DEBUG_ERROR - xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err); -#endif /* * generate the error directly */ @@ -2780,17 +2740,13 @@ xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || (check == NULL) || (comp == NULL)) return (-1); - if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { - xmlGenericError(xmlGenericErrorContext, - "Relax-NG types library '%s' already registered\n", - namespace); + if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) return (-1); - } lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); if (lib == NULL) { - xmlRngVErrMemory(NULL, "adding types library\n"); + xmlRngVErrMemory(NULL); return (-1); } memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); @@ -2803,9 +2759,6 @@ xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, lib->freef = freef; ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); if (ret < 0) { - xmlGenericError(xmlGenericErrorContext, - "Relax-NG types library failed to register '%s'\n", - namespace); xmlRelaxNGFreeTypeLibrary(lib, namespace); return (-1); } @@ -2825,11 +2778,8 @@ xmlRelaxNGInitTypes(void) if (xmlRelaxNGTypeInitialized != 0) return (0); xmlRelaxNGRegisteredTypes = xmlHashCreate(10); - if (xmlRelaxNGRegisteredTypes == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Failed to allocate sh table for Relax-NG types\n"); + if (xmlRelaxNGRegisteredTypes == NULL) return (-1); - } xmlRelaxNGRegisterTypeLibrary(BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes", NULL, xmlRelaxNGSchemaTypeHave, @@ -2875,10 +2825,6 @@ xmlRelaxNGCleanupTypes(void) * * ************************************************************************/ -/* from automata.c but not exported */ -void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); - - static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def); @@ -2937,21 +2883,6 @@ xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def) } if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) def->dflags |= IS_COMPILABLE; -#ifdef DEBUG_COMPILE - if (ret == 1) { - xmlGenericError(xmlGenericErrorContext, - "element content for %s is compilable\n", - def->name); - } else if (ret == 0) { - xmlGenericError(xmlGenericErrorContext, - "element content for %s is not compilable\n", - def->name); - } else { - xmlGenericError(xmlGenericErrorContext, - "Problem in RelaxNGIsCompilable for element %s\n", - def->name); - } -#endif } /* * All elements return a compilable status unless they @@ -3013,21 +2944,6 @@ xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def) def->dflags |= IS_NOT_COMPILABLE; if (ret == 1) def->dflags |= IS_COMPILABLE; -#ifdef DEBUG_COMPILE - if (ret == 1) { - xmlGenericError(xmlGenericErrorContext, - "RelaxNGIsCompilable %s : true\n", - xmlRelaxNGDefName(def)); - } else if (ret == 0) { - xmlGenericError(xmlGenericErrorContext, - "RelaxNGIsCompilable %s : false\n", - xmlRelaxNGDefName(def)); - } else { - xmlGenericError(xmlGenericErrorContext, - "Problem in RelaxNGIsCompilable %s\n", - xmlRelaxNGDefName(def)); - } -#endif return (ret); } @@ -3113,11 +3029,6 @@ xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) xmlAutomataSetFinalState(ctxt->am, ctxt->state); def->contModel = xmlAutomataCompile(ctxt->am); if (!xmlRegexpIsDeterminist(def->contModel)) { -#ifdef DEBUG_COMPILE - xmlGenericError(xmlGenericErrorContext, - "Content model not determinist %s\n", - def->name); -#endif /* * we can only use the automata if it is determinist */ @@ -3282,24 +3193,6 @@ xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { ctxt->am = NULL; ret = xmlRelaxNGCompile(ctxt, def); -#ifdef DEBUG_PROGRESSIVE - if (ret == 0) { - if (def->type == XML_RELAXNG_START) - xmlGenericError(xmlGenericErrorContext, - "compiled the start\n"); - else - xmlGenericError(xmlGenericErrorContext, - "compiled element %s\n", def->name); - } else { - if (def->type == XML_RELAXNG_START) - xmlGenericError(xmlGenericErrorContext, - "failed to compile the start\n"); - else - xmlGenericError(xmlGenericErrorContext, - "failed to compile element %s\n", - def->name); - } -#endif return (ret); } } @@ -3848,7 +3741,8 @@ xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, else if (ret == 1) ret = 0; } else { - TODO ret = 0; + /* TODO */ + ret = 0; } if (ret == 0) return (ret); @@ -3879,7 +3773,8 @@ xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, ret = 1; } } else { - TODO ret = 0; + /* TODO */ + ret = 0; } return (ret); @@ -4036,7 +3931,7 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, ret = (xmlRelaxNGDefinePtr *) xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "getting element list\n"); + xmlRngPErrMemory(ctxt); return (NULL); } } else if (max <= len) { @@ -4046,7 +3941,7 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, temp = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr)); if (temp == NULL) { - xmlRngPErrMemory(ctxt, "getting element list\n"); + xmlRngPErrMemory(ctxt); xmlFree(ret); return (NULL); } @@ -4144,7 +4039,7 @@ xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, sizeof(xmlRelaxNGDefinePtr *)); if (list == NULL) { - xmlRngPErrMemory(ctxt, "building choice\n"); + xmlRngPErrMemory(ctxt); return; } i = 0; @@ -4281,7 +4176,7 @@ xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, sizeof(xmlRelaxNGDefinePtr *)); if (list == NULL) { - xmlRngPErrMemory(ctxt, "building group\n"); + xmlRngPErrMemory(ctxt); return; } i = 0; @@ -4359,19 +4254,12 @@ xmlRelaxNGComputeInterleaves(void *payload, void *data, if (ctxt->nbErrors != 0) return; -#ifdef DEBUG_INTERLEAVE - xmlGenericError(xmlGenericErrorContext, - "xmlRelaxNGComputeInterleaves(%s)\n", name); -#endif cur = def->content; while (cur != NULL) { nbchild++; cur = cur->next; } -#ifdef DEBUG_INTERLEAVE - xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); -#endif groups = (xmlRelaxNGInterleaveGroupPtr *) xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); if (groups == NULL) @@ -4390,9 +4278,6 @@ xmlRelaxNGComputeInterleaves(void *payload, void *data, nbgroups++; cur = cur->next; } -#ifdef DEBUG_INTERLEAVE - xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); -#endif /* * Let's check that all rules makes a partitions according to 7.4 @@ -4483,7 +4368,7 @@ xmlRelaxNGComputeInterleaves(void *payload, void *data, return; error: - xmlRngPErrMemory(ctxt, "in interleave computation\n"); + xmlRngPErrMemory(ctxt); if (groups != NULL) { for (i = 0; i < nbgroups; i++) if (groups[i] != NULL) { @@ -4521,7 +4406,7 @@ xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) if (ctxt->interleaves == NULL) ctxt->interleaves = xmlHashCreate(10); if (ctxt->interleaves == NULL) { - xmlRngPErrMemory(ctxt, "create interleaves\n"); + xmlRngPErrMemory(ctxt); } else { char name[32]; @@ -5019,11 +4904,6 @@ xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) xmlRelaxNGGrammarPtr grammar, old; xmlRelaxNGGrammarPtr oldparent; -#ifdef DEBUG_GRAMMAR - xmlGenericError(xmlGenericErrorContext, - "Found pattern\n"); -#endif - oldparent = ctxt->parentgrammar; old = ctxt->grammar; ctxt->parentgrammar = old; @@ -5393,7 +5273,7 @@ xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, if (tmp != NULL) { if (last == NULL) { last = tmp; - } else { + } else if (tmp != ret) { last->next = tmp; last = tmp; } @@ -5809,11 +5689,6 @@ xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name) cur = cur->nextHash; } -#ifdef DEBUG - xmlGenericError(xmlGenericErrorContext, - "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", - name, choiceOrInterleave); -#endif if (choiceOrInterleave == -1) choiceOrInterleave = 0; cur = xmlRelaxNGNewDefine(ctxt, define->node); @@ -5939,11 +5814,6 @@ xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, cur = cur->next; } -#ifdef DEBUG - xmlGenericError(xmlGenericErrorContext, - "xmlRelaxNGCombineStart(): merging : %d\n", - choiceOrInterleave); -#endif if (choiceOrInterleave == -1) choiceOrInterleave = 0; cur = xmlRelaxNGNewDefine(ctxt, starts->node); @@ -6609,10 +6479,6 @@ xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) { xmlRelaxNGGrammarPtr ret, tmp, old; -#ifdef DEBUG_GRAMMAR - xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n"); -#endif - ret = xmlRelaxNGNewGrammar(ctxt); if (ret == NULL) return (NULL); @@ -6741,11 +6607,6 @@ xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); } } -#ifdef DEBUG - if (schema == NULL) - xmlGenericError(xmlGenericErrorContext, - "xmlRelaxNGParseDocument() failed\n"); -#endif return (schema); } @@ -6776,13 +6637,11 @@ xmlRelaxNGNewParserCtxt(const char *URL) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); ret->URL = xmlStrdup((const xmlChar *) URL); - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; return (ret); } @@ -6807,14 +6666,12 @@ xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); ret->buffer = buffer; ret->size = size; - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; return (ret); } @@ -6843,7 +6700,7 @@ xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); xmlFreeDoc(copy); return (NULL); } @@ -7525,7 +7382,7 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) * First step is to parse the input document into an DOM/Infoset */ if (ctxt->URL != NULL) { - doc = xmlReadFile((const char *) ctxt->URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) ctxt->URL); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNGParse: could not load %s\n", ctxt->URL, @@ -7533,7 +7390,7 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) return (NULL); } } else if (ctxt->buffer != NULL) { - doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); + doc = xmlRelaxReadMemory(ctxt, ctxt->buffer, ctxt->size); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNGParse: could not parse schemas\n", NULL, @@ -7644,6 +7501,8 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) * @warn: the warning callback * @ctx: contextual data for the callbacks * + * DEPRECATED: Use xmlRelaxNGSetParserStructuredErrors. + * * Set the callback functions used to handle errors for a validation context */ void @@ -7838,11 +7697,13 @@ xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) break; case XML_RELAXNG_DATATYPE: case XML_RELAXNG_VALUE: - TODO break; + /* TODO */ + break; case XML_RELAXNG_START: case XML_RELAXNG_EXCEPT: case XML_RELAXNG_PARAM: - TODO break; + /* TODO */ + break; case XML_RELAXNG_NOOP: xmlRelaxNGDumpDefines(output, define->content); break; @@ -7971,10 +7832,6 @@ xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, 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; @@ -7987,12 +7844,7 @@ xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, 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) { + 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; @@ -8119,7 +7971,7 @@ xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) sizeof (xmlRegExecCtxtPtr)); if (ctxt->elemTab == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } } @@ -8130,7 +7982,7 @@ xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) sizeof (xmlRegExecCtxtPtr)); if (ctxt->elemTab == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } } @@ -8186,10 +8038,6 @@ xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec 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; @@ -8205,13 +8053,7 @@ xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ctxt->pstate = -1; return; } - if ((ctxt == NULL) || (define == NULL)) { - fprintf(stderr, "callback on %s missing info\n", token); - if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) - ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; - ctxt->pstate = -1; - return; - } else if (define->type != XML_RELAXNG_ELEMENT) { + if (define->type != XML_RELAXNG_ELEMENT) { fprintf(stderr, "callback on %s define is not element\n", token); if (ctxt->errNo == XML_RELAXNG_OK) ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; @@ -8229,11 +8071,6 @@ xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec /* * 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; @@ -8330,9 +8167,6 @@ xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, 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; @@ -8381,11 +8215,6 @@ xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, else ret = 1; } -#ifdef DEBUG_PROGRESSIVE - if (ret < 0) - xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n", - elem->name); -#endif return (ret); } @@ -8408,10 +8237,6 @@ xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, 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; @@ -8423,9 +8248,6 @@ xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, 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); } @@ -8452,9 +8274,6 @@ xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, 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. */ @@ -8472,11 +8291,6 @@ xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, ret = 1; } xmlRegFreeExecCtxt(exec); -#ifdef DEBUG_PROGRESSIVE - if (ret < 0) - xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n", - elem->name); -#endif return (ret); } @@ -8501,9 +8315,6 @@ xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, 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); @@ -8518,11 +8329,6 @@ xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, 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); } @@ -8588,9 +8394,9 @@ xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str) tmp++; len = tmp - str; - ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); + ret = (xmlChar *) xmlMallocAtomic(len + 1); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (NULL); } p = ret; @@ -8852,10 +8658,6 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 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; @@ -8872,20 +8674,11 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 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)) @@ -8898,16 +8691,8 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 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; } @@ -9022,7 +8807,8 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, } break; default: - TODO ret = -1; + /* TODO */ + ret = -1; } return (ret); } @@ -9110,7 +8896,9 @@ xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, } return (0); } else { - TODO} + /* TODO */ + return (0); + } return (1); } @@ -9171,11 +8959,6 @@ xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, } 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]; @@ -9208,17 +8991,6 @@ xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, } 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); @@ -9378,13 +9150,13 @@ xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, */ list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); if (list == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } memset(list, 0, nbgroups * sizeof(xmlNodePtr)); lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); if (lasts == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); @@ -9761,7 +9533,8 @@ xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, ctxt->flags = oldflags; } } else { - TODO ret = -1; + /* TODO */ + ret = -1; } return (ret); } @@ -9900,18 +9673,6 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, } 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: @@ -10030,11 +9791,6 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, 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; @@ -10152,21 +9908,6 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, 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; @@ -10503,7 +10244,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10546,7 +10287,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10597,7 +10338,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10621,22 +10362,11 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, } case XML_RELAXNG_EXCEPT: case XML_RELAXNG_PARAM: - TODO ret = -1; + /* 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, "succeeded\n"); - else - xmlGenericError(xmlGenericErrorContext, "failed\n"); -#endif return (ret); } @@ -10660,7 +10390,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, * We should NOT have both ctxt->state and ctxt->states */ if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } @@ -10672,7 +10403,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, } ret = xmlRelaxNGValidateState(ctxt, define); if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { @@ -10697,7 +10429,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, * We should NOT have both ctxt->state and ctxt->states */ if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } if (ret == 0) { @@ -10763,7 +10496,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, } } if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } return (ret); @@ -10835,23 +10569,22 @@ xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) } 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 (ctxt->error == NULL) { + vctxt.error = xmlGenericError; + vctxt.warning = xmlGenericError; + vctxt.userData = xmlGenericErrorContext; + } else { + vctxt.error = ctxt->error; + vctxt.warning = ctxt->warning; + vctxt.userData = ctxt->userData; + } if (xmlValidateDocumentFinal(&vctxt, doc) != 1) ret = -1; @@ -10938,13 +10671,11 @@ xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); if (ret == NULL) { - xmlRngVErrMemory(NULL, "building context\n"); + xmlRngVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); ret->schema = schema; - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; ret->errNr = 0; ret->errMax = 0; ret->err = NULL; @@ -11007,6 +10738,8 @@ xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) * @warn: the warning function * @ctx: the functions context * + * DEPRECATED: Use xmlRelaxNGSetValidStructuredErrors. + * * Set the error and warning callback information */ void diff --git a/rngparser.c b/rngparser.c new file mode 100644 index 00000000000..799a60e6347 --- /dev/null +++ b/rngparser.c @@ -0,0 +1,1588 @@ +/** + * rngparser.c: parser for the Relax-NG compact syntax. + * + * Based on: + * RELAX NG Compact Syntax + * Committee Specification 21 November 2002 + * http://www.oasis-open.org/committees/relax-ng/compact-20021121.html + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +#include + +#include +#include +#include +#include + +#define MAX_TOKEN 10 + +typedef enum { + CRNG_NONE = 0, + CRNG_OP = 1, + CRNG_KEYWORD, + CRNG_IDENTIFIER, + CRNG_LITERAL_SEGMENT, + CRNG_CNAME, + CRNG_QNAME, + CRNG_NSNAME, + CRNG_DOCUMENTATION +} xmlCRNGTokType; + +typedef enum { + CRNG_OKAY = 0, + CRNG_MEMORY_ERROR, + CRNG_INVALID_CHAR_ERROR, + CRNG_END_ERROR, + CRNG_ENCODING_ERROR +} xmlCRNGError; + +typedef enum { + XML_CRNG_ERROR = -1, + XML_CRNG_OK = 0, + XML_CRNG_EOF = 1 +} xmlCRelaxNGParserState; + +typedef struct _token _token; +typedef _token *tokenPtr; +struct _token { + xmlCRNGTokType toktype; + int toklen; + const xmlChar *token; + const xmlChar *prefix; +}; + +typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt; +typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr; +struct _xmlCRelaxNGParserCtxt { + void *userData; /* user specific data block */ + xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ + xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */ + xmlRelaxNGValidErr err; + + const xmlChar *compact; + const xmlChar *end; + const xmlChar *cur; + int isElem; + int lineno; + const xmlChar *linestart; + const char *filename; + + int nbTokens; + int firstToken; + _token tokens[MAX_TOKEN]; + int totalToken; + + xmlCRelaxNGParserState state; + + int nbErrors; + + xmlDocPtr res; /* the result */ + xmlNodePtr ins; /* the current insertion node */ + + xmlNsPtr nsDef; + tokenPtr token; + + xmlHashTablePtr namespaces; + xmlHashTablePtr datatypes; + + /* + * dictionary and keywords + */ + xmlDictPtr dict; + const xmlChar *key_attribute; + const xmlChar *key_default; + const xmlChar *key_datatypes; + const xmlChar *key_div; + const xmlChar *key_element; + const xmlChar *key_empty; + const xmlChar *key_external; + const xmlChar *key_grammar; + const xmlChar *key_include; + const xmlChar *key_inherit; + const xmlChar *key_list; + const xmlChar *key_mixed; + const xmlChar *key_namespace; + const xmlChar *key_notAllowed; + const xmlChar *key_parent; + const xmlChar *key_start; + const xmlChar *key_string; + const xmlChar *key_text; + const xmlChar *key_token; + const xmlChar *key_equal; + const xmlChar *key_orequal; + const xmlChar *key_andequal; + const xmlChar *key_combine; + const xmlChar *key_or; + const xmlChar *key_comma; + const xmlChar *key_and; + const xmlChar *key_choice; + const xmlChar *key_group; + const xmlChar *key_interleave; + const xmlChar *key_ref; + const xmlChar *key_define; + + /* results */ + xmlDocPtr doc; /* the resulting doc */ + xmlNodePtr insert; /* the insertion point */ + xmlAttrPtr attrs; /* pending attributes */ +}; + +static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string"; +static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string"; + +#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) +/** + * IS_BLANK: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [3] S ::= (#x20 | #x9 | #xD | #xA)+ + */ +#ifndef IS_BLANK +#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ + ((c) == 0x0D)) +#endif +#define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ + ((c) == 0x0D) || (c == '#')) + +#define CRNG_ERROR0(X) \ + { xmlCRNGErr(ctxt, X, NULL); return(0); } +#define CRNG_ERROR(X) \ + { xmlCRNGErr(ctxt, X, NULL); } + +#define CRNG_MEM_ERROR0() \ + { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); } +#define CRNG_MEM_ERROR() \ + { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); } + +#define ERROR(str) xmlCRNGErr(ctxt, 0, str); + +static void +xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) { + const xmlChar *cur; + xmlChar buffer[150]; + int i, l; + + if (ctxt != NULL) { + if (ctxt->filename != NULL) + fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno); + } + if (err_msg != NULL) { + fprintf(stderr, "error: %s\n", err_msg); + } else if (err_no != 0) + fprintf(stderr, "error %d\n", err_no); + cur = ctxt->cur; + while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--; + l = ctxt->cur - cur; + cur++; + for (i = 0; i < 100;i++) { + if ((*cur == '\n') || (*cur == '\r')) break; + buffer[i] = *cur++; + } + buffer[i] = 0; + fprintf(stderr, "%s\n", buffer); + for (i = 0; i < l;i++) buffer[i] = ' '; + buffer[i++] = '^'; + buffer[i++] = 0; + fprintf(stderr, "%s\n", buffer); +} + +/** + * IS_OP + * @c: an UNICODE value (int) + * + * Macro to check for operator value + */ +#ifndef IS_OP +#define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') || \ + ((c) == '?') || ((c) == '-') || ((c) == '*') || \ + ((c) == '{') || ((c) == '}') || ((c) == '(') || \ + ((c) == ')') || ((c) == '+') || ((c) == '=') || \ + ((c) == ':')) +#endif + +static int +xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) { + if ((str == ctxt->key_attribute) || + (str == ctxt->key_default) || + (str == ctxt->key_datatypes) || + (str == ctxt->key_div) || + (str == ctxt->key_element) || + (str == ctxt->key_empty) || + (str == ctxt->key_external) || + (str == ctxt->key_grammar) || + (str == ctxt->key_include) || + (str == ctxt->key_inherit) || + (str == ctxt->key_list) || + (str == ctxt->key_mixed) || + (str == ctxt->key_namespace) || + (str == ctxt->key_notAllowed) || + (str == ctxt->key_parent) || + (str == ctxt->key_start) || + (str == ctxt->key_string) || + (str == ctxt->key_text) || + (str == ctxt->key_token)) + return(1); + return(0); + +} + +/* + * xmlCRNGNextToken: + * ctxt: a compact RNG parser context + * + * Scan the schema to get the next token + * + * Return 0 if success and -1 in case of error + */ + +static int +xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) { + const xmlChar *cur; + tokenPtr token; + + if (ctxt == NULL) return(-1); + if (ctxt->nbTokens >= MAX_TOKEN) return(-1); + token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]); + token->toktype = CRNG_NONE; + + if (ctxt->cur == NULL) { + ctxt->cur = ctxt->compact; + } +retry: + if (ctxt->cur >= ctxt->end) { + ctxt->state = XML_CRNG_EOF; + return(-1); + } + while ((ctxt->cur < ctxt->end) && + (IS_BLANK(*ctxt->cur))) ctxt->cur++; + if (ctxt->cur >= ctxt->end) { + ctxt->state = XML_CRNG_EOF; + return(-1); + } + if (*ctxt->cur == '#') { + cur = ctxt->cur; + cur++; + while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r')) + cur++; + ctxt->cur = cur; + goto retry; + } else if (*ctxt->cur == '"') { + /* string, check for '"""' */ + ctxt->cur++; + if (ctxt->cur >= ctxt->end) goto eof; + cur = ctxt->cur; + if ((ctxt->end - ctxt->end > 2) && + (*cur == '"') && (cur[1] == '"')) { + /* TODO */ + } else { + while ((cur < ctxt->end) && (*cur != '"')) cur++; + if (cur >= ctxt->end) goto eof; + token->toklen = cur - ctxt->cur; + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); + token->toktype = CRNG_LITERAL_SEGMENT; + token->prefix = NULL; + cur++; + ctxt->cur = cur; + } + } else if (*ctxt->cur == '\'') { + /* string, check for "'''" */ + /* TODO */ + } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) { + cur = ctxt->cur; + cur++; + if ((cur < ctxt->end) && + (((*cur == '=') && + ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) || + ((*cur == '*') && (*ctxt->cur == ':')))) { + token->toklen = 2; + } else { + token->toklen = 1; + } + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); + token->toktype = CRNG_OP; + token->prefix = NULL; + ctxt->cur += token->toklen; + } else { + int escape = 0; + + cur = ctxt->cur; + if (*cur == '\\') { + escape = 1; + cur++; + ctxt->cur++; + } + while ((cur < ctxt->end) && + (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; + + token->toklen = cur - ctxt->cur; + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); + token->prefix = NULL; + ctxt->cur = cur; + if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token))) + token->toktype = CRNG_KEYWORD; + else { + token->toktype = CRNG_IDENTIFIER; + } + if (*ctxt->cur == ':') { + ctxt->cur++; + if (*ctxt->cur == '*') { + ctxt->cur++; + token->toktype = CRNG_NSNAME; + } else { + cur = ctxt->cur; + while ((cur < ctxt->end) && + (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; + token->prefix = token->token; + token->toklen = cur - ctxt->cur; + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, + token->toklen); + ctxt->cur = cur; + if (xmlValidateNCName(token->token, 0) == 0) + token->toktype = CRNG_QNAME; + else { + /* TODO: sounds like an error ! */ + token->toktype = CRNG_IDENTIFIER; + } + } + } + } + ctxt->nbTokens++; + return(0); +eof: + ctxt->state = XML_CRNG_EOF; + CRNG_ERROR(CRNG_END_ERROR); + return(-1); +} + +/** + * xmlParseCRNGGetToken: + * @ctxt: a compact RNG parser context + * @no: the number of the token from 1 for the first one + * and 2, 3 ... for read-ahead + * + * Token reading interface + * + * returns a pointer to the new token, or NULL in case of error or EOF + */ +static tokenPtr +xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) { + tokenPtr ret; + int res; + + if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL); + no--; + while (ctxt->nbTokens <= no) { + res = xmlCRNGNextToken(ctxt); + if (res < 0) + return(NULL); + } + ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]); + return(ret); +} + +/** + * xmlParseCRNGDropTokens: + * @ctxt: a compact RNG parser context + * @nr: the number of token marked as read + * + * mark a number of token as read and consumed. + * + * Returns -1 in case of error and 0 otherwise + */ +static int +xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) { + if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1); + while ((ctxt->nbTokens >0) && (nr > 0)) { + ctxt->firstToken++; + nr--; + ctxt->nbTokens--; + ctxt->totalToken++; + if (ctxt->totalToken == 384) + fprintf(stderr, "found\n"); + } + ctxt->firstToken = ctxt->firstToken % MAX_TOKEN; + return(0); +} + +static void +xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) { + tokenPtr token; + + token = xmlParseCRNGGetToken(ctxt, 1); + while (token != NULL) { + switch (token->toktype) { + case CRNG_NONE: printf("none"); break; + case CRNG_OP: printf("op"); break; + case CRNG_KEYWORD: printf("keyword"); break; + case CRNG_IDENTIFIER: printf("identifier"); break; + case CRNG_LITERAL_SEGMENT: printf("literal"); break; + case CRNG_CNAME: printf("cname"); break; + case CRNG_QNAME: printf("qname"); break; + case CRNG_NSNAME: printf("nsname"); break; + case CRNG_DOCUMENTATION: printf("doc"); break; + } + printf(":%s\n", token->token); + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + } +} + +/** + * xmlParseCRNG_attribute: + * @ctxt: a compact RNG parser context + * @name: the attribute name + * @ns: the attribute namespace + * @value: the attribute value + * + * implements attribute of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt, + const xmlChar *name, + xmlNsPtr ns, + const xmlChar *value) +{ + xmlAttrPtr attr; + + attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value); + if (attr == NULL) CRNG_MEM_ERROR0(); + attr->next = ctxt->attrs; + if (ctxt->attrs != NULL) + ctxt->attrs->prev = attr; + ctxt->attrs = attr; + return(0); +} + +/** + * xmlParseCRNG_bindPrefix: + * @ctxt: a compact RNG parser context + * @prefix: the namespace prefix or NULL + * @namespace: the namespace name + * + * implements bindPrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt, + const xmlChar *prefix, + const xmlChar *namespace) +{ + int ret; + + if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")) && + (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) { + ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\""); + return(-1); + } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) && + (!xmlStrEqual(prefix, BAD_CAST "xml"))) { + ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix"); + return(-1); + } + if (ctxt->namespaces == NULL) + ctxt->namespaces = xmlHashCreate(10); + if (ctxt->namespaces == NULL) { + ERROR("Failed to create namespace hash table"); + return(-1); + } + if (prefix == NULL) + ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault, + (void *) namespace); + else + ret = xmlHashAddEntry(ctxt->namespaces, prefix, + (void *) namespace); + if (ret < 0) { + if (prefix == NULL) { + ERROR("Redefinition of default namespace"); + } else { + ERROR("Redefinition of namespace"); + } + return(-1); + } + + return(0); +} + +/** + * xmlParseCRNG_bindDatatypePrefix: + * @ctxt: a compact RNG parser context + * @prefix: the datatype prefix + * @namespace: the datatype identifier + * + * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *prefix, + const xmlChar *namespace) +{ + int ret; + + if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd")) && + (!xmlStrEqual(namespace, + BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) { + ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\""); + return(-1); + } + if (ctxt->datatypes == NULL) + ctxt->datatypes = xmlHashCreate(10); + if (ctxt->datatypes == NULL) { + ERROR("Failed to create namespace hash table"); + return(-1); + } + ret = xmlHashAddEntry(ctxt->datatypes, prefix, + (void *) namespace); + if (ret < 0) { + ERROR("Redefinition of datatype"); + return(-1); + } + return(0); +} + +/** + * xmlParseCRNG_lookupPrefix: + * @ctxt: a compact RNG parser context + * @prefix: the namespace prefix or NULL + * + * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns the prefix in case of success or NULL in case of error + */ +static const xmlChar * +xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *prefix) +{ + const xmlChar *ret; + + if (prefix == NULL) + ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault); + else + ret = xmlHashLookup(ctxt->namespaces, prefix); + return(ret); +} + +/** + * xmlParseCRNG_lookupDatatypePrefix: + * @ctxt: a compact RNG parser context + * @prefix: the namespace prefix or NULL + * + * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns the prefix in case of success or NULL in case of error + */ +static const xmlChar * +xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *prefix) +{ + const xmlChar *ret; + ret = xmlHashLookup(ctxt->datatypes, prefix); + return(ret); +} + +/** + * xmlParseCRNG_datatypeAttributes: + * @ctxt: a compact RNG parser context + * @prefix: the namespace prefix or NULL + * + * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns the prefix in case of success or NULL in case of error + */ +static xmlAttrPtr +xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *library, const xmlChar *type) +{ + xmlAttrPtr lib, typ; + + lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library); + if (lib == NULL) { + CRNG_MEM_ERROR(); + return(NULL); + } + typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type); + if (typ == NULL) { + CRNG_MEM_ERROR(); + return(lib); + } + lib->next = typ; + + return(lib); +} + +/** + * xmlParseCRNG_XXX: + * @ctxt: a compact RNG parser context + * + * Parse XXX of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + return(0); +} + +static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt); +static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt); + +/** + * xmlParseCRNG_params: + * @ctxt: a compact RNG parser context + * + * Parse params of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + /* TODO */ + return(0); +} + +/** + * xmlParseCRNG_exceptNameClass: + * @ctxt: a compact RNG parser context + * + * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + tokenPtr token; + xmlNodePtr insert = ctxt->insert, cur; + + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype == CRNG_OP) && + (token->token[0] == '-') && (token->token[1] == 0)) { + xmlParseCRNGDropTokens(ctxt, 1); + cur = xmlNewNode(NULL, BAD_CAST "except"); + if (cur == NULL) CRNG_MEM_ERROR0(); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, cur); + ctxt->insert = cur; + xmlParseCRNG_nameClass(ctxt); + } + ctxt->insert = insert; + return(0); +} + +/** + * xmlParseCRNG_innerNameClass: + * @ctxt: a compact RNG parser context + * + * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + xmlNodePtr cur; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_OP) { + if ((token->token[0] == '(') && (token->token[1] == 0)) { + xmlParseCRNGDropTokens(ctxt, 1); + xmlParseCRNG_nameClass(ctxt); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != ')') || (token->token[1] != 0)) { + ERROR("Expecting \")\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + } else if ((token->token[0] == '*') && (token->token[1] == 0)) { + xmlParseCRNGDropTokens(ctxt, 1); + cur = xmlNewNode(NULL, BAD_CAST "anyName"); + if (cur == NULL) CRNG_MEM_ERROR0(); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, cur); + ctxt->insert = cur; + xmlParseCRNG_exceptNameClass(ctxt); + } else { + /* TODO */ + } + } else if ((token->toktype == CRNG_IDENTIFIER) || + (token->toktype == CRNG_KEYWORD)) { + cur = xmlNewNode(NULL, BAD_CAST "name"); + if (cur == NULL) CRNG_MEM_ERROR0(); + if (ctxt->isElem) { + xmlSetProp(cur, BAD_CAST "ns", + xmlParseCRNG_lookupPrefix(ctxt, NULL)); + } else { + xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); + } + xmlNodeAddContent(cur, token->token); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, cur); + ctxt->insert = cur; + xmlParseCRNGDropTokens(ctxt, 1); + } else if (token->toktype == CRNG_CNAME) { + /* TODO */ + } else if (token->toktype == CRNG_NSNAME) { + cur = xmlNewNode(NULL, BAD_CAST "nsName"); + if (cur == NULL) CRNG_MEM_ERROR0(); + xmlSetProp(cur, BAD_CAST "ns", + xmlParseCRNG_lookupPrefix(ctxt, token->token)); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, cur); + ctxt->insert = cur; + xmlParseCRNGDropTokens(ctxt, 1); + xmlParseCRNG_exceptNameClass(ctxt); + } else { + /* TODO: probably an error */ + } + + return(0); +} + +/** + * xmlParseCRNG_nameClass: + * @ctxt: a compact RNG parser context + * + * Parse nameClass of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + xmlNodePtr insert = ctxt->insert, last, choice; + + ctxt->insert = NULL; + xmlParseCRNG_innerNameClass(ctxt); + last = ctxt->insert; + token = xmlParseCRNGGetToken(ctxt, 1); + while ((token->toktype == CRNG_OP) && + (token->token[0] == '|') && (token->token[1] == 0)) { + choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); + xmlParseCRNGDropTokens(ctxt, 1); + if (choice == NULL) CRNG_MEM_ERROR0(); + ctxt->insert = NULL; + xmlParseCRNG_innerNameClass(ctxt); + xmlAddChild(choice, last); + xmlAddChild(choice, ctxt->insert); + last = choice; + token = xmlParseCRNGGetToken(ctxt, 1); + } + xmlAddChild(insert, last); + + ctxt->insert = insert; + return(0); +} + +/** + * xmlParseCRNG_patternBlock: + * @ctxt: a compact RNG parser context + * + * Parse a pattern block of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != '{') || (token->token[1] != 0)) { + ERROR("Expecting \"{\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + xmlParseCRNG_pattern(ctxt); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != '}') || (token->token[1] != 0)) { + ERROR("Expecting \"}\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + return(0); +} + +/** + * xmlParseCRNG_datatype: + * @ctxt: a compact RNG parser context + * + * Parse datatype of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + tokenPtr token; + xmlAttrPtr attrs = NULL; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_KEYWORD) { + if (token->token == ctxt->key_string) { + attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", + token->token); + xmlParseCRNGDropTokens(ctxt, 1); + } else if (token->token == ctxt->key_token) { + attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", + token->token); + xmlParseCRNGDropTokens(ctxt, 1); + } else { + /* TODO: probably an error */ + } + } else if (token->toktype == CRNG_LITERAL_SEGMENT) { + ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + xmlNodeAddContent(ctxt->insert, token->token); + } else if (token->toktype == CRNG_QNAME) { + attrs = xmlParseCRNG_datatypeAttributes(ctxt, + xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix), + token->token); + } else { + /* TODO */ + } + if (attrs != NULL) { + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_LITERAL_SEGMENT) { + ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) { + xmlFreePropList(attrs); + CRNG_MEM_ERROR0(); + } + ctxt->insert->properties = attrs; + xmlNodeAddContent(ctxt->insert, token->token); + } else if ((token->toktype == CRNG_OP) && + (token->token[0] == '{') && (token->token[0] == 0)) { + ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) { + xmlFreePropList(attrs); + CRNG_MEM_ERROR0(); + } + ctxt->insert->properties = attrs; + xmlParseCRNG_params(ctxt); + } else { + ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) { + xmlFreePropList(attrs); + CRNG_MEM_ERROR0(); + } + ctxt->insert->properties = attrs; + xmlNodeAddContent(ctxt->insert, token->token); + } + } + return(0); +} + +/** + * xmlParseCRNG_primary: + * @ctxt: a compact RNG parser context + * + * Parse primary of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + tokenPtr token; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token == NULL) + return(0); + if (token->toktype == CRNG_KEYWORD) { + if (token->token == ctxt->key_element) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + ctxt->isElem = 1; + xmlParseCRNG_nameClass(ctxt); + xmlParseCRNG_patternBlock(ctxt); + } else if (token->token == ctxt->key_attribute) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + ctxt->isElem = 0; + xmlParseCRNG_nameClass(ctxt); + xmlParseCRNG_patternBlock(ctxt); + } else if (token->token == ctxt->key_mixed) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + xmlParseCRNG_patternBlock(ctxt); + } else if (token->token == ctxt->key_list) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + xmlParseCRNG_patternBlock(ctxt); + } else if (token->token == ctxt->key_empty) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + } else if (token->token == ctxt->key_notAllowed) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + } else if (token->token == ctxt->key_text) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + } else if (token->token == ctxt->key_parent) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + /* TODO */ + } else if (token->token == ctxt->key_grammar) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + /* TODO */ + } else if (token->token == ctxt->key_external) { + ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef"); + xmlParseCRNGDropTokens(ctxt, 1); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + /* TODO */ + } else { + /* TODO */ + } + } else if (token->toktype == CRNG_IDENTIFIER) { + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref); + if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); + xmlSetProp(ctxt->insert, BAD_CAST "name", token->token); + xmlParseCRNGDropTokens(ctxt, 1); + } else if (token->toktype == CRNG_QNAME) { + xmlParseCRNG_datatype(ctxt); + } else if (token->toktype == CRNG_LITERAL_SEGMENT) { + xmlParseCRNG_datatype(ctxt); + } else if ((token->toktype == CRNG_OP) && + (token->token[0] == '(') && (token->token[1] == 0)) { + xmlParseCRNGDropTokens(ctxt, 1); + xmlParseCRNG_pattern(ctxt); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != ')') || (token->token[1] != 0)) { + ERROR("Expecting \")\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + } + return(0); +} + +/** + * xmlParseCRNG_particle: + * @ctxt: a compact RNG parser context + * + * Parse particle of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + xmlNodePtr insert = ctxt->insert, res, tmp = NULL; + + ctxt->insert = NULL; + xmlParseCRNG_primary(ctxt); + res = ctxt->insert; + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token != NULL) && (token->toktype == CRNG_OP)) { + if ((token->token[0] == '*') && (token->token[1] == 0)) { + tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore"); + if (tmp == NULL) CRNG_MEM_ERROR0(); + } else if ((token->token[0] == '+') && (token->token[1] == 0)) { + tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore"); + if (tmp == NULL) CRNG_MEM_ERROR0(); + } else if ((token->token[0] == '?') && (token->token[1] == 0)) { + tmp = xmlNewNode(NULL, BAD_CAST "optional"); + if (tmp == NULL) CRNG_MEM_ERROR0(); + } + if (tmp != NULL) { + xmlAddChild(tmp, res); + res = tmp; + xmlParseCRNGDropTokens(ctxt, 1); + } + } + if (insert != NULL) { + xmlAddChild(insert, res); + ctxt->insert = insert; + } else + ctxt->insert = res; + return(0); +} + +/** + * xmlParseCRNG_pattern: + * @ctxt: a compact RNG parser context + * + * Parse pattern of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + xmlNodePtr insert = ctxt->insert, prev, grp; + + ctxt->insert = NULL; + xmlParseCRNG_particle(ctxt); + prev = ctxt->insert; + token = xmlParseCRNGGetToken(ctxt, 1); + while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) { + if (token->token == ctxt->key_or) { + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); + if (grp == NULL) CRNG_MEM_ERROR0(); + } else if (token->token == ctxt->key_and) { + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave); + if (grp == NULL) CRNG_MEM_ERROR0(); + } else if (token->token == ctxt->key_comma) { + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group); + if (grp == NULL) CRNG_MEM_ERROR0(); + } else + break; + xmlParseCRNGDropTokens(ctxt, 1); + ctxt->insert = NULL; + xmlParseCRNG_particle(ctxt); + xmlAddChild(grp, prev); + xmlAddChild(grp, ctxt->insert); + prev = grp; + token = xmlParseCRNGGetToken(ctxt, 1); + } + if (insert != NULL) { + xmlAddChild(insert, prev); + ctxt->insert = insert; + } else { + ctxt->insert = prev; + } + + return(0); +} + +/** + * xmlParseCRNG_component: + * @ctxt: a compact RNG parser context + * + * Parse component of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token, tok2; + xmlNodePtr insert = ctxt->insert; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token == NULL) + return(0); + if (token->toktype == CRNG_KEYWORD) { + if (token->token == ctxt->key_start) { + xmlNodePtr start; + + start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start); + if (start == NULL) CRNG_MEM_ERROR0(); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, start); + ctxt->insert = start; + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + + if ((token->toktype == CRNG_OP) && + (token->token == ctxt->key_equal)) { + } else if ((token->toktype == CRNG_OP) && + (token->token == ctxt->key_orequal)) { + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, + BAD_CAST "choice"); + } else if ((token->toktype == CRNG_OP) && + (token->token == ctxt->key_andequal)) { + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, + BAD_CAST "interleave"); + } else { + ERROR("expecting \"=\" or \"&=\" or \"|=\" here") + return(-1); + } + start->properties = ctxt->attrs; + ctxt->attrs = NULL; + xmlParseCRNGDropTokens(ctxt, 1); + xmlParseCRNG_pattern(ctxt); + + } else if (token->token == ctxt->key_include) { + /* TODO */ + } else if (token->token == ctxt->key_div) { + /* TODO */ + } else { + return(-1); + } + } else if (token->toktype == CRNG_IDENTIFIER) { + xmlNodePtr define; + const xmlChar *identifier; + + identifier = token->token; + tok2 = xmlParseCRNGGetToken(ctxt, 2); + if ((tok2->toktype == CRNG_OP) && + (tok2->token == ctxt->key_equal)) { + } else if ((tok2->toktype == CRNG_OP) && + (tok2->token == ctxt->key_orequal)) { + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, + BAD_CAST "choice"); + } else if ((tok2->toktype == CRNG_OP) && + (tok2->token == ctxt->key_andequal)) { + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, + BAD_CAST "interleave"); + } else { + ERROR("expecting \"=\" or \"&=\" or \"|=\" here") + return(-1); + } + xmlParseCRNGDropTokens(ctxt, 2); + + define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define); + if (define == NULL) CRNG_MEM_ERROR0(); + define->properties = ctxt->attrs; + ctxt->attrs = NULL; + xmlSetProp(define, BAD_CAST "name", identifier); + if (ctxt->insert != NULL) + xmlAddChild(ctxt->insert, define); + ctxt->insert = define; + xmlParseCRNG_pattern(ctxt); + } else { + return(-1); + } + ctxt->insert = insert; + return(0); +} + +/** + * xmlParseCRNG_grammar: + * @ctxt: a compact RNG parser context + * + * Parse grammar of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + tokenPtr token; + int ret; + + token = xmlParseCRNGGetToken(ctxt, 1); + while (token != NULL) { + ret = xmlParseCRNG_component(ctxt); + if (ret != 0) + break; + token = xmlParseCRNGGetToken(ctxt, 1); + } + return(0); +} + +/** + * xmlParseCRNG_topLevelBody: + * @ctxt: a compact RNG parser context + * + * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token, tok2; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_KEYWORD) { + if ((token->token == ctxt->key_start) || + (token->token == ctxt->key_include) || + (token->token == ctxt->key_div)) { + xmlNodePtr grammar; + + grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); + if (grammar == NULL) CRNG_MEM_ERROR0(); + xmlDocSetRootElement(ctxt->doc, grammar); + ctxt->insert = grammar; + + xmlParseCRNG_grammar(ctxt); + } else { + xmlParseCRNG_pattern(ctxt); + } + } else { + tok2 = xmlParseCRNGGetToken(ctxt, 2); + if ((tok2->toktype == CRNG_OP) && + ((tok2->token == ctxt->key_equal) || + (tok2->token == ctxt->key_orequal) || + (tok2->token == ctxt->key_andequal))) { + xmlNodePtr grammar; + + grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); + if (grammar == NULL) CRNG_MEM_ERROR0(); + xmlDocSetRootElement(ctxt->doc, grammar); + ctxt->insert = grammar; + + xmlParseCRNG_grammar(ctxt); + } else { + xmlParseCRNG_pattern(ctxt); + } + } + return(0); +} + +/** + * xmlParseCRNG_namespacePrefix: + * @ctxt: a compact RNG parser context + * + * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A + * + * Returns the prefix or NULL in case of error + */ +static const xmlChar * +xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + const xmlChar *prefix = NULL; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_IDENTIFIER) { + prefix = token->token; + } else if (token->toktype == CRNG_OP) { + if ((token->token[0] == '=') && (token->token[1] == 0)) + return(NULL); + prefix = token->token; + } else { + ERROR("Expecting a namespace prefix"); + return(NULL); + } + xmlParseCRNGDropTokens(ctxt, 1); + + if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { + ERROR("Namespace prefix \"xmlns\" is forbidden"); + } + return(prefix); +} + +/** + * xmlParseCRNG_decl: + * @ctxt: a compact RNG parser context + * + * Parse decl of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt) +{ + const xmlChar *prefix = NULL; + const xmlChar *namespace = NULL; + tokenPtr token; + + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype != CRNG_KEYWORD) return(-1); + if (token->token == ctxt->key_default) { + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_KEYWORD) || + (token->token != ctxt->key_namespace)) { + ERROR("Expecting keyword \"namespace\" after \"default\""); + } + xmlParseCRNGDropTokens(ctxt, 1); + prefix = xmlParseCRNG_namespacePrefix(ctxt); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != '=') || (token->token[1] != 0)) { + ERROR("Expecting keyword \"=\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype == CRNG_KEYWORD) && + (token->token == ctxt->key_inherit)) { + namespace = xmlCRelaxNGInherit; + } else if (token->toktype == CRNG_LITERAL_SEGMENT) { + namespace = token->token; + } else { + ERROR("Expecting an URI or \"inherit\" value"); + } + xmlParseCRNGDropTokens(ctxt, 1); + if (namespace != NULL) { + if (prefix != NULL) + xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); + xmlParseCRNG_bindPrefix(ctxt, NULL, namespace); + } + } else if (token->token == ctxt->key_namespace) { + xmlParseCRNGDropTokens(ctxt, 1); + prefix = xmlParseCRNG_namespacePrefix(ctxt); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != '=') || (token->token[1] != 0)) { + ERROR("Expecting keyword \"=\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype == CRNG_KEYWORD) && + (token->token == ctxt->key_inherit)) { + namespace = xmlCRelaxNGInherit; + } else if (token->toktype == CRNG_LITERAL_SEGMENT) { + namespace = token->token; + } else { + ERROR("Expecting an URI or \"inherit\" value"); + } + xmlParseCRNGDropTokens(ctxt, 1); + if (namespace != NULL) + xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); + } else if (token->token == ctxt->key_datatypes) { + xmlParseCRNGDropTokens(ctxt, 1); + + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_KEYWORD) && + (token->toktype != CRNG_IDENTIFIER)) { + ERROR("Expecting a datatype prefix identifier here"); + } else + prefix = token->token; + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + if ((token->toktype != CRNG_OP) || + (token->token[0] != '=') || (token->token[1] != 0)) { + ERROR("Expecting keyword \"=\" here"); + } + xmlParseCRNGDropTokens(ctxt, 1); + token = xmlParseCRNGGetToken(ctxt, 1); + if (token->toktype == CRNG_LITERAL_SEGMENT) { + namespace = token->token; + } else { + ERROR("Expecting a literal value for the datatype identifier"); + } + xmlParseCRNGDropTokens(ctxt, 1); + if ((namespace != NULL) && (prefix != NULL)) + xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace); + } + + return(0); +} + +/** + * xmlParseCRNG_preamble: + * @ctxt: a compact RNG parser context + * + * Parse preamble of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt) +{ + tokenPtr token; + + token = xmlParseCRNGGetToken(ctxt, 1); + while (token != NULL) { + if (token == NULL) return(-1); + if ((token->toktype == CRNG_KEYWORD) && + ((token->token == ctxt->key_default) || + (token->token == ctxt->key_namespace) || + (token->token == ctxt->key_datatypes))) { + xmlParseCRNG_decl(ctxt); + } else + break; + token = xmlParseCRNGGetToken(ctxt, 1); + } + return(0); +} + +/** + * xmlParseCRNG_topLevel: + * @ctxt: a compact RNG parser context + * + * Parse topLevel of the RELAX NG Compact Syntax Appendix A + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt) +{ + xmlParseCRNG_preamble(ctxt); + xmlParseCRNG_topLevelBody(ctxt); + return(0); +} + +/** + * xmlConvertCRNG: + * @schemas: pointer to the text of the compact schemas + * @len: length of the schemas in bytes (or 0) + * @encoding: encoding indicated by the context or NULL + * + * Compiles the schemas into the equivalent Relax-NG XML structure + * + * Returns the xmlDocPtr resulting from the compilation or + * NULL in case of error + */ +xmlDocPtr +xmlConvertCRNG(const char *schemas, int len, const char *encoding) { + struct _xmlCRelaxNGParserCtxt ctxt; + xmlDocPtr ret = NULL; + + if (schemas == NULL) return(NULL); + if (len <= 5) len = xmlStrlen((const unsigned char *) schemas); + if (len <= 0) return(NULL); + + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.compact = (const unsigned char *) schemas; + ctxt.cur = (const unsigned char *) schemas; + ctxt.end = (const unsigned char *) &schemas[len]; + ctxt.dict = xmlDictCreate(); + if (ctxt.dict == NULL) + return(NULL); + ctxt.doc = xmlNewDoc(NULL); + if (ctxt.doc == NULL) { + xmlDictFree(ctxt.dict); + return(NULL); + } + ctxt.doc->dict = ctxt.dict; + xmlDictReference(ctxt.dict); + + ctxt.nbTokens = 0; + ctxt.firstToken = 0; + ctxt.key_attribute = xmlDictLookup(ctxt.dict, BAD_CAST "attribute", -1); + ctxt.key_default = xmlDictLookup(ctxt.dict, BAD_CAST "default", -1); + ctxt.key_datatypes = xmlDictLookup(ctxt.dict, BAD_CAST "datatypes", -1); + ctxt.key_div = xmlDictLookup(ctxt.dict, BAD_CAST "div", -1); + ctxt.key_element = xmlDictLookup(ctxt.dict, BAD_CAST "element", -1); + ctxt.key_empty = xmlDictLookup(ctxt.dict, BAD_CAST "empty", -1); + ctxt.key_external = xmlDictLookup(ctxt.dict, BAD_CAST "external", -1); + ctxt.key_grammar = xmlDictLookup(ctxt.dict, BAD_CAST "grammar", -1); + ctxt.key_include = xmlDictLookup(ctxt.dict, BAD_CAST "include", -1); + ctxt.key_inherit = xmlDictLookup(ctxt.dict, BAD_CAST "inherit", -1); + ctxt.key_list = xmlDictLookup(ctxt.dict, BAD_CAST "list", -1); + ctxt.key_mixed = xmlDictLookup(ctxt.dict, BAD_CAST "mixed", -1); + ctxt.key_namespace = xmlDictLookup(ctxt.dict, BAD_CAST "namespace", -1); + ctxt.key_notAllowed = xmlDictLookup(ctxt.dict, BAD_CAST "notAllowed", -1); + ctxt.key_parent = xmlDictLookup(ctxt.dict, BAD_CAST "parent", -1); + ctxt.key_start = xmlDictLookup(ctxt.dict, BAD_CAST "start", -1); + ctxt.key_string = xmlDictLookup(ctxt.dict, BAD_CAST "string", -1); + ctxt.key_text = xmlDictLookup(ctxt.dict, BAD_CAST "text", -1); + ctxt.key_token = xmlDictLookup(ctxt.dict, BAD_CAST "token", -1); + ctxt.key_equal = xmlDictLookup(ctxt.dict, BAD_CAST "=", 1); + ctxt.key_orequal = xmlDictLookup(ctxt.dict, BAD_CAST "|=", 2); + ctxt.key_andequal = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2); + ctxt.key_combine = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2); + ctxt.key_or = xmlDictLookup(ctxt.dict, BAD_CAST "|", 1); + ctxt.key_comma = xmlDictLookup(ctxt.dict, BAD_CAST ",", 1); + ctxt.key_and = xmlDictLookup(ctxt.dict, BAD_CAST "&", 1); + ctxt.key_choice = xmlDictLookup(ctxt.dict, BAD_CAST "choice", -1); + ctxt.key_group = xmlDictLookup(ctxt.dict, BAD_CAST "group", -1); + ctxt.key_interleave = xmlDictLookup(ctxt.dict, BAD_CAST "interleave", -1); + ctxt.key_ref = xmlDictLookup(ctxt.dict, BAD_CAST "ref", 3); + ctxt.key_define = xmlDictLookup(ctxt.dict, BAD_CAST "define", 6); + + /* xmlConvertCRNGTokenize(&ctxt); */ + xmlConvertCRNG_topLevel(&ctxt); + + xmlDictFree(ctxt.dict); + + ret = ctxt.doc; + return(ret); +} + +/** + * xmlConvertCRNGFile: + * @URL: URL or filename for the resource + * @encoding: encoding indicated by the context or NULL + * + * Compiles the schemas into the equivalent Relax-NG XML structure + * + * Returns the xmlDocPtr resulting from the compilation or + * NULL in case of error + */ +xmlDocPtr +xmlConvertCRNGFile(const char *URL, const char *encoding) { +} + +#ifdef STANDALONE +const xmlChar *schemas = +"# RELAX NG XML syntax specified in compact syntax.\n\ +\n\ +default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\ +namespace local = \"\"\n\ +datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\ +\n\ +start = pattern\n\ +\n\ +pattern =\n\ + element element { (nameQName | nameClass), (common & pattern+) }\n\ + | element attribute { (nameQName | nameClass), (common & pattern?) }\n\ + | element group|interleave|choice|optional\n\ + |zeroOrMore|oneOrMore|list|mixed { common & pattern+ }\n\ + | element ref|parentRef { nameNCName, common }\n\ + | element empty|notAllowed|text { common }\n\ + | element data { type, param*, (common & exceptPattern?) }\n\ + | element value { commonAttributes, type?, xsd:string }\n\ + | element externalRef { href, common }\n\ + | element grammar { common & grammarContent* }\n\ +\n\ +param = element param { commonAttributes, nameNCName, xsd:string }\n\ +\n\ +exceptPattern = element except { common & pattern+ }\n\ +\n\ +grammarContent =\n\ + definition\n\ + | element div { common & grammarContent* }\n\ + | element include { href, (common & includeContent*) }\n\ +\n\ +includeContent =\n\ + definition\n\ + | element div { common & includeContent* }\n\ +\n\ +definition =\n\ + element start { combine?, (common & pattern+) }\n\ + | element define { nameNCName, combine?, (common & pattern+) }\n\ +\n\ +combine = attribute combine { \"choice\" | \"interleave\" }\n\ +\n\ +nameClass =\n\ + element name { commonAttributes, xsd:QName }\n\ + | element anyName { common & exceptNameClass? }\n\ + | element nsName { common & exceptNameClass? }\n\ + | element choice { common & nameClass+ }\n\ +\n\ +exceptNameClass = element except { common & nameClass+ }\n\ +\n\ +nameQName = attribute name { xsd:QName }\n\ +nameNCName = attribute name { xsd:NCName }\n\ +href = attribute href { xsd:anyURI }\n\ +type = attribute type { xsd:NCName }\n\ +\n\ +common = commonAttributes, foreignElement*\n\ +\n\ +commonAttributes =\n\ + attribute ns { xsd:string }?,\n\ + attribute datatypeLibrary { xsd:anyURI }?,\n\ + foreignAttribute*\n\ +\n\ +foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\ +foreignAttribute = attribute * - (rng:*|local:*) { text }\n\ +anyElement = element * { (anyAttribute | text | anyElement)* }\n\ +anyAttribute = attribute * { text }\n\ +"; + +int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + xmlDocPtr res; + + res = xmlConvertCRNG(schemas, -1); + if (res != NULL) { + xmlDocFormatDump(stdout, res, 1); + xmlFreeDoc(res); + } + return(0); +} +#endif diff --git a/runsuite.c b/runsuite.c new file mode 100644 index 00000000000..75b8f3ad797 --- /dev/null +++ b/runsuite.c @@ -0,0 +1,1166 @@ +/* + * runsuite.c: C program to run libxml2 against published testsuites + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#include "config.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#include + +#include +#include + +#include +#include +#include + +#define LOGFILE "runsuite.log" +static FILE *logfile = NULL; +static int verbose = 0; + + +/************************************************************************ + * * + * File name and path utilities * + * * + ************************************************************************/ + +static int checkTestFile(const char *filename) { + struct stat buf; + + if (stat(filename, &buf) == -1) + return(0); + +#if defined(_WIN32) + if (!(buf.st_mode & _S_IFREG)) + return(0); +#else + if (!S_ISREG(buf.st_mode)) + return(0); +#endif + + return(1); +} + +static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) { + char buf[500]; + + if (dir == NULL) return(xmlStrdup(path)); + if (path == NULL) return(NULL); + + snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path); + return(xmlStrdup((const xmlChar *) buf)); +} + +/************************************************************************ + * * + * Libxml2 specific routines * + * * + ************************************************************************/ + +static int nb_tests = 0; +static int nb_errors = 0; +static int nb_internals = 0; +static int nb_schematas = 0; +static int nb_unimplemented = 0; +static int nb_leaks = 0; +static int extraMemoryFromResolver = 0; + +static int +fatalError(void) { + fprintf(stderr, "Exitting tests on fatal error\n"); + exit(1); +} + +/* + * that's needed to implement + */ +#define MAX_ENTITIES 20 +static char *testEntitiesName[MAX_ENTITIES]; +static char *testEntitiesValue[MAX_ENTITIES]; +static int nb_entities = 0; +static void resetEntities(void) { + int i; + + for (i = 0;i < nb_entities;i++) { + if (testEntitiesName[i] != NULL) + xmlFree(testEntitiesName[i]); + if (testEntitiesValue[i] != NULL) + xmlFree(testEntitiesValue[i]); + } + nb_entities = 0; +} +static int addEntity(char *name, char *content) { + if (nb_entities >= MAX_ENTITIES) { + fprintf(stderr, "Too many entities defined\n"); + return(-1); + } + testEntitiesName[nb_entities] = name; + testEntitiesValue[nb_entities] = content; + nb_entities++; + return(0); +} + +/* + * We need to trap calls to the resolver to not account memory for the catalog + * which is shared to the current running test. We also don't want to have + * network downloads modifying tests. + */ +static xmlParserInputPtr +testExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr ret; + int i; + + for (i = 0;i < nb_entities;i++) { + if (!strcmp(testEntitiesName[i], URL)) { + ret = xmlNewStringInputStream(ctxt, + (const xmlChar *) testEntitiesValue[i]); + if (ret != NULL) { + ret->filename = (const char *) + xmlStrdup((xmlChar *)testEntitiesName[i]); + } + return(ret); + } + } + if (checkTestFile(URL)) { + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + } else { + int memused = xmlMemUsed(); + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + extraMemoryFromResolver += xmlMemUsed() - memused; + } +#if 0 + if (ret == NULL) { + fprintf(stderr, "Failed to find resource %s\n", URL); + } +#endif + + return(ret); +} + +/* + * Trapping the error messages at the generic level to grab the equivalent of + * stderr messages on CLI tools. + */ +static char testErrors[32769]; +static int testErrorsSize = 0; + +static void test_log(const char *msg, ...) { + va_list args; + if (logfile != NULL) { + fprintf(logfile, "\n------------\n"); + va_start(args, msg); + vfprintf(logfile, msg, args); + va_end(args); + fprintf(logfile, "%s", testErrors); + testErrorsSize = 0; testErrors[0] = 0; + } + if (verbose) { + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + } +} + +static void +testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { + va_list args; + int res; + + if (testErrorsSize >= 32768) + return; + va_start(args, msg); + res = vsnprintf(&testErrors[testErrorsSize], + 32768 - testErrorsSize, + msg, args); + va_end(args); + if (testErrorsSize + res >= 32768) { + /* buffer is full */ + testErrorsSize = 32768; + testErrors[testErrorsSize] = 0; + } else { + testErrorsSize += res; + } + testErrors[testErrorsSize] = 0; +} + +static xmlXPathContextPtr ctxtXPath; + +static void +initializeLibxml2(void) { + xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); + xmlInitParser(); + xmlSetExternalEntityLoader(testExternalEntityLoader); + ctxtXPath = xmlXPathNewContext(NULL); + /* + * Deactivate the cache if created; otherwise we have to create/free it + * for every test, since it will confuse the memory leak detection. + * Note that normally this need not be done, since the cache is not + * created until set explicitly with xmlXPathContextSetCache(); + * but for test purposes it is sometimes useful to activate the + * cache by default for the whole library. + */ + if (ctxtXPath->cache != NULL) + xmlXPathContextSetCache(ctxtXPath, 0, -1, 0); + /* used as default namespace in xstc tests */ + xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite"); + xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink", + BAD_CAST "http://www.w3.org/1999/xlink"); + xmlSetGenericErrorFunc(NULL, testErrorHandler); +#ifdef LIBXML_SCHEMAS_ENABLED + xmlSchemaInitTypes(); + xmlRelaxNGInitTypes(); +#endif +} + +static xmlNodePtr +getNext(xmlNodePtr cur, const char *xpath) { + xmlNodePtr ret = NULL; + xmlXPathObjectPtr res; + xmlXPathCompExprPtr comp; + + if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL)) + return(NULL); + ctxtXPath->doc = cur->doc; + ctxtXPath->node = cur; + comp = xmlXPathCompile(BAD_CAST xpath); + if (comp == NULL) { + fprintf(stderr, "Failed to compile %s\n", xpath); + return(NULL); + } + res = xmlXPathCompiledEval(comp, ctxtXPath); + xmlXPathFreeCompExpr(comp); + if (res == NULL) + return(NULL); + if ((res->type == XPATH_NODESET) && + (res->nodesetval != NULL) && + (res->nodesetval->nodeNr > 0) && + (res->nodesetval->nodeTab != NULL)) + ret = res->nodesetval->nodeTab[0]; + xmlXPathFreeObject(res); + return(ret); +} + +static xmlChar * +getString(xmlNodePtr cur, const char *xpath) { + xmlChar *ret = NULL; + xmlXPathObjectPtr res; + xmlXPathCompExprPtr comp; + + if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL)) + return(NULL); + ctxtXPath->doc = cur->doc; + ctxtXPath->node = cur; + comp = xmlXPathCompile(BAD_CAST xpath); + if (comp == NULL) { + fprintf(stderr, "Failed to compile %s\n", xpath); + return(NULL); + } + res = xmlXPathCompiledEval(comp, ctxtXPath); + xmlXPathFreeCompExpr(comp); + if (res == NULL) + return(NULL); + if (res->type == XPATH_STRING) { + ret = res->stringval; + res->stringval = NULL; + } + xmlXPathFreeObject(res); + return(ret); +} + +/************************************************************************ + * * + * Test test/xsdtest/xsdtestsuite.xml * + * * + ************************************************************************/ + +static int +xsdIncorrectTestCase(xmlNodePtr cur) { + xmlNodePtr test; + xmlBufferPtr buf; + xmlRelaxNGParserCtxtPtr pctxt; + xmlRelaxNGPtr rng = NULL; + int ret = 0, memt; + + cur = getNext(cur, "./incorrect[1]"); + if (cur == NULL) { + return(0); + } + + test = getNext(cur, "./*"); + if (test == NULL) { + test_log("Failed to find test in correct line %ld\n", + xmlGetLineNo(cur)); + return(1); + } + + memt = xmlMemUsed(); + extraMemoryFromResolver = 0; + /* + * dump the schemas to a buffer, then reparse it and compile the schemas + */ + buf = xmlBufferCreate(); + if (buf == NULL) { + fprintf(stderr, "out of memory !\n"); + fatalError(); + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + xmlNodeDump(buf, test->doc, test, 0, 0); + pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use); + xmlRelaxNGSetParserErrors(pctxt, testErrorHandler, testErrorHandler, + pctxt); + rng = xmlRelaxNGParse(pctxt); + xmlRelaxNGFreeParserCtxt(pctxt); + if (rng != NULL) { + test_log("Failed to detect incorrect RNG line %ld\n", + xmlGetLineNo(test)); + ret = 1; + goto done; + } + +done: + if (buf != NULL) + xmlBufferFree(buf); + if (rng != NULL) + xmlRelaxNGFree(rng); + xmlResetLastError(); + if ((memt < xmlMemUsed()) && (extraMemoryFromResolver == 0)) { + test_log("Validation of tests starting line %ld leaked %d\n", + xmlGetLineNo(cur), xmlMemUsed() - memt); + nb_leaks++; + } + return(ret); +} + +static void +installResources(xmlNodePtr tst, const xmlChar *base) { + xmlNodePtr test; + xmlBufferPtr buf; + xmlChar *name, *content, *res; + + buf = xmlBufferCreate(); + if (buf == NULL) { + fprintf(stderr, "out of memory !\n"); + fatalError(); + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + xmlNodeDump(buf, tst->doc, tst, 0, 0); + + while (tst != NULL) { + test = getNext(tst, "./*"); + if (test != NULL) { + xmlBufferEmpty(buf); + xmlNodeDump(buf, test->doc, test, 0, 0); + name = getString(tst, "string(@name)"); + content = xmlStrdup(buf->content); + if ((name != NULL) && (content != NULL)) { + res = composeDir(base, name); + xmlFree(name); + addEntity((char *) res, (char *) content); + } else { + if (name != NULL) xmlFree(name); + if (content != NULL) xmlFree(content); + } + } + tst = getNext(tst, "following-sibling::resource[1]"); + } + if (buf != NULL) + xmlBufferFree(buf); +} + +static void +installDirs(xmlNodePtr tst, const xmlChar *base) { + xmlNodePtr test; + xmlChar *name, *res; + + name = getString(tst, "string(@name)"); + if (name == NULL) + return; + res = composeDir(base, name); + xmlFree(name); + if (res == NULL) { + return; + } + /* Now process resources and subdir recursively */ + test = getNext(tst, "./resource[1]"); + if (test != NULL) { + installResources(test, res); + } + test = getNext(tst, "./dir[1]"); + while (test != NULL) { + installDirs(test, res); + test = getNext(test, "following-sibling::dir[1]"); + } + xmlFree(res); +} + +static int +xsdTestCase(xmlNodePtr tst) { + xmlNodePtr test, tmp, cur; + xmlBufferPtr buf; + xmlDocPtr doc = NULL; + xmlRelaxNGParserCtxtPtr pctxt; + xmlRelaxNGValidCtxtPtr ctxt; + xmlRelaxNGPtr rng = NULL; + int ret = 0, mem, memt; + xmlChar *dtd; + + resetEntities(); + testErrorsSize = 0; testErrors[0] = 0; + + tmp = getNext(tst, "./dir[1]"); + if (tmp != NULL) { + installDirs(tmp, NULL); + } + tmp = getNext(tst, "./resource[1]"); + if (tmp != NULL) { + installResources(tmp, NULL); + } + + cur = getNext(tst, "./correct[1]"); + if (cur == NULL) { + return(xsdIncorrectTestCase(tst)); + } + + test = getNext(cur, "./*"); + if (test == NULL) { + fprintf(stderr, "Failed to find test in correct line %ld\n", + xmlGetLineNo(cur)); + return(1); + } + + memt = xmlMemUsed(); + extraMemoryFromResolver = 0; + /* + * dump the schemas to a buffer, then reparse it and compile the schemas + */ + buf = xmlBufferCreate(); + if (buf == NULL) { + fprintf(stderr, "out of memory !\n"); + fatalError(); + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + xmlNodeDump(buf, test->doc, test, 0, 0); + pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use); + xmlRelaxNGSetParserErrors(pctxt, testErrorHandler, testErrorHandler, + pctxt); + rng = xmlRelaxNGParse(pctxt); + xmlRelaxNGFreeParserCtxt(pctxt); + if (extraMemoryFromResolver) + memt = 0; + + if (rng == NULL) { + test_log("Failed to parse RNGtest line %ld\n", + xmlGetLineNo(test)); + nb_errors++; + ret = 1; + goto done; + } + /* + * now scan all the siblings of correct to process the tests + */ + tmp = getNext(cur, "following-sibling::valid[1]"); + while (tmp != NULL) { + dtd = xmlGetProp(tmp, BAD_CAST "dtd"); + test = getNext(tmp, "./*"); + if (test == NULL) { + fprintf(stderr, "Failed to find test in line %ld\n", + xmlGetLineNo(tmp)); + + } else { + xmlBufferEmpty(buf); + if (dtd != NULL) + xmlBufferAdd(buf, dtd, -1); + xmlNodeDump(buf, test->doc, test, 0, 0); + + /* + * We are ready to run the test + */ + mem = xmlMemUsed(); + extraMemoryFromResolver = 0; + doc = xmlReadMemory((const char *)buf->content, buf->use, + "test", NULL, 0); + if (doc == NULL) { + test_log("Failed to parse valid instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } else { + nb_tests++; + ctxt = xmlRelaxNGNewValidCtxt(rng); + xmlRelaxNGSetValidErrors(ctxt, + testErrorHandler, testErrorHandler, ctxt); + ret = xmlRelaxNGValidateDoc(ctxt, doc); + xmlRelaxNGFreeValidCtxt(ctxt); + if (ret > 0) { + test_log("Failed to validate valid instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } else if (ret < 0) { + test_log("Internal error validating instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } + xmlFreeDoc(doc); + } + xmlResetLastError(); + if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) { + test_log("Validation of instance line %ld leaked %d\n", + xmlGetLineNo(tmp), xmlMemUsed() - mem); + nb_leaks++; + } + } + if (dtd != NULL) + xmlFree(dtd); + tmp = getNext(tmp, "following-sibling::valid[1]"); + } + /* + * now scan all the siblings of correct to process the tests + */ + tmp = getNext(cur, "following-sibling::invalid[1]"); + while (tmp != NULL) { + test = getNext(tmp, "./*"); + if (test == NULL) { + fprintf(stderr, "Failed to find test in line %ld\n", + xmlGetLineNo(tmp)); + + } else { + xmlBufferEmpty(buf); + xmlNodeDump(buf, test->doc, test, 0, 0); + + /* + * We are ready to run the test + */ + mem = xmlMemUsed(); + extraMemoryFromResolver = 0; + doc = xmlReadMemory((const char *)buf->content, buf->use, + "test", NULL, 0); + if (doc == NULL) { + test_log("Failed to parse valid instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } else { + nb_tests++; + ctxt = xmlRelaxNGNewValidCtxt(rng); + xmlRelaxNGSetValidErrors(ctxt, + testErrorHandler, testErrorHandler, ctxt); + ret = xmlRelaxNGValidateDoc(ctxt, doc); + xmlRelaxNGFreeValidCtxt(ctxt); + if (ret == 0) { + test_log("Failed to detect invalid instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } else if (ret < 0) { + test_log("Internal error validating instance line %ld\n", + xmlGetLineNo(tmp)); + nb_errors++; + } + xmlFreeDoc(doc); + } + xmlResetLastError(); + if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) { + test_log("Validation of instance line %ld leaked %d\n", + xmlGetLineNo(tmp), xmlMemUsed() - mem); + nb_leaks++; + } + } + tmp = getNext(tmp, "following-sibling::invalid[1]"); + } + +done: + if (buf != NULL) + xmlBufferFree(buf); + if (rng != NULL) + xmlRelaxNGFree(rng); + xmlResetLastError(); + if ((memt != xmlMemUsed()) && (memt != 0)) { + test_log("Validation of tests starting line %ld leaked %d\n", + xmlGetLineNo(cur), xmlMemUsed() - memt); + nb_leaks++; + } + return(ret); +} + +static int +xsdTestSuite(xmlNodePtr cur) { + if (verbose) { + xmlChar *doc = getString(cur, "string(documentation)"); + + if (doc != NULL) { + printf("Suite %s\n", doc); + xmlFree(doc); + } + } + cur = getNext(cur, "./testCase[1]"); + while (cur != NULL) { + xsdTestCase(cur); + cur = getNext(cur, "following-sibling::testCase[1]"); + } + + return(0); +} + +static int +xsdTest(void) { + xmlDocPtr doc; + xmlNodePtr cur; + const char *filename = "test/xsdtest/xsdtestsuite.xml"; + int ret = 0; + + doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } + printf("## XML Schemas datatypes test suite from James Clark\n"); + + cur = xmlDocGetRootElement(doc); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + + cur = getNext(cur, "./testSuite[1]"); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + while (cur != NULL) { + xsdTestSuite(cur); + cur = getNext(cur, "following-sibling::testSuite[1]"); + } + +done: + if (doc != NULL) + xmlFreeDoc(doc); + return(ret); +} + +static int +rngTestSuite(xmlNodePtr cur) { + if (verbose) { + xmlChar *doc = getString(cur, "string(documentation)"); + + if (doc != NULL) { + printf("Suite %s\n", doc); + xmlFree(doc); + } else { + doc = getString(cur, "string(section)"); + if (doc != NULL) { + printf("Section %s\n", doc); + xmlFree(doc); + } + } + } + cur = getNext(cur, "./testSuite[1]"); + while (cur != NULL) { + xsdTestSuite(cur); + cur = getNext(cur, "following-sibling::testSuite[1]"); + } + + return(0); +} + +static int +rngTest1(void) { + xmlDocPtr doc; + xmlNodePtr cur; + const char *filename = "test/relaxng/OASIS/spectest.xml"; + int ret = 0; + + doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } + printf("## Relax NG test suite from James Clark\n"); + + cur = xmlDocGetRootElement(doc); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + + cur = getNext(cur, "./testSuite[1]"); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + while (cur != NULL) { + rngTestSuite(cur); + cur = getNext(cur, "following-sibling::testSuite[1]"); + } + +done: + if (doc != NULL) + xmlFreeDoc(doc); + return(ret); +} + +static int +rngTest2(void) { + xmlDocPtr doc; + xmlNodePtr cur; + const char *filename = "test/relaxng/testsuite.xml"; + int ret = 0; + + doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } + printf("## Relax NG test suite for libxml2\n"); + + cur = xmlDocGetRootElement(doc); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + + cur = getNext(cur, "./testSuite[1]"); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) { + fprintf(stderr, "Unexpected format %s\n", filename); + ret = -1; + goto done; + } + while (cur != NULL) { + xsdTestSuite(cur); + cur = getNext(cur, "following-sibling::testSuite[1]"); + } + +done: + if (doc != NULL) + xmlFreeDoc(doc); + return(ret); +} + +/************************************************************************ + * * + * Schemas test suites from W3C/NIST/MS/Sun * + * * + ************************************************************************/ + +static int +xstcTestInstance(xmlNodePtr cur, xmlSchemaPtr schemas, + const xmlChar *spath, const char *base) { + xmlChar *href = NULL; + xmlChar *path = NULL; + xmlChar *validity = NULL; + xmlSchemaValidCtxtPtr ctxt = NULL; + xmlDocPtr doc = NULL; + int ret = 0, mem; + + xmlResetLastError(); + testErrorsSize = 0; testErrors[0] = 0; + mem = xmlMemUsed(); + href = getString(cur, + "string(ts:instanceDocument/@xlink:href)"); + if ((href == NULL) || (href[0] == 0)) { + test_log("testGroup line %ld misses href for schemaDocument\n", + xmlGetLineNo(cur)); + ret = -1; + goto done; + } + path = xmlBuildURI(href, BAD_CAST base); + if (path == NULL) { + fprintf(stderr, + "Failed to build path to schemas testGroup line %ld : %s\n", + xmlGetLineNo(cur), href); + ret = -1; + goto done; + } + if (checkTestFile((const char *) path) <= 0) { + test_log("schemas for testGroup line %ld is missing: %s\n", + xmlGetLineNo(cur), path); + ret = -1; + goto done; + } + validity = getString(cur, + "string(ts:expected/@validity)"); + if (validity == NULL) { + fprintf(stderr, "instanceDocument line %ld misses expected validity\n", + xmlGetLineNo(cur)); + ret = -1; + goto done; + } + nb_tests++; + doc = xmlReadFile((const char *) path, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "instance %s fails to parse\n", path); + ret = -1; + nb_errors++; + goto done; + } + + ctxt = xmlSchemaNewValidCtxt(schemas); + xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt); + ret = xmlSchemaValidateDoc(ctxt, doc); + + if (xmlStrEqual(validity, BAD_CAST "valid")) { + if (ret > 0) { + test_log("valid instance %s failed to validate against %s\n", + path, spath); + nb_errors++; + } else if (ret < 0) { + test_log("valid instance %s got internal error validating %s\n", + path, spath); + nb_internals++; + nb_errors++; + } + } else if (xmlStrEqual(validity, BAD_CAST "invalid")) { + if (ret == 0) { + test_log("Failed to detect invalid instance %s against %s\n", + path, spath); + nb_errors++; + } + } else { + test_log("instanceDocument line %ld has unexpected validity value%s\n", + xmlGetLineNo(cur), validity); + ret = -1; + goto done; + } + +done: + if (href != NULL) xmlFree(href); + if (path != NULL) xmlFree(path); + if (validity != NULL) xmlFree(validity); + if (ctxt != NULL) xmlSchemaFreeValidCtxt(ctxt); + if (doc != NULL) xmlFreeDoc(doc); + xmlResetLastError(); + if (mem != xmlMemUsed()) { + test_log("Validation of tests starting line %ld leaked %d\n", + xmlGetLineNo(cur), xmlMemUsed() - mem); + nb_leaks++; + } + return(ret); +} + +static int +xstcTestGroup(xmlNodePtr cur, const char *base) { + xmlChar *href = NULL; + xmlChar *path = NULL; + xmlChar *validity = NULL; + xmlSchemaPtr schemas = NULL; + xmlSchemaParserCtxtPtr ctxt; + xmlNodePtr instance; + int ret = 0, mem; + + xmlResetLastError(); + testErrorsSize = 0; testErrors[0] = 0; + mem = xmlMemUsed(); + href = getString(cur, + "string(ts:schemaTest/ts:schemaDocument/@xlink:href)"); + if ((href == NULL) || (href[0] == 0)) { + test_log("testGroup line %ld misses href for schemaDocument\n", + xmlGetLineNo(cur)); + ret = -1; + goto done; + } + path = xmlBuildURI(href, BAD_CAST base); + if (path == NULL) { + test_log("Failed to build path to schemas testGroup line %ld : %s\n", + xmlGetLineNo(cur), href); + ret = -1; + goto done; + } + if (checkTestFile((const char *) path) <= 0) { + test_log("schemas for testGroup line %ld is missing: %s\n", + xmlGetLineNo(cur), path); + ret = -1; + goto done; + } + validity = getString(cur, + "string(ts:schemaTest/ts:expected/@validity)"); + if (validity == NULL) { + test_log("testGroup line %ld misses expected validity\n", + xmlGetLineNo(cur)); + ret = -1; + goto done; + } + nb_tests++; + if (xmlStrEqual(validity, BAD_CAST "valid")) { + nb_schematas++; + ctxt = xmlSchemaNewParserCtxt((const char *) path); + xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, + ctxt); + schemas = xmlSchemaParse(ctxt); + xmlSchemaFreeParserCtxt(ctxt); + if (schemas == NULL) { + test_log("valid schemas %s failed to parse\n", + path); + ret = 1; + nb_errors++; + } + if ((ret == 0) && (strstr(testErrors, "nimplemented") != NULL)) { + test_log("valid schemas %s hit an unimplemented block\n", + path); + ret = 1; + nb_unimplemented++; + nb_errors++; + } + instance = getNext(cur, "./ts:instanceTest[1]"); + while (instance != NULL) { + if (schemas != NULL) { + xstcTestInstance(instance, schemas, path, base); + } else { + /* + * We'll automatically mark the instances as failed + * if the schema was broken. + */ + nb_errors++; + } + instance = getNext(instance, + "following-sibling::ts:instanceTest[1]"); + } + } else if (xmlStrEqual(validity, BAD_CAST "invalid")) { + nb_schematas++; + ctxt = xmlSchemaNewParserCtxt((const char *) path); + xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, + ctxt); + schemas = xmlSchemaParse(ctxt); + xmlSchemaFreeParserCtxt(ctxt); + if (schemas != NULL) { + test_log("Failed to detect error in schemas %s\n", + path); + nb_errors++; + ret = 1; + } + if ((ret == 0) && (strstr(testErrors, "nimplemented") != NULL)) { + nb_unimplemented++; + test_log("invalid schemas %s hit an unimplemented block\n", + path); + ret = 1; + nb_errors++; + } + } else { + test_log("testGroup line %ld misses unexpected validity value%s\n", + xmlGetLineNo(cur), validity); + ret = -1; + goto done; + } + +done: + if (href != NULL) xmlFree(href); + if (path != NULL) xmlFree(path); + if (validity != NULL) xmlFree(validity); + if (schemas != NULL) xmlSchemaFree(schemas); + xmlResetLastError(); + if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) { + test_log("Processing test line %ld %s leaked %d\n", + xmlGetLineNo(cur), path, xmlMemUsed() - mem); + nb_leaks++; + } + return(ret); +} + +static int +xstcMetadata(const char *metadata, const char *base) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *contributor; + xmlChar *name; + int ret = 0; + + doc = xmlReadFile(metadata, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", metadata); + return(-1); + } + + cur = xmlDocGetRootElement(doc); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSet"))) { + fprintf(stderr, "Unexpected format %s\n", metadata); + return(-1); + } + contributor = xmlGetProp(cur, BAD_CAST "contributor"); + if (contributor == NULL) { + contributor = xmlStrdup(BAD_CAST "Unknown"); + } + name = xmlGetProp(cur, BAD_CAST "name"); + if (name == NULL) { + name = xmlStrdup(BAD_CAST "Unknown"); + } + printf("## %s test suite for Schemas version %s\n", contributor, name); + xmlFree(contributor); + xmlFree(name); + + cur = getNext(cur, "./ts:testGroup[1]"); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testGroup"))) { + fprintf(stderr, "Unexpected format %s\n", metadata); + ret = -1; + goto done; + } + while (cur != NULL) { + xstcTestGroup(cur, base); + cur = getNext(cur, "following-sibling::ts:testGroup[1]"); + } + +done: + xmlFreeDoc(doc); + return(ret); +} + +/************************************************************************ + * * + * The driver for the tests * + * * + ************************************************************************/ + +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + int ret = 0; + int old_errors, old_tests, old_leaks, expected_errors; + + logfile = fopen(LOGFILE, "w"); + if (logfile == NULL) { + fprintf(stderr, + "Could not open the log file, running in verbose mode\n"); + verbose = 1; + } + initializeLibxml2(); + + if ((argc >= 2) && (!strcmp(argv[1], "-v"))) + verbose = 1; + + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + xsdTest(); + expected_errors = 3; + printf("Ran %d tests, %d errors, %d leaks\n", + nb_tests - old_tests, + nb_errors - old_errors, + nb_leaks - old_leaks); + if (nb_errors - old_errors == expected_errors) { + printf("%d errors were expected\n", expected_errors); + nb_errors = old_errors; + } else { + printf("%d errors were expected, got %d errors\n", + expected_errors, nb_errors - old_errors); + nb_errors = old_errors + 1; + } + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + rngTest1(); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) + printf("Ran %d tests, no errors\n", nb_tests - old_tests); + else + printf("Ran %d tests, %d errors, %d leaks\n", + nb_tests - old_tests, + nb_errors - old_errors, + nb_leaks - old_leaks); + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + rngTest2(); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) + printf("Ran %d tests, no errors\n", nb_tests - old_tests); + else + printf("Ran %d tests, %d errors, %d leaks\n", + nb_tests - old_tests, + nb_errors - old_errors, + nb_leaks - old_leaks); + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + nb_internals = 0; + nb_schematas = 0; + xstcMetadata("xstc/Tests/Metadata/NISTXMLSchemaDatatypes.testSet", + "xstc/Tests/Metadata/"); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) + printf("Ran %d tests (%d schemata), no errors\n", + nb_tests - old_tests, nb_schematas); + else + printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n", + nb_tests - old_tests, + nb_schematas, + nb_errors - old_errors, + nb_internals, + nb_leaks - old_leaks); + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + nb_internals = 0; + nb_schematas = 0; + xstcMetadata("xstc/Tests/Metadata/SunXMLSchema1-0-20020116.testSet", + "xstc/Tests/"); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) { + printf("Ran %d tests (%d schemata), no errors\n", + nb_tests - old_tests, nb_schematas); + } else { + printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n", + nb_tests - old_tests, + nb_schematas, + nb_errors - old_errors, + nb_internals, + nb_leaks - old_leaks); + printf("Some errors were expected.\n"); + nb_errors = old_errors; + } + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + nb_internals = 0; + nb_schematas = 0; + xstcMetadata("xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet", + "xstc/Tests/"); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) { + printf("Ran %d tests (%d schemata), no errors\n", + nb_tests - old_tests, nb_schematas); + } else { + printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n", + nb_tests - old_tests, + nb_schematas, + nb_errors - old_errors, + nb_internals, + nb_leaks - old_leaks); + printf("Some errors were expected.\n"); + nb_errors = old_errors; + } + + if ((nb_errors == 0) && (nb_leaks == 0)) { + ret = 0; + printf("Total %d tests, no errors\n", + nb_tests); + } else { + ret = 1; + printf("Total %d tests, %d errors, %d leaks\n", + nb_tests, nb_errors, nb_leaks); + } + xmlXPathFreeContext(ctxtXPath); + xmlCleanupParser(); + + if (logfile != NULL) + fclose(logfile); + return(ret); +} +#else /* !SCHEMAS */ +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + fprintf(stderr, "runsuite requires support for schemas and xpath in libxml2\n"); +} +#endif diff --git a/runtest.c b/runtest.c new file mode 100644 index 00000000000..26681a3c207 --- /dev/null +++ b/runtest.c @@ -0,0 +1,5129 @@ +/* + * runtest.c: C program to run libxml2 regression tests without + * requiring make or Python, and reducing platform dependencies + * to a strict minimum. + * + * To compile on Unixes: + * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define XML_DEPRECATED + +#include "libxml.h" +#include +#ifdef HAVE_UNISTD_H +#include +#elif defined (_WIN32) +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef LIBXML_READER_ENABLED +#include +#endif + +#ifdef LIBXML_XINCLUDE_ENABLED +#include +#endif + +#ifdef LIBXML_XPATH_ENABLED +#include +#include +#ifdef LIBXML_XPTR_ENABLED +#include +#endif +#endif + +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#include +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif + +#ifdef LIBXML_C14N_ENABLED +#include +#endif + +#ifdef LIBXML_HTML_ENABLED +#include +#include +#endif + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +#include +#include +#include +#endif + +/* + * pseudo flag for the unification of HTML and XML tests + */ +#define XML_PARSE_HTML 1 << 24 + +/* + * O_BINARY is just for Windows compatibility - if it isn't defined + * on this system, avoid any compilation error + */ +#ifdef O_BINARY +#define RD_FLAGS O_RDONLY | O_BINARY +#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY +#else +#define RD_FLAGS O_RDONLY +#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC +#endif + +typedef int (*functest) (const char *filename, const char *result, + const char *error, int options); + +typedef struct testDesc testDesc; +typedef testDesc *testDescPtr; +struct testDesc { + const char *desc; /* description of the test */ + functest func; /* function implementing the test */ + const char *in; /* glob to path for input files */ + const char *out; /* output directory */ + const char *suffix;/* suffix for output files */ + const char *err; /* suffix for error output files */ + int options; /* parser options for the test */ +}; + +static int update_results = 0; +static char* temp_directory = NULL; +static int checkTestFile(const char *filename); + +#if defined(_WIN32) + +#include + +typedef struct +{ + size_t gl_pathc; /* Count of paths matched so far */ + char **gl_pathv; /* List of matched pathnames. */ + size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */ +} glob_t; + +#define GLOB_DOOFFS 0 +static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags, + ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno), + glob_t *pglob) { + glob_t *ret; + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + unsigned int nb_paths = 0; + char directory[500]; + int len; + + if ((pattern == NULL) || (pglob == NULL)) return(-1); + + strncpy(directory, pattern, 499); + for (len = strlen(directory);len >= 0;len--) { + if (directory[len] == '/') { + len++; + directory[len] = 0; + break; + } + } + if (len <= 0) + len = 0; + + + ret = pglob; + memset(ret, 0, sizeof(glob_t)); + + hFind = FindFirstFileA(pattern, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + return(0); + nb_paths = 20; + ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *)); + if (ret->gl_pathv == NULL) { + FindClose(hFind); + return(-1); + } + strncpy(directory + len, FindFileData.cFileName, 499 - len); + ret->gl_pathv[ret->gl_pathc] = strdup(directory); + if (ret->gl_pathv[ret->gl_pathc] == NULL) + goto done; + ret->gl_pathc++; + while(FindNextFileA(hFind, &FindFileData)) { + if (FindFileData.cFileName[0] == '.') + continue; + if (ret->gl_pathc + 2 > nb_paths) { + char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *)); + if (tmp == NULL) + break; + ret->gl_pathv = tmp; + nb_paths *= 2; + } + strncpy(directory + len, FindFileData.cFileName, 499 - len); + ret->gl_pathv[ret->gl_pathc] = strdup(directory); + if (ret->gl_pathv[ret->gl_pathc] == NULL) + break; + ret->gl_pathc++; + } + ret->gl_pathv[ret->gl_pathc] = NULL; + +done: + FindClose(hFind); + return(0); +} + + + +static void globfree(glob_t *pglob) { + unsigned int i; + if (pglob == NULL) + return; + + for (i = 0;i < pglob->gl_pathc;i++) { + if (pglob->gl_pathv[i] != NULL) + free(pglob->gl_pathv[i]); + } +} + +#else +#include +#endif + +/************************************************************************ + * * + * Libxml2 specific routines * + * * + ************************************************************************/ + +static int nb_tests = 0; +static int nb_errors = 0; +static int nb_leaks = 0; +static int extraMemoryFromResolver = 0; + +static int +fatalError(void) { + fprintf(stderr, "Exitting tests on fatal error\n"); + exit(1); +} + +/* + * We need to trap calls to the resolver to not account memory for the catalog + * which is shared to the current running test. We also don't want to have + * network downloads modifying tests. + */ +static xmlParserInputPtr +testExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr ret; + + if (checkTestFile(URL)) { + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + } else { + int memused = xmlMemUsed(); + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + extraMemoryFromResolver += xmlMemUsed() - memused; + } + + return(ret); +} + +/* + * Trapping the error messages at the generic level to grab the equivalent of + * stderr messages on CLI tools. + */ +static char testErrors[32769]; +static int testErrorsSize = 0; + +static void +testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { + va_list args; + int res; + + if (testErrorsSize >= 32768) + return; + va_start(args, msg); + res = vsnprintf(&testErrors[testErrorsSize], + 32768 - testErrorsSize, + msg, args); + va_end(args); + if (testErrorsSize + res >= 32768) { + /* buffer is full */ + testErrorsSize = 32768; + testErrors[testErrorsSize] = 0; + } else { + testErrorsSize += res; + } + testErrors[testErrorsSize] = 0; +} + +static void +testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) { + xmlFormatError(err, testErrorHandler, NULL); +} + +static void +initializeLibxml2(void) { + /* + * This verifies that xmlInitParser doesn't allocate memory with + * xmlMalloc + */ + xmlFree = NULL; + xmlMalloc = NULL; + xmlRealloc = NULL; + xmlMemStrdup = NULL; + xmlInitParser(); + xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); + xmlSetExternalEntityLoader(testExternalEntityLoader); +#ifdef LIBXML_SCHEMAS_ENABLED + xmlSchemaInitTypes(); + xmlRelaxNGInitTypes(); +#endif +} + + +/************************************************************************ + * * + * File name and path utilities * + * * + ************************************************************************/ + +static const char *baseFilename(const char *filename) { + const char *cur; + if (filename == NULL) + return(NULL); + cur = &filename[strlen(filename)]; + while ((cur > filename) && (*cur != '/')) + cur--; + if (*cur == '/') + return(cur + 1); + return(cur); +} + +static char *resultFilename(const char *filename, const char *out, + const char *suffix) { + const char *base; + char res[500]; + char suffixbuff[500]; + +/************* + if ((filename[0] == 't') && (filename[1] == 'e') && + (filename[2] == 's') && (filename[3] == 't') && + (filename[4] == '/')) + filename = &filename[5]; + *************/ + + base = baseFilename(filename); + if (suffix == NULL) + suffix = ".tmp"; + if (out == NULL) + out = ""; + + strncpy(suffixbuff,suffix,499); + + if (snprintf(res, 499, "%s%s%s", out, base, suffixbuff) >= 499) + res[499] = 0; + return(strdup(res)); +} + +static int checkTestFile(const char *filename) { + struct stat buf; + + if (stat(filename, &buf) == -1) + return(0); + +#if defined(_WIN32) + if (!(buf.st_mode & _S_IFREG)) + return(0); +#else + if (!S_ISREG(buf.st_mode)) + return(0); +#endif + + return(1); +} + +static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) { + int res1, res2, total; + int fd1, fd2; + char bytes1[4096]; + char bytes2[4096]; + + if (update_results) { + fd1 = open(r1, RD_FLAGS); + if (fd1 < 0) + return(-1); + fd2 = open(r2, WR_FLAGS, 0644); + if (fd2 < 0) { + close(fd1); + return(-1); + } + total = 0; + do { + res1 = read(fd1, bytes1, 4096); + if (res1 <= 0) + break; + total += res1; + res2 = write(fd2, bytes1, res1); + if (res2 <= 0 || res2 != res1) + break; + } while (1); + close(fd2); + close(fd1); + if (total == 0) + unlink(r2); + return(res1 != 0); + } + + fd1 = open(r1, RD_FLAGS); + if (fd1 < 0) + return(-1); + fd2 = open(r2, RD_FLAGS); + while (1) { + res1 = read(fd1, bytes1, 4096); + res2 = fd2 >= 0 ? read(fd2, bytes2, 4096) : 0; + if ((res1 != res2) || (res1 < 0)) { + close(fd1); + if (fd2 >= 0) + close(fd2); + return(1); + } + if (res1 == 0) + break; + if (memcmp(bytes1, bytes2, res1) != 0) { + close(fd1); + if (fd2 >= 0) + close(fd2); + return(1); + } + } + close(fd1); + if (fd2 >= 0) + close(fd2); + return(0); +} + +static int compareFileMem(const char *filename, const char *mem, int size) { + int res; + int fd; + char bytes[4096]; + int idx = 0; + struct stat info; + + if (update_results) { + if (size == 0) { + unlink(filename); + return(0); + } + fd = open(filename, WR_FLAGS, 0644); + if (fd < 0) { + fprintf(stderr, "failed to open %s for writing", filename); + return(-1); + } + res = write(fd, mem, size); + close(fd); + return(res != size); + } + + if (stat(filename, &info) < 0) { + if (size == 0) + return(0); + fprintf(stderr, "failed to stat %s\n", filename); + return(-1); + } + if (info.st_size != size) { + fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n", + filename, (long) info.st_size, size); + return(-1); + } + fd = open(filename, RD_FLAGS); + if (fd < 0) { + fprintf(stderr, "failed to open %s for reading", filename); + return(-1); + } + while (idx < size) { + res = read(fd, bytes, 4096); + if (res <= 0) + break; + if (res + idx > size) + break; + if (memcmp(bytes, &mem[idx], res) != 0) { + int ix; + for (ix=0; ix 0) { + siz += res; + } + close(fd); +#if !defined(_WIN32) + if (siz != info.st_size) { + free(base); + return(-1); + } +#endif + base[siz] = 0; + *mem = base; + *size = siz; + return(0); +} + +static int unloadMem(const char *mem) { + free((char *)mem); + return(0); +} + +/************************************************************************ + * * + * Tests implementations * + * * + ************************************************************************/ + +/************************************************************************ + * * + * Parse to SAX based tests * + * * + ************************************************************************/ + +static FILE *SAXdebug = NULL; + +/* + * 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; */ + 1, + NULL, + NULL, /* startElementNs */ + NULL, /* endElementNs */ + NULL /* xmlStructuredErrorFunc */ +}; + +typedef struct { + const char *filename; + xmlHashTablePtr generalEntities; + xmlHashTablePtr parameterEntities; +} debugContext; + +static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; +static int callbacks = 0; +static int quiet = 0; + +/** + * isStandaloneDebug: + * @ctxt: An XML parser context + * + * Is this document tagged standalone ? + * + * Returns 1 if true + */ +static int +isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return(0); + fprintf(SAXdebug, "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 (quiet) + return(0); + fprintf(SAXdebug, "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 (quiet) + return(0); + fprintf(SAXdebug, "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 (quiet) + return; + if (name == NULL) + name = BAD_CAST "(null)"; + fprintf(SAXdebug, "SAX.internalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(SAXdebug, " ,"); + else + fprintf(SAXdebug, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(SAXdebug, " )\n"); + else + fprintf(SAXdebug, " %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 (quiet) + return; + fprintf(SAXdebug, "SAX.externalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(SAXdebug, " ,"); + else + fprintf(SAXdebug, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(SAXdebug, " )\n"); + else + fprintf(SAXdebug, " %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 (quiet) + return(NULL); + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ + + + fprintf(SAXdebug, "SAX.resolveEntity("); + if (publicId != NULL) + fprintf(SAXdebug, "%s", (char *)publicId); + else + fprintf(SAXdebug, " "); + if (systemId != NULL) + fprintf(SAXdebug, ", %s)\n", (char *)systemId); + else + fprintf(SAXdebug, ", )\n"); +/********* + if (systemId != NULL) { + return(xmlNewInputFromFile(ctxt, (char *) systemId)); + } + *********/ + 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, const xmlChar *name) +{ + debugContext *ctxt = ctx; + + callbacks++; + if (quiet) + return(NULL); + fprintf(SAXdebug, "SAX.getEntity(%s)\n", name); + + return(xmlHashLookup(ctxt->generalEntities, name)); +} + +/** + * getParameterEntityDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * Get a parameter entity by name + * + * Returns the xmlParserInputPtr + */ +static xmlEntityPtr +getParameterEntityDebug(void *ctx, const xmlChar *name) +{ + debugContext *ctxt = ctx; + + callbacks++; + if (quiet) + return(NULL); + fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name); + + return(xmlHashLookup(ctxt->parameterEntities, name)); +} + + +/** + * 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, const xmlChar *name, int type, + const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) +{ + debugContext *ctxt = ctx; + xmlEntityPtr ent; + const xmlChar *nullstr = BAD_CAST "(null)"; + + ent = xmlNewEntity(NULL, name, type, publicId, systemId, content); + if (systemId != NULL) + ent->URI = xmlBuildURI(systemId, (const xmlChar *) ctxt->filename); + + if ((type == XML_INTERNAL_PARAMETER_ENTITY) || + (type == XML_EXTERNAL_PARAMETER_ENTITY)) + xmlHashAddEntry(ctxt->parameterEntities, name, ent); + else + xmlHashAddEntry(ctxt->generalEntities, name, ent); + + /* 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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + if (defaultValue == NULL) + fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", + elem, name, type, def); + else + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "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 (quiet) + return; + fprintf(SAXdebug, "SAX.startElement(%s", (char *) name); + if (atts != NULL) { + for (i = 0;(atts[i] != NULL);i++) { + fprintf(SAXdebug, ", %s='", atts[i++]); + if (atts[i] != NULL) + fprintf(SAXdebug, "%s'", atts[i]); + } + } + fprintf(SAXdebug, ")\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 (quiet) + return; + fprintf(SAXdebug, "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 output[40]; + int i; + + callbacks++; + if (quiet) + return; + for (i = 0;(isax, emptySAXHandler, sizeof(xmlSAXHandler)); + xmlCtxtUseOptions(ctxt, options); + xmlParseDocument(ctxt); + ret = ctxt->wellFormed ? 0 : ctxt->errNo; + xmlFreeDoc(ctxt->myDoc); + xmlFreeParserCtxt(ctxt); + } + if (ret == XML_ERR_UNDECLARED_ENTITY) { + fprintf(SAXdebug, "xmlParseDocument returned error %d\n", ret); + ret = 0; + } + if (ret != 0) { + fprintf(stderr, "Failed to parse %s\n", filename); + ret = 1; + goto done; + } +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + htmlParserCtxtPtr ctxt; + + ctxt = htmlNewSAXParserCtxt(debugHTMLSAXHandler, NULL); + htmlCtxtReadFile(ctxt, filename, NULL, options); + htmlFreeParserCtxt(ctxt); + ret = 0; + } else +#endif + { + debugContext userData; + xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename); + + if (options & XML_PARSE_SAX1) { + memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler)); + options -= XML_PARSE_SAX1; + } else { + memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler)); + } + userData.filename = filename; + userData.generalEntities = xmlHashCreate(0); + userData.parameterEntities = xmlHashCreate(0); + ctxt->userData = &userData; + xmlCtxtUseOptions(ctxt, options); + xmlParseDocument(ctxt); + ret = ctxt->wellFormed ? 0 : ctxt->errNo; + xmlHashFree(userData.generalEntities, hashFreeEntity); + xmlHashFree(userData.parameterEntities, hashFreeEntity); + xmlFreeDoc(ctxt->myDoc); + xmlFreeParserCtxt(ctxt); + } + fclose(SAXdebug); + if (compareFiles(temp, result)) { + fprintf(stderr, "Got a difference for %s\n", filename); + ret = 1; + } + +done: + if (temp != NULL) { + unlink(temp); + free(temp); + } + + return(ret); +} + +/************************************************************************ + * * + * Parse to tree based tests * + * * + ************************************************************************/ +/** + * oldParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file using the old xmlParseFile API, then serialize back + * reparse the result and serialize again, then check for deviation + * in serialization. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +oldParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + xmlDocPtr doc; + char *temp; + int res = 0; + + nb_tests++; + /* + * base of the test, parse with the old API + */ +#ifdef LIBXML_SAX1_ENABLED + xmlGetWarningsDefaultValue = 0; + doc = xmlParseFile(filename); + xmlGetWarningsDefaultValue = 1; +#else + doc = xmlReadFile(filename, NULL, XML_PARSE_NOWARNING); +#endif + if (doc == NULL) + return(1); + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "out of memory\n"); + fatalError(); + } + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + /* + * Parse the saved result to make sure the round trip is okay + */ +#ifdef LIBXML_SAX1_ENABLED + xmlGetWarningsDefaultValue = 0; + doc = xmlParseFile(temp); + xmlGetWarningsDefaultValue = 1; +#else + doc = xmlReadFile(temp, NULL, XML_PARSE_NOWARNING); +#endif + if (doc == NULL) + return(1); + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + if (temp != NULL) { + unlink(temp); + free(temp); + } + + return(res); +} + +#ifdef LIBXML_PUSH_ENABLED +/** + * pushParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file using the Push API, then serialize back + * to check for content. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +pushParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + const char *base; + int size, res; + int cur = 0; + int chunkSize = 4; + + nb_tests++; + /* + * load the document in memory and work from there. + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + if (chunkSize > size) + chunkSize = size; + +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename, + XML_CHAR_ENCODING_NONE); + else +#endif + ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + xmlCtxtUseOptions(ctxt, options); + cur += chunkSize; + chunkSize = 1024; + do { + if (cur + chunkSize >= size) { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlParseChunk(ctxt, base + cur, size - cur, 1); + else +#endif + xmlParseChunk(ctxt, base + cur, size - cur, 1); + break; + } else { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlParseChunk(ctxt, base + cur, chunkSize, 0); + else +#endif + xmlParseChunk(ctxt, base + cur, chunkSize, 0); + cur += chunkSize; + } + } while (cur < size); + doc = ctxt->myDoc; +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + res = 1; + else +#endif + res = ctxt->wellFormed; + xmlFreeParserCtxt(ctxt); + free((char *)base); + if (!res) { + xmlFreeDoc(doc); + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + xmlFreeDoc(doc); + res = compareFileMem(result, base, size); + if ((base == NULL) || (res != 0)) { + if (base != NULL) + xmlFree((char *)base); + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + xmlFree((char *)base); + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } + return(0); +} + +static int pushBoundaryCount; +static int pushBoundaryRefCount; +static int pushBoundaryCharsCount; +static int pushBoundaryCDataCount; + +static void +internalSubsetBnd(void *ctx, const xmlChar *name, const xmlChar *externalID, + const xmlChar *systemID) { + pushBoundaryCount++; + xmlSAX2InternalSubset(ctx, name, externalID, systemID); +} + +static void +referenceBnd(void *ctx, const xmlChar *name) { + pushBoundaryRefCount++; + xmlSAX2Reference(ctx, name); +} + +static void +charactersBnd(void *ctx, const xmlChar *ch, int len) { + pushBoundaryCount++; + pushBoundaryCharsCount++; + xmlSAX2Characters(ctx, ch, len); +} + +static void +cdataBlockBnd(void *ctx, const xmlChar *ch, int len) { + pushBoundaryCount++; + pushBoundaryCDataCount++; + xmlSAX2CDataBlock(ctx, ch, len); +} + +static void +processingInstructionBnd(void *ctx, const xmlChar *target, + const xmlChar *data) { + pushBoundaryCount++; + xmlSAX2ProcessingInstruction(ctx, target, data); +} + +static void +commentBnd(void *ctx, const xmlChar *value) { + xmlParserCtxtPtr ctxt = ctx; + if (ctxt->inSubset == 0) + pushBoundaryCount++; + xmlSAX2Comment(ctx, value); +} + +static void +startElementBnd(void *ctx, const xmlChar *xname, const xmlChar **atts) { + const char *name = (const char *)xname; + + /* Some elements might be created automatically. */ + if ((strcmp(name, "html") != 0) && + (strcmp(name, "body") != 0) && + (strcmp(name, "head") != 0) && + (strcmp(name, "p") != 0)) { + pushBoundaryCount++; + } + xmlSAX2StartElement(ctx, xname, atts); +} + +static void +endElementBnd(void *ctx, const xmlChar *name) { + /*pushBoundaryCount++;*/ + xmlSAX2EndElement(ctx, name); +} + +static void +startElementNsBnd(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) { + pushBoundaryCount++; + xmlSAX2StartElementNs(ctx, localname, prefix, URI, nb_namespaces, + namespaces, nb_attributes, nb_defaulted, attributes); +} + +static void +endElementNsBnd(void *ctx, const xmlChar *localname, const xmlChar *prefix, + const xmlChar *URI) { + /*pushBoundaryCount++;*/ + xmlSAX2EndElementNs(ctx, localname, prefix, URI); +} + +/** + * pushBoundaryTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Test whether the push parser detects boundaries between syntactical + * elements correctly. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +pushBoundaryTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlSAXHandler bndSAX; + const char *base; + int size, res, numCallbacks; + int cur = 0; + unsigned long avail, oldConsumed, consumed; + + /* + * HTML encoding detection doesn't work when data is fed bytewise. + */ + if (strcmp(filename, "./test/HTML/xml-declaration-1.html") == 0) + return(0); + + /* + * If the parser made progress, check that exactly one construct was + * processed and that the input buffer is (almost) empty. + * Since we use a chunk size of 1, this tests whether content is + * processed as early as possible. + */ + + nb_tests++; + + memset(&bndSAX, 0, sizeof(bndSAX)); +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + xmlSAX2InitHtmlDefaultSAXHandler(&bndSAX); + bndSAX.startElement = startElementBnd; + bndSAX.endElement = endElementBnd; + } else +#endif + { + xmlSAXVersion(&bndSAX, 2); + bndSAX.startElementNs = startElementNsBnd; + bndSAX.endElementNs = endElementNsBnd; + } + + bndSAX.internalSubset = internalSubsetBnd; + bndSAX.reference = referenceBnd; + bndSAX.characters = charactersBnd; + bndSAX.cdataBlock = cdataBlockBnd; + bndSAX.processingInstruction = processingInstructionBnd; + bndSAX.comment = commentBnd; + + /* + * load the document in memory and work from there. + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + ctxt = htmlCreatePushParserCtxt(&bndSAX, NULL, base, 1, filename, + XML_CHAR_ENCODING_NONE); + else +#endif + ctxt = xmlCreatePushParserCtxt(&bndSAX, NULL, base, 1, filename); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + xmlCtxtUseOptions(ctxt, options); + cur = 1; + consumed = 0; + numCallbacks = 0; + avail = 0; + while ((cur < size) && (numCallbacks <= 1) && (avail <= 0)) { + int terminate = (cur + 1 >= size); + int isText = 0; + + if (ctxt->instate == XML_PARSER_CONTENT) { + int firstChar = (ctxt->input->end > ctxt->input->cur) ? + *ctxt->input->cur : + base[cur]; + + if ((firstChar != '<') && + ((options & XML_PARSE_HTML) || (firstChar != '&'))) + isText = 1; + } + + oldConsumed = ctxt->input->consumed + + (unsigned long) (ctxt->input->cur - ctxt->input->base); + + pushBoundaryCount = 0; + pushBoundaryRefCount = 0; + pushBoundaryCharsCount = 0; + pushBoundaryCDataCount = 0; + +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlParseChunk(ctxt, base + cur, 1, terminate); + else +#endif + xmlParseChunk(ctxt, base + cur, 1, terminate); + cur += 1; + + /* + * Callback check: Check that only a single construct was parsed. + */ + if (pushBoundaryRefCount > 0) { + numCallbacks = 1; + } else { + numCallbacks = pushBoundaryCount; + if (pushBoundaryCharsCount > 1) { + if (options & XML_PARSE_HTML) { + /* + * The HTML parser can generate a mix of chars and + * references. + */ + numCallbacks -= pushBoundaryCharsCount - 1; + } else { + /* + * Allow two chars callbacks. This can happen when + * multi-byte chars are split across buffer boundaries. + */ + numCallbacks -= 1; + } + } + if (options & XML_PARSE_HTML) { + /* + * Allow multiple cdata callbacks in HTML mode. + */ + if (pushBoundaryCDataCount > 1) + numCallbacks -= pushBoundaryCDataCount - 1; + } + } + + /* + * Buffer check: If input was consumed, check that the input + * buffer is (almost) empty. + */ + consumed = ctxt->input->consumed + + (unsigned long) (ctxt->input->cur - ctxt->input->base); + if ((ctxt->instate != XML_PARSER_DTD) && + (consumed >= 4) && + (consumed != oldConsumed)) { + size_t max = 0; + + avail = ctxt->input->end - ctxt->input->cur; + + if ((options & XML_PARSE_HTML) && + (ctxt->instate == XML_PARSER_END_TAG)) { + /* Something related to script parsing. */ + max = 3; + } else if (isText) { + int c = *ctxt->input->cur; + + /* 3 bytes for partial UTF-8 */ + max = ((c == '<') || (c == '&')) ? 1 : 3; + } else if (ctxt->instate == XML_PARSER_CDATA_SECTION) { + /* 2 bytes for terminator, 3 bytes for UTF-8 */ + max = 5; + } + + if (avail <= max) + avail = 0; + } + } + doc = ctxt->myDoc; +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + res = 1; + else +#endif + res = ctxt->wellFormed; + xmlFreeParserCtxt(ctxt); + free((char *)base); + if (numCallbacks > 1) { + xmlFreeDoc(doc); + fprintf(stderr, "Failed push boundary callback test (%d@%lu-%lu): %s\n", + numCallbacks, oldConsumed, consumed, filename); + return(-1); + } + if (avail > 0) { + xmlFreeDoc(doc); + fprintf(stderr, "Failed push boundary buffer test (%lu@%lu): %s\n", + avail, consumed, filename); + return(-1); + } + if (!res) { + xmlFreeDoc(doc); + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + xmlFreeDoc(doc); + res = compareFileMem(result, base, size); + if ((base == NULL) || (res != 0)) { + if (base != NULL) + xmlFree((char *)base); + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + xmlFree((char *)base); + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } + return(0); +} +#endif + +/** + * memParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file using the old xmlReadMemory API, then serialize back + * reparse the result and serialize again, then check for deviation + * in serialization. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +memParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + xmlDocPtr doc; + const char *base; + int size, res; + + nb_tests++; + /* + * load and parse the memory + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + doc = xmlReadMemory(base, size, filename, NULL, XML_PARSE_NOWARNING); + unloadMem(base); + if (doc == NULL) { + return(1); + } + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + xmlFreeDoc(doc); + res = compareFileMem(result, base, size); + if ((base == NULL) || (res != 0)) { + if (base != NULL) + xmlFree((char *)base); + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + xmlFree((char *)base); + return(0); +} + +/** + * noentParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file with entity resolution, then serialize back + * reparse the result and serialize again, then check for deviation + * in serialization. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +noentParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlDocPtr doc; + char *temp; + int res = 0; + + nb_tests++; + /* + * base of the test, parse with the old API + */ + doc = xmlReadFile(filename, NULL, + options | XML_PARSE_NOWARNING | XML_PARSE_NOERROR); + if (doc == NULL) + return(1); + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + /* + * Parse the saved result to make sure the round trip is okay + */ + doc = xmlReadFile(filename, NULL, + options | XML_PARSE_NOWARNING | XML_PARSE_NOERROR); + if (doc == NULL) + return(1); + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(res); +} + +/** + * errParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the xmlReadFile API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +errParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + const char *base = NULL; + int size, res = 0; + + nb_tests++; +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + ctxt = htmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + doc = htmlCtxtReadFile(ctxt, filename, NULL, options); + htmlFreeParserCtxt(ctxt); + } else +#endif + { + ctxt = xmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + xmlFreeParserCtxt(ctxt); +#ifdef LIBXML_XINCLUDE_ENABLED + if (options & XML_PARSE_XINCLUDE) { + xmlXIncludeCtxtPtr xinc = NULL; + + xinc = xmlXIncludeNewContext(doc); + xmlXIncludeSetErrorHandler(xinc, testStructuredErrorHandler, NULL); + xmlXIncludeSetFlags(xinc, options); + if (xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc) < 0) { + testErrorHandler(NULL, "%s : failed to parse\n", filename); + xmlFreeDoc(doc); + doc = NULL; + } + xmlXIncludeFreeContext(xinc); + } +#endif + } + if (result) { + if (doc == NULL) { + base = ""; + size = 0; + } else { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } + res = compareFileMem(result, base, size); + } + if (doc != NULL) { + if (base != NULL) + xmlFree((char *)base); + xmlFreeDoc(doc); + } + if (res != 0) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } else if (options & XML_PARSE_DTDVALID) { + if (testErrorsSize != 0) + fprintf(stderr, "Validation for %s failed\n", filename); + } + + return(0); +} + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_HTML_ENABLED) +/** + * fdParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the xmlReadFd API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +fdParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + const char *base = NULL; + int size, res = 0, fd; + + nb_tests++; + fd = open(filename, RD_FLAGS); +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + ctxt = htmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + doc = htmlCtxtReadFd(ctxt, fd, filename, NULL, options); + htmlFreeParserCtxt(ctxt); + } else +#endif + { + ctxt = xmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + doc = xmlCtxtReadFd(ctxt, fd, filename, NULL, options); + xmlFreeParserCtxt(ctxt); + } + close(fd); + if (result) { + if (doc == NULL) { + base = ""; + size = 0; + } else { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } + res = compareFileMem(result, base, size); + } + if (doc != NULL) { + if (base != NULL) + xmlFree((char *)base); + xmlFreeDoc(doc); + } + if (res != 0) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } else if (options & XML_PARSE_DTDVALID) { + if (testErrorsSize != 0) + fprintf(stderr, "Validation for %s failed\n", filename); + } + + return(0); +} +#endif + + +#ifdef LIBXML_READER_ENABLED +/************************************************************************ + * * + * Reader based tests * + * * + ************************************************************************/ + +static void processNode(FILE *out, xmlTextReaderPtr reader) { + const xmlChar *name, *value; + int type, empty; + + type = xmlTextReaderNodeType(reader); + empty = xmlTextReaderIsEmptyElement(reader); + + name = xmlTextReaderConstName(reader); + if (name == NULL) + name = BAD_CAST "--"; + + value = xmlTextReaderConstValue(reader); + + + fprintf(out, "%d %d %s %d %d", + xmlTextReaderDepth(reader), + type, + name, + empty, + xmlTextReaderHasValue(reader)); + if (value == NULL) + fprintf(out, "\n"); + else { + fprintf(out, " %s\n", value); + } +} +static int +streamProcessTest(const char *filename, const char *result, const char *err, + xmlTextReaderPtr reader, const char *rng, + int options ATTRIBUTE_UNUSED) { + int ret; + char *temp = NULL; + FILE *t = NULL; + + if (reader == NULL) + return(-1); + + nb_tests++; + if (result != NULL) { + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + t = fopen(temp, "wb"); + if (t == NULL) { + fprintf(stderr, "Can't open temp file %s\n", temp); + free(temp); + return(-1); + } + } +#ifdef LIBXML_SCHEMAS_ENABLED + if (rng != NULL) { + ret = xmlTextReaderRelaxNGValidate(reader, rng); + if (ret < 0) { + testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", + rng); + fclose(t); + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(0); + } + } +#endif + ret = xmlTextReaderRead(reader); + while (ret == 1) { + if ((t != NULL) && (rng == NULL)) + processNode(t, reader); + ret = xmlTextReaderRead(reader); + } + if (ret != 0) { + testErrorHandler(NULL, "%s : failed to parse\n", filename); + } + if (rng != NULL) { + if (xmlTextReaderIsValid(reader) != 1) { + testErrorHandler(NULL, "%s fails to validate\n", filename); + } else { + testErrorHandler(NULL, "%s validates\n", filename); + } + } + if (t != NULL) { + fclose(t); + ret = compareFiles(temp, result); + if (temp != NULL) { + unlink(temp); + free(temp); + } + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + return(-1); + } + } + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + printf("%s", testErrors); + return(-1); + } + } + + return(0); +} + +/** + * streamParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the reader API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +streamParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlTextReaderPtr reader; + int ret; + + reader = xmlReaderForFile(filename, NULL, options); + xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler, + NULL); + ret = streamProcessTest(filename, result, err, reader, NULL, options); + xmlFreeTextReader(reader); + return(ret); +} + +/** + * walkerParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the walker, i.e. a reader built from a atree. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +walkerParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlDocPtr doc; + xmlTextReaderPtr reader; + int ret; + + doc = xmlReadFile(filename, NULL, options | XML_PARSE_NOWARNING); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } + reader = xmlReaderWalker(doc); + ret = streamProcessTest(filename, result, err, reader, NULL, options); + xmlFreeTextReader(reader); + xmlFreeDoc(doc); + return(ret); +} + +/** + * streamMemParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the reader API from memory and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +streamMemParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlTextReaderPtr reader; + int ret; + const char *base; + int size; + + /* + * load and parse the memory + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + reader = xmlReaderForMemory(base, size, filename, NULL, options); + xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler, + NULL); + ret = streamProcessTest(filename, result, err, reader, NULL, options); + free((char *)base); + xmlFreeTextReader(reader); + return(ret); +} +#endif + +#ifdef LIBXML_XPATH_ENABLED +#ifdef LIBXML_DEBUG_ENABLED +/************************************************************************ + * * + * XPath and XPointer based tests * + * * + ************************************************************************/ + +static FILE *xpathOutput; +static xmlDocPtr xpathDocument; + +static void +testXPath(const char *str, int xptr, int expr) { + xmlXPathObjectPtr res; + xmlXPathContextPtr ctxt; + + nb_tests++; +#if defined(LIBXML_XPTR_ENABLED) + if (xptr) { + ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL); + xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + res = xmlXPtrEval(BAD_CAST str, ctxt); + } else { +#endif + ctxt = xmlXPathNewContext(xpathDocument); + xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + ctxt->node = xmlDocGetRootElement(xpathDocument); + if (expr) + res = xmlXPathEvalExpression(BAD_CAST str, ctxt); + else { + /* res = xmlXPathEval(BAD_CAST str, ctxt); */ + xmlXPathCompExprPtr comp; + + comp = xmlXPathCompile(BAD_CAST str); + if (comp != NULL) { + res = xmlXPathCompiledEval(comp, ctxt); + xmlXPathFreeCompExpr(comp); + } else + res = NULL; + } +#if defined(LIBXML_XPTR_ENABLED) + } +#endif + xmlXPathDebugDumpObject(xpathOutput, res, 0); + xmlXPathFreeObject(res); + xmlXPathFreeContext(ctxt); +} + +/** + * xpathExprTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath standalone expressions and evaluate them + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathCommonTest(const char *filename, const char *result, + int xptr, int expr) { + FILE *input; + char expression[5000]; + int len, ret = 0; + char *temp; + + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xpathOutput = fopen(temp, "wb"); + if (xpathOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + + input = fopen(filename, "rb"); + if (input == NULL) { + fprintf(stderr, + "Cannot open %s for reading\n", filename); + free(temp); + return(-1); + } + while (fgets(expression, 4500, input) != NULL) { + len = strlen(expression); + len--; + while ((len >= 0) && + ((expression[len] == '\n') || (expression[len] == '\t') || + (expression[len] == '\r') || (expression[len] == ' '))) len--; + expression[len + 1] = 0; + if (len >= 0) { + fprintf(xpathOutput, + "\n========================\nExpression: %s\n", + expression) ; + testXPath(expression, xptr, expr); + } + } + + fclose(input); + fclose(xpathOutput); + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + } + } + + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(ret); +} + +/** + * xpathExprTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath standalone expressions and evaluate them + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathExprTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(xpathCommonTest(filename, result, 0, 1)); +} + +/** + * xpathDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath expressions and evaluate them against + * a set of corresponding documents. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathDocTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + + char pattern[500]; + char result[500]; + glob_t globbuf; + size_t i; + int ret = 0, res; + + xpathDocument = xmlReadFile(filename, NULL, + options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + res = snprintf(pattern, 499, "./test/XPath/tests/%s*", + baseFilename(filename)); + if (res >= 499) + pattern[499] = 0; + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + res = snprintf(result, 499, "result/XPath/tests/%s", + baseFilename(globbuf.gl_pathv[i])); + if (res >= 499) + result[499] = 0; + res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0); + if (res != 0) + ret = res; + } + globfree(&globbuf); + + xmlFreeDoc(xpathDocument); + return(ret); +} + +#ifdef LIBXML_XPTR_ENABLED +/** + * xptrDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath expressions and evaluate them against + * a set of corresponding documents. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xptrDocTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + + char pattern[500]; + char result[500]; + glob_t globbuf; + size_t i; + int ret = 0, res; + const char *subdir = options == -1 ? "xptr-xp1" : "xptr"; + + xpathDocument = xmlReadFile(filename, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + res = snprintf(pattern, 499, "./test/XPath/%s/%s*", + subdir, baseFilename(filename)); + if (res >= 499) + pattern[499] = 0; + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + res = snprintf(result, 499, "result/XPath/%s/%s", + subdir, baseFilename(globbuf.gl_pathv[i])); + if (res >= 499) + result[499] = 0; + res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0); + if (res != 0) + ret = res; + } + globfree(&globbuf); + + xmlFreeDoc(xpathDocument); + return(ret); +} +#endif /* LIBXML_XPTR_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +/** + * xmlidDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing xml:id and check for errors and verify + * that XPath queries will work on them as expected. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xmlidDocTest(const char *filename, + const char *result, + const char *err, + int options) { + xmlParserCtxtPtr ctxt; + int res = 0; + int ret = 0; + char *temp; + + ctxt = xmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL); + xpathDocument = xmlCtxtReadFile(ctxt, filename, NULL, + options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); + xmlFreeParserCtxt(ctxt); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xpathOutput = fopen(temp, "wb"); + if (xpathOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + xmlFreeDoc(xpathDocument); + free(temp); + return(-1); + } + + testXPath("id('bar')", 0, 0); + + fclose(xpathOutput); + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + res = 1; + } + } + + if (temp != NULL) { + unlink(temp); + free(temp); + } + xmlFreeDoc(xpathDocument); + + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + res = 1; + } + } + return(res); +} +#endif /* LIBXML_VALID_ENABLED */ + +#endif /* LIBXML_DEBUG_ENABLED */ +#endif /* XPATH */ +/************************************************************************ + * * + * URI based tests * + * * + ************************************************************************/ + +static void +handleURI(const char *str, const char *base, FILE *o) { + int ret; + xmlURIPtr uri; + xmlChar *res = NULL; + + uri = xmlCreateURI(); + + if (base == NULL) { + ret = xmlParseURIReference(uri, str); + if (ret != 0) + fprintf(o, "%s : error %d\n", str, ret); + else { + xmlNormalizeURIPath(uri->path); + xmlPrintURI(o, uri); + fprintf(o, "\n"); + } + } else { + res = xmlBuildURI((xmlChar *)str, (xmlChar *) base); + if (res != NULL) { + fprintf(o, "%s\n", (char *) res); + } + else + fprintf(o, "::ERROR::\n"); + } + if (res != NULL) + xmlFree(res); + xmlFreeURI(uri); +} + +/** + * uriCommonTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI and check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriCommonTest(const char *filename, + const char *result, + const char *err, + const char *base) { + char *temp; + FILE *o, *f; + char str[1024]; + int res = 0, i, ret; + + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + o = fopen(temp, "wb"); + if (o == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "failed to open input file %s\n", filename); + fclose(o); + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(-1); + } + + while (1) { + /* + * read one line in string buffer. + */ + if (fgets (&str[0], sizeof (str) - 1, f) == NULL) + break; + + /* + * remove the ending spaces + */ + i = strlen(str); + while ((i > 0) && + ((str[i - 1] == '\n') || (str[i - 1] == '\r') || + (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { + i--; + str[i] = 0; + } + nb_tests++; + handleURI(str, base, o); + } + + fclose(f); + fclose(o); + + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + res = 1; + } + } + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + res = 1; + } + } + + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(res); +} + +/** + * uriParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI and check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriParseTest(const char *filename, + const char *result, + const char *err, + int options ATTRIBUTE_UNUSED) { + return(uriCommonTest(filename, result, err, NULL)); +} + +/** + * uriBaseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI, compose them against a fixed base and + * check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriBaseTest(const char *filename, + const char *result, + const char *err, + int options ATTRIBUTE_UNUSED) { + return(uriCommonTest(filename, result, err, + "http://foo.com/path/to/index.html?orig#help")); +} + +static int urip_success = 1; +static int urip_current = 0; +static const char *urip_testURLs[] = { + "urip://example.com/a b.html", + "urip://example.com/a%20b.html", + "file:///path/to/a b.html", + "file:///path/to/a%20b.html", + "/path/to/a b.html", + "/path/to/a%20b.html", + "urip://example.com/r" "\xe9" "sum" "\xe9" ".html", + "urip://example.com/test?a=1&b=2%263&c=4#foo", + NULL +}; +static const char *urip_rcvsURLs[] = { + /* it is an URI the strings must be escaped */ + "urip://example.com/a%20b.html", + /* check that % escaping is not broken */ + "urip://example.com/a%20b.html", + /* it's an URI path the strings must be escaped */ + "file:///path/to/a%20b.html", + /* check that % escaping is not broken */ + "file:///path/to/a%20b.html", + /* this is not an URI, this is a path, so this should not be escaped */ + "/path/to/a b.html", + /* check that paths with % are not broken */ + "/path/to/a%20b.html", + /* out of context the encoding can't be guessed byte by byte conversion */ + "urip://example.com/r%E9sum%E9.html", + /* verify we don't destroy URIs especially the query part */ + "urip://example.com/test?a=1&b=2%263&c=4#foo", + NULL +}; +static const char *urip_res = ""; +static const char *urip_cur = NULL; +static int urip_rlen; + +/** + * uripMatch: + * @URI: an URI to test + * + * Check for an urip: query + * + * Returns 1 if yes and 0 if another Input module should be used + */ +static int +uripMatch(const char * URI) { + if ((URI == NULL) || (!strcmp(URI, "file://" SYSCONFDIR "/xml/catalog"))) + return(0); + /* Verify we received the escaped URL */ + if (strcmp(urip_rcvsURLs[urip_current], URI)) + urip_success = 0; + return(1); +} + +/** + * uripOpen: + * @URI: an URI to test + * + * Return a pointer to the urip: query handler, in this example simply + * the urip_current pointer... + * + * Returns an Input context or NULL in case or error + */ +static void * +uripOpen(const char * URI) { + if ((URI == NULL) || (!strcmp(URI, "file://" SYSCONFDIR "/xml/catalog"))) + return(NULL); + /* Verify we received the escaped URL */ + if (strcmp(urip_rcvsURLs[urip_current], URI)) + urip_success = 0; + urip_cur = urip_res; + urip_rlen = strlen(urip_res); + return((void *) urip_cur); +} + +/** + * uripClose: + * @context: the read context + * + * Close the urip: query handler + * + * Returns 0 or -1 in case of error + */ +static int +uripClose(void * context) { + if (context == NULL) return(-1); + urip_cur = NULL; + urip_rlen = 0; + return(0); +} + +/** + * uripRead: + * @context: the read context + * @buffer: where to store data + * @len: number of bytes to read + * + * Implement an urip: query read. + * + * Returns the number of bytes read or -1 in case of error + */ +static int +uripRead(void * context, char * buffer, int len) { + const char *ptr = (const char *) context; + + if ((context == NULL) || (buffer == NULL) || (len < 0)) + return(-1); + + if (len > urip_rlen) len = urip_rlen; + memcpy(buffer, ptr, len); + urip_rlen -= len; + return(len); +} + +static int +urip_checkURL(const char *URL) { + xmlDocPtr doc; + + doc = xmlReadFile(URL, NULL, 0); + if (doc == NULL) + return(-1); + xmlFreeDoc(doc); + return(1); +} + +/** + * uriPathTest: + * @filename: ignored + * @result: ignored + * @err: ignored + * + * Run a set of tests to check how Path and URI are handled before + * being passed to the I/O layer + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriPathTest(const char *filename ATTRIBUTE_UNUSED, + const char *result ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + int parsed; + int failures = 0; + + /* + * register the new I/O handlers + */ + if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0) + { + fprintf(stderr, "failed to register HTTP handler\n"); + return(-1); + } + + for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) { + urip_success = 1; + parsed = urip_checkURL(urip_testURLs[urip_current]); + if (urip_success != 1) { + fprintf(stderr, "failed the URL passing test for %s", + urip_testURLs[urip_current]); + failures++; + } else if (parsed != 1) { + fprintf(stderr, "failed the parsing test for %s", + urip_testURLs[urip_current]); + failures++; + } + nb_tests++; + } + + xmlPopInputCallbacks(); + return(failures); +} + +#ifdef LIBXML_SCHEMAS_ENABLED +/************************************************************************ + * * + * Schemas tests * + * * + ************************************************************************/ +static int +schemasOneTest(const char *sch, + const char *filename, + const char *result, + const char *err, + int options, + xmlSchemaPtr schemas) { + int ret = 0; + int i; + char *temp; + int parseErrorsSize = testErrorsSize; + + temp = resultFilename(result, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + return(-1); + } + + /* + * Test both memory and streaming validation. + */ + for (i = 0; i < 2; i++) { + xmlSchemaValidCtxtPtr ctxt; + int validResult = 0; + FILE *schemasOutput; + + testErrorsSize = parseErrorsSize; + testErrors[parseErrorsSize] = 0; + + if (schemas == NULL) + goto done; + + ctxt = xmlSchemaNewValidCtxt(schemas); + xmlSchemaSetValidStructuredErrors(ctxt, testStructuredErrorHandler, + NULL); + + schemasOutput = fopen(temp, "wb"); + if (schemasOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + + if (i == 0) { + xmlDocPtr doc; + + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) { + fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); + return(-1); + } + validResult = xmlSchemaValidateDoc(ctxt, doc); + xmlFreeDoc(doc); + } else { + validResult = xmlSchemaValidateFile(ctxt, filename, options); + } + + if (validResult == 0) { + fprintf(schemasOutput, "%s validates\n", filename); + } else if (validResult > 0) { + fprintf(schemasOutput, "%s fails to validate\n", filename); + } else { + fprintf(schemasOutput, "%s validation generated an internal error\n", + filename); + } + fclose(schemasOutput); + + if (result) { + if (compareFiles(temp, result)) { + fprintf(stderr, "Result for %s on %s failed\n", filename, sch); + ret = 1; + } + } + + xmlSchemaFreeValidCtxt(ctxt); + +done: + if (compareFileMem(err, testErrors, testErrorsSize)) { + fprintf(stderr, "Error for %s on %s failed\n", filename, sch); + ret = 1; + } + + unlink(temp); + } + + free(temp); + return(ret); +} +/** + * schemasTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI, compose them against a fixed base and + * check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +schemasTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + xmlSchemaParserCtxtPtr ctxt; + xmlSchemaPtr schemas; + int res = 0, len, ret; + int parseErrorsSize; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + + /* first compile the schemas if possible */ + ctxt = xmlSchemaNewParserCtxt(filename); + xmlSchemaSetParserStructuredErrors(ctxt, testStructuredErrorHandler, NULL); + schemas = xmlSchemaParse(ctxt); + xmlSchemaFreeParserCtxt(ctxt); + parseErrorsSize = testErrorsSize; + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + xmlSchemaFree(schemas); + return(-1); + } + len -= 4; /* remove trailing .xsd */ + if (base[len - 2] == '_') { + len -= 2; /* remove subtest number */ + } + if (base[len - 2] == '_') { + len -= 2; /* remove subtest number */ + } + memcpy(prefix, base, len); + prefix[len] = 0; + + if (snprintf(pattern, 499, "./test/schemas/%s_*.xml", prefix) >= 499) + pattern[499] = 0; + + if (base[len] == '_') { + len += 2; + memcpy(prefix, base, len); + prefix[len] = 0; + } + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = parseErrorsSize; + testErrors[parseErrorsSize] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + ret = snprintf(result, 499, "result/schemas/%s_%c", + prefix, count); + if (ret >= 499) + result[499] = 0; + ret = snprintf(err, 499, "result/schemas/%s_%c.err", + prefix, count); + if (ret >= 499) + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + + nb_tests++; + ret = schemasOneTest(filename, instance, result, err, + options, schemas); + if (ret != 0) + res = ret; + } + globfree(&globbuf); + xmlSchemaFree(schemas); + + return(res); +} + +/************************************************************************ + * * + * Schemas tests * + * * + ************************************************************************/ +static int +rngOneTest(const char *sch, + const char *filename, + const char *result, + int options, + xmlRelaxNGPtr schemas) { + xmlDocPtr doc; + xmlRelaxNGValidCtxtPtr ctxt; + int ret = 0; + char *temp; + FILE *schemasOutput; + + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) { + fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); + return(-1); + } + + temp = resultFilename(result, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + schemasOutput = fopen(temp, "wb"); + if (schemasOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + xmlFreeDoc(doc); + free(temp); + return(-1); + } + + ctxt = xmlRelaxNGNewValidCtxt(schemas); + xmlRelaxNGSetValidStructuredErrors(ctxt, testStructuredErrorHandler, NULL); + ret = xmlRelaxNGValidateDoc(ctxt, doc); + if (ret == 0) { + testErrorHandler(NULL, "%s validates\n", filename); + } else if (ret > 0) { + testErrorHandler(NULL, "%s fails to validate\n", filename); + } else { + testErrorHandler(NULL, "%s validation generated an internal error\n", + filename); + } + fclose(schemasOutput); + ret = 0; + if (result) { + if (compareFiles(temp, result)) { + fprintf(stderr, "Result for %s on %s failed\n", filename, sch); + ret = 1; + } + } + if (temp != NULL) { + unlink(temp); + free(temp); + } + + xmlRelaxNGFreeValidCtxt(ctxt); + xmlFreeDoc(doc); + return(ret); +} +/** + * rngTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse an RNG schemas and then apply it to the related .xml + * + * Returns 0 in case of success, an error code otherwise + */ +static int +rngTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + xmlRelaxNGParserCtxtPtr ctxt; + xmlRelaxNGPtr schemas; + int res = 0, len, ret = 0; + int parseErrorsSize; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + + /* first compile the schemas if possible */ + ctxt = xmlRelaxNGNewParserCtxt(filename); + xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler, + NULL); + schemas = xmlRelaxNGParse(ctxt); + xmlRelaxNGFreeParserCtxt(ctxt); + if (schemas == NULL) + testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", + filename); + parseErrorsSize = testErrorsSize; + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + xmlRelaxNGFree(schemas); + return(-1); + } + len -= 4; /* remove trailing .rng */ + memcpy(prefix, base, len); + prefix[len] = 0; + + if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499) + pattern[499] = 0; + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = parseErrorsSize; + testErrors[parseErrorsSize] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + res = snprintf(result, 499, "result/relaxng/%s_%c", + prefix, count); + if (res >= 499) + result[499] = 0; + res = snprintf(err, 499, "result/relaxng/%s_%c.err", + prefix, count); + if (res >= 499) + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + if (schemas != NULL) { + nb_tests++; + res = rngOneTest(filename, instance, result, options, schemas); + if (res != 0) + ret = res; + } + if (compareFileMem(err, testErrors, testErrorsSize)) { + fprintf(stderr, "Error for %s on %s failed\n", instance, + filename); + ret = 1; + } + } + globfree(&globbuf); + xmlRelaxNGFree(schemas); + + return(ret); +} + +#ifdef LIBXML_READER_ENABLED +/** + * rngStreamTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a set of files with streaming, applying an RNG schemas + * + * Returns 0 in case of success, an error code otherwise + */ +static int +rngStreamTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + int res = 0, len, ret; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + xmlTextReaderPtr reader; + int disable_err = 0; + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + fprintf(stderr, "len(base) == %d !\n", len); + return(-1); + } + len -= 4; /* remove trailing .rng */ + memcpy(prefix, base, len); + prefix[len] = 0; + + /* + * strictly unifying the error messages is nearly impossible this + * hack is also done in the Makefile + */ + if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) || + (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) || + (!strcmp(prefix, "tutor8_2"))) + disable_err = 1; + + if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499) + pattern[499] = 0; + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = 0; + testErrors[0] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + ret = snprintf(result, 499, "result/relaxng/%s_%c", + prefix, count); + if (ret >= 499) + result[499] = 0; + ret = snprintf(err, 499, "result/relaxng/%s_%c.err", + prefix, count); + if (ret >= 499) + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + reader = xmlReaderForFile(instance, NULL, options); + xmlTextReaderSetStructuredErrorHandler(reader, + testStructuredErrorHandler, NULL); + if (reader == NULL) { + fprintf(stderr, "Failed to build reader for %s\n", instance); + } + if (disable_err == 1) + ret = streamProcessTest(instance, result, NULL, reader, filename, + options); + else + ret = streamProcessTest(instance, result, err, reader, filename, + options); + xmlFreeTextReader(reader); + if (ret != 0) { + fprintf(stderr, "instance %s failed\n", instance); + res = ret; + } + } + globfree(&globbuf); + + return(res); +} +#endif /* READER */ + +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#ifdef LIBXML_READER_ENABLED +/************************************************************************ + * * + * Patterns tests * + * * + ************************************************************************/ +static void patternNode(FILE *out, xmlTextReaderPtr reader, + const char *pattern, xmlPatternPtr patternc, + xmlStreamCtxtPtr patstream) { + xmlChar *path = NULL; + int match = -1; + int type, empty; + + type = xmlTextReaderNodeType(reader); + empty = xmlTextReaderIsEmptyElement(reader); + + if (type == XML_READER_TYPE_ELEMENT) { + /* do the check only on element start */ + match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); + + if (match) { + path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); + fprintf(out, "Node %s matches pattern %s\n", path, pattern); + } + } + if (patstream != NULL) { + int ret; + + if (type == XML_READER_TYPE_ELEMENT) { + ret = xmlStreamPush(patstream, + xmlTextReaderConstLocalName(reader), + xmlTextReaderConstNamespaceUri(reader)); + if (ret < 0) { + fprintf(out, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } else if (ret != match) { + if (path == NULL) { + path = xmlGetNodePath( + xmlTextReaderCurrentNode(reader)); + } + fprintf(out, + "xmlPatternMatch and xmlStreamPush disagree\n"); + fprintf(out, + " pattern %s node %s\n", + pattern, path); + } + + + } + if ((type == XML_READER_TYPE_END_ELEMENT) || + ((type == XML_READER_TYPE_ELEMENT) && (empty))) { + ret = xmlStreamPop(patstream); + if (ret < 0) { + fprintf(out, "xmlStreamPop() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } + if (path != NULL) + xmlFree(path); +} + +/** + * patternTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a set of files with streaming, applying an RNG schemas + * + * Returns 0 in case of success, an error code otherwise + */ +static int +patternTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlPatternPtr patternc = NULL; + xmlStreamCtxtPtr patstream = NULL; + FILE *o, *f; + char str[1024]; + char xml[500]; + char result[500]; + int len, i; + int ret = 0, res; + char *temp; + xmlTextReaderPtr reader; + xmlDocPtr doc; + + len = strlen(filename); + len -= 4; + memcpy(xml, filename, len); + xml[len] = 0; + if (snprintf(result, 499, "result/pattern/%s", baseFilename(xml)) >= 499) + result[499] = 0; + memcpy(xml + len, ".xml", 5); + + if (!checkTestFile(xml) && !update_results) { + fprintf(stderr, "Missing xml file %s\n", xml); + return(-1); + } + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "Failed to open %s\n", filename); + return(-1); + } + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + o = fopen(temp, "wb"); + if (o == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + fclose(f); + free(temp); + return(-1); + } + while (1) { + /* + * read one line in string buffer. + */ + if (fgets (&str[0], sizeof (str) - 1, f) == NULL) + break; + + /* + * remove the ending spaces + */ + i = strlen(str); + while ((i > 0) && + ((str[i - 1] == '\n') || (str[i - 1] == '\r') || + (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { + i--; + str[i] = 0; + } + doc = xmlReadFile(xml, NULL, options); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", xml); + ret = 1; + } else { + xmlNodePtr root; + const xmlChar *namespaces[22]; + int j; + xmlNsPtr ns; + + root = xmlDocGetRootElement(doc); + for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) { + namespaces[j++] = ns->href; + namespaces[j++] = ns->prefix; + } + namespaces[j++] = NULL; + namespaces[j] = NULL; + + patternc = xmlPatterncompile((const xmlChar *) str, doc->dict, + 0, &namespaces[0]); + if (patternc == NULL) { + testErrorHandler(NULL, + "Pattern %s failed to compile\n", str); + xmlFreeDoc(doc); + ret = 1; + continue; + } + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream != NULL) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + nb_tests++; + + reader = xmlReaderWalker(doc); + res = xmlTextReaderRead(reader); + while (res == 1) { + patternNode(o, reader, str, patternc, patstream); + res = xmlTextReaderRead(reader); + } + if (res != 0) { + fprintf(o, "%s : failed to parse\n", filename); + } + xmlFreeTextReader(reader); + xmlFreeDoc(doc); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + xmlFreePattern(patternc); + + } + } + + fclose(f); + fclose(o); + + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + ret = 1; + } + if (temp != NULL) { + unlink(temp); + free(temp); + } + return(ret); +} +#endif /* READER */ +#endif /* PATTERN */ +#ifdef LIBXML_C14N_ENABLED +/************************************************************************ + * * + * Canonicalization tests * + * * + ************************************************************************/ +static xmlXPathObjectPtr +load_xpath_expr (xmlDocPtr parent_doc, const char* filename) { + xmlXPathObjectPtr xpath; + xmlDocPtr doc; + xmlChar *expr; + xmlXPathContextPtr ctx; + xmlNodePtr node; + xmlNsPtr ns; + + /* + * load XPath expr as a file + */ + doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); + return(NULL); + } + + /* + * Check the document is of the right kind + */ + if(xmlDocGetRootElement(doc) == NULL) { + fprintf(stderr,"Error: empty document for file \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + node = doc->children; + while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) { + node = node->next; + } + + if(node == NULL) { + fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + expr = xmlNodeGetContent(node); + if(expr == NULL) { + fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + ctx = xmlXPathNewContext(parent_doc); + if(ctx == NULL) { + fprintf(stderr,"Error: unable to create new context\n"); + xmlFree(expr); + xmlFreeDoc(doc); + return(NULL); + } + + /* + * Register namespaces + */ + ns = node->nsDef; + while(ns != NULL) { + if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) { + fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href); + xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(NULL); + } + ns = ns->next; + } + + /* + * Evaluate xpath + */ + xpath = xmlXPathEvalExpression(expr, ctx); + if(xpath == NULL) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); +xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(NULL); + } + + /* print_xpath_nodes(xpath->nodesetval); */ + + xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(xpath); +} + +/* + * Macro used to grow the current buffer. + */ +#define xxx_growBufferReentrant() { \ + buffer_size *= 2; \ + buffer = (xmlChar **) \ + xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \ + if (buffer == NULL) { \ + perror("realloc failed"); \ + return(NULL); \ + } \ +} + +static xmlChar ** +parse_list(xmlChar *str) { + xmlChar **buffer; + xmlChar **out = NULL; + int buffer_size = 0; + int len; + + if(str == NULL) { + return(NULL); + } + + len = xmlStrlen(str); + if((str[0] == '\'') && (str[len - 1] == '\'')) { + str[len - 1] = '\0'; + str++; + } + /* + * allocate an translation buffer. + */ + buffer_size = 1000; + buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*)); + if (buffer == NULL) { + perror("malloc failed"); + return(NULL); + } + out = buffer; + + while(*str != '\0') { + if (out - buffer > buffer_size - 10) { + int indx = out - buffer; + + xxx_growBufferReentrant(); + out = &buffer[indx]; + } + (*out++) = str; + while(*str != ',' && *str != '\0') ++str; + if(*str == ',') *(str++) = '\0'; + } + (*out) = NULL; + return buffer; +} + +static int +c14nRunTest(const char* xml_filename, int with_comments, int mode, + const char* xpath_filename, const char *ns_filename, + const char* result_file) { + xmlDocPtr doc; + xmlXPathObjectPtr xpath = NULL; + xmlChar *result = NULL; + int ret; + xmlChar **inclusive_namespaces = NULL; + const char *nslist = NULL; + int nssize; + + + /* + * build an XML tree from a the file; we need to add default + * attributes and resolve all character and entities references + */ + doc = xmlReadFile(xml_filename, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT | XML_PARSE_NOWARNING); + if (doc == NULL) { + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename); + return(-1); + } + + /* + * Check the document is of the right kind + */ + if(xmlDocGetRootElement(doc) == NULL) { + fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename); + xmlFreeDoc(doc); + return(-1); + } + + /* + * load xpath file if specified + */ + if(xpath_filename) { + xpath = load_xpath_expr(doc, xpath_filename); + if(xpath == NULL) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); + xmlFreeDoc(doc); + return(-1); + } + } + + if (ns_filename != NULL) { + if (loadMem(ns_filename, &nslist, &nssize)) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); + if(xpath != NULL) xmlXPathFreeObject(xpath); + xmlFreeDoc(doc); + return(-1); + } + inclusive_namespaces = parse_list((xmlChar *) nslist); + } + + /* + * Canonical form + */ + /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */ + ret = xmlC14NDocDumpMemory(doc, + (xpath) ? xpath->nodesetval : NULL, + mode, inclusive_namespaces, + with_comments, &result); + if (ret >= 0) { + if(result != NULL) { + if (compareFileMem(result_file, (const char *) result, ret)) { + fprintf(stderr, "Result mismatch for %s\n", xml_filename); + fprintf(stderr, "RESULT:\n%s\n", (const char*)result); + ret = -1; + } + } + } else { + fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret); + ret = -1; + } + + /* + * Cleanup + */ + if (result != NULL) xmlFree(result); + if(xpath != NULL) xmlXPathFreeObject(xpath); + if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces); + if (nslist != NULL) free((char *) nslist); + xmlFreeDoc(doc); + + return(ret); +} + +static int +c14nCommonTest(const char *filename, int with_comments, int mode, + const char *subdir) { + char buf[500]; + char prefix[500]; + const char *base; + int len; + char *result = NULL; + char *xpath = NULL; + char *ns = NULL; + int ret = 0; + + base = baseFilename(filename); + len = strlen(base); + len -= 4; + memcpy(prefix, base, len); + prefix[len] = 0; + + if (snprintf(buf, 499, "result/c14n/%s/%s", subdir, prefix) >= 499) + buf[499] = 0; + result = strdup(buf); + if (snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir, prefix) >= 499) + buf[499] = 0; + if (checkTestFile(buf)) { + xpath = strdup(buf); + } + if (snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir, prefix) >= 499) + buf[499] = 0; + if (checkTestFile(buf)) { + ns = strdup(buf); + } + + nb_tests++; + if (c14nRunTest(filename, with_comments, mode, + xpath, ns, result) < 0) + ret = 1; + + if (result != NULL) free(result); + if (xpath != NULL) free(xpath); + if (ns != NULL) free(ns); + return(ret); +} + +static int +c14nWithCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments")); +} +static int +c14nWithoutCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments")); +} +static int +c14nExcWithoutCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments")); +} +static int +c14n11WithoutCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments")); +} +#endif +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +/************************************************************************ + * * + * Catalog and threads test * + * * + ************************************************************************/ + +/* + * mostly a cut and paste from testThreads.c + */ +#define MAX_ARGC 20 + +typedef struct { + const char *filename; + int okay; +} xmlThreadParams; + +static const char *catalog = "test/threads/complex.xml"; +static xmlThreadParams threadParams[] = { + { "test/threads/abc.xml", 0 }, + { "test/threads/acb.xml", 0 }, + { "test/threads/bac.xml", 0 }, + { "test/threads/bca.xml", 0 }, + { "test/threads/cab.xml", 0 }, + { "test/threads/cba.xml", 0 }, + { "test/threads/invalid.xml", 0 } +}; +static const unsigned int num_threads = sizeof(threadParams) / + sizeof(threadParams[0]); + +static void * +thread_specific_data(void *private_data) +{ + xmlDocPtr myDoc; + xmlThreadParams *params = (xmlThreadParams *) private_data; + const char *filename = params->filename; + int okay = 1; + +#ifdef LIBXML_THREAD_ALLOC_ENABLED + xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); +#endif + + myDoc = xmlReadFile(filename, NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD); + if (myDoc) { + xmlFreeDoc(myDoc); + } else { + printf("parse failed\n"); + okay = 0; + } + params->okay = okay; + return(NULL); +} + +#if defined(_WIN32) +#include +#include + +#define TEST_REPEAT_COUNT 500 + +static HANDLE tid[MAX_ARGC]; + +static DWORD WINAPI +win32_thread_specific_data(void *private_data) +{ + thread_specific_data(private_data); + return(0); +} + +static int +testThread(void) +{ + unsigned int i, repeat; + BOOL ret; + int res = 0; + + xmlInitParser(); + for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) { + xmlLoadCatalog(catalog); + nb_tests++; + + for (i = 0; i < num_threads; i++) { + tid[i] = (HANDLE) - 1; + } + + for (i = 0; i < num_threads; i++) { + DWORD useless; + + tid[i] = CreateThread(NULL, 0, + win32_thread_specific_data, + (void *) &threadParams[i], 0, + &useless); + if (tid[i] == NULL) { + fprintf(stderr, "CreateThread failed\n"); + return(1); + } + } + + if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) == + WAIT_FAILED) { + fprintf(stderr, "WaitForMultipleObjects failed\n"); + return(1); + } + + for (i = 0; i < num_threads; i++) { + DWORD exitCode; + ret = GetExitCodeThread(tid[i], &exitCode); + if (ret == 0) { + fprintf(stderr, "GetExitCodeThread failed\n"); + return(1); + } + CloseHandle(tid[i]); + } + + xmlCatalogCleanup(); + for (i = 0; i < num_threads; i++) { + if (threadParams[i].okay == 0) { + fprintf(stderr, "Thread %d handling %s failed\n", + i, threadParams[i].filename); + res = 1; + } + } + } + + return (res); +} + +#elif defined HAVE_PTHREAD_H +#include + +static pthread_t tid[MAX_ARGC]; + +static int +testThread(void) +{ + unsigned int i, repeat; + int ret; + int res = 0; + + xmlInitParser(); + + for (repeat = 0; repeat < 500; repeat++) { + xmlLoadCatalog(catalog); + nb_tests++; + + for (i = 0; i < num_threads; i++) { + tid[i] = (pthread_t) - 1; + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&tid[i], 0, thread_specific_data, + (void *) &threadParams[i]); + if (ret != 0) { + fprintf(stderr, "pthread_create failed\n"); + return (1); + } + } + for (i = 0; i < num_threads; i++) { + void *result; + ret = pthread_join(tid[i], &result); + if (ret != 0) { + fprintf(stderr, "pthread_join failed\n"); + return (1); + } + } + + xmlCatalogCleanup(); + for (i = 0; i < num_threads; i++) + if (threadParams[i].okay == 0) { + fprintf(stderr, "Thread %d handling %s failed\n", + i, threadParams[i].filename); + res = 1; + } + } + return (res); +} + +#else +static int +testThread(void) +{ + fprintf(stderr, + "Specific platform thread support not detected\n"); + return (-1); +} +#endif +static int +threadsTest(const char *filename ATTRIBUTE_UNUSED, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(testThread()); +} +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +/************************************************************************ + * * + * Regexp tests * + * * + ************************************************************************/ + +static void testRegexp(FILE *output, xmlRegexpPtr comp, const char *value) { + int ret; + + ret = xmlRegexpExec(comp, (const xmlChar *) value); + if (ret == 1) + fprintf(output, "%s: Ok\n", value); + else if (ret == 0) + fprintf(output, "%s: Fail\n", value); + else + fprintf(output, "%s: Error: %d\n", value, ret); +} + +static int +regexpTest(const char *filename, const char *result, const char *err, + int options ATTRIBUTE_UNUSED) { + xmlRegexpPtr comp = NULL; + FILE *input, *output; + char *temp; + char expression[5000]; + int len, ret, res = 0; + + /* + * TODO: Custom error handler for regexp + */ + xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); + + nb_tests++; + + input = fopen(filename, "rb"); + if (input == NULL) { + fprintf(stderr, + "Cannot open %s for reading\n", filename); + ret = -1; + goto done; + } + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + output = fopen(temp, "wb"); + if (output == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + ret = -1; + goto done; + } + while (fgets(expression, 4500, input) != NULL) { + len = strlen(expression); + len--; + while ((len >= 0) && + ((expression[len] == '\n') || (expression[len] == '\t') || + (expression[len] == '\r') || (expression[len] == ' '))) len--; + expression[len + 1] = 0; + if (len >= 0) { + if (expression[0] == '#') + continue; + if ((expression[0] == '=') && (expression[1] == '>')) { + char *pattern = &expression[2]; + + if (comp != NULL) { + xmlRegFreeRegexp(comp); + comp = NULL; + } + fprintf(output, "Regexp: %s\n", pattern) ; + comp = xmlRegexpCompile((const xmlChar *) pattern); + if (comp == NULL) { + fprintf(output, " failed to compile\n"); + break; + } + } else if (comp == NULL) { + fprintf(output, "Regexp: %s\n", expression) ; + comp = xmlRegexpCompile((const xmlChar *) expression); + if (comp == NULL) { + fprintf(output, " failed to compile\n"); + break; + } + } else if (comp != NULL) { + testRegexp(output, comp, expression); + } + } + } + fclose(output); + fclose(input); + if (comp != NULL) + xmlRegFreeRegexp(comp); + + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + res = 1; + } + if (temp != NULL) { + unlink(temp); + free(temp); + } + + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + res = 1; + } + +done: + xmlSetStructuredErrorFunc(NULL, NULL); + + return(res); +} + +#endif /* LIBXML_REGEXPS_ENABLED */ + +#ifdef LIBXML_AUTOMATA_ENABLED +/************************************************************************ + * * + * Automata tests * + * * + ************************************************************************/ + +static int scanNumber(char **ptr) { + int ret = 0; + char *cur; + + cur = *ptr; + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + cur++; + } + *ptr = cur; + return(ret); +} + +static int +automataTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, int options ATTRIBUTE_UNUSED) { + FILE *input, *output; + char *temp; + char expr[5000]; + int len; + int ret; + int i; + int res = 0; + xmlAutomataPtr am; + xmlAutomataStatePtr states[1000]; + xmlRegexpPtr regexp = NULL; + xmlRegExecCtxtPtr exec = NULL; + + nb_tests++; + + for (i = 0;i<1000;i++) + states[i] = NULL; + + input = fopen(filename, "rb"); + if (input == NULL) { + fprintf(stderr, + "Cannot open %s for reading\n", filename); + return(-1); + } + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + output = fopen(temp, "wb"); + if (output == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + + am = xmlNewAutomata(); + if (am == NULL) { + fprintf(stderr, + "Cannot create automata\n"); + fclose(input); + return(-1); + } + states[0] = xmlAutomataGetInitState(am); + if (states[0] == NULL) { + fprintf(stderr, + "Cannot get start state\n"); + xmlFreeAutomata(am); + fclose(input); + return(-1); + } + ret = 0; + + while (fgets(expr, 4500, input) != NULL) { + if (expr[0] == '#') + continue; + len = strlen(expr); + len--; + while ((len >= 0) && + ((expr[len] == '\n') || (expr[len] == '\t') || + (expr[len] == '\r') || (expr[len] == ' '))) len--; + expr[len + 1] = 0; + if (len >= 0) { + if ((am != NULL) && (expr[0] == 't') && (expr[1] == ' ')) { + char *ptr = &expr[2]; + int from, to; + + from = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + if (states[from] == NULL) + states[from] = xmlAutomataNewState(am); + ptr++; + to = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + if (states[to] == NULL) + states[to] = xmlAutomataNewState(am); + ptr++; + xmlAutomataNewTransition(am, states[from], states[to], + BAD_CAST ptr, NULL); + } else if ((am != NULL) && (expr[0] == 'e') && (expr[1] == ' ')) { + char *ptr = &expr[2]; + int from, to; + + from = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + if (states[from] == NULL) + states[from] = xmlAutomataNewState(am); + ptr++; + to = scanNumber(&ptr); + if (states[to] == NULL) + states[to] = xmlAutomataNewState(am); + xmlAutomataNewEpsilon(am, states[from], states[to]); + } else if ((am != NULL) && (expr[0] == 'f') && (expr[1] == ' ')) { + char *ptr = &expr[2]; + int state; + + state = scanNumber(&ptr); + if (states[state] == NULL) { + fprintf(stderr, + "Bad state %d : %s\n", state, expr); + break; + } + xmlAutomataSetFinalState(am, states[state]); + } else if ((am != NULL) && (expr[0] == 'c') && (expr[1] == ' ')) { + char *ptr = &expr[2]; + int from, to; + int min, max; + + from = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + if (states[from] == NULL) + states[from] = xmlAutomataNewState(am); + ptr++; + to = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + if (states[to] == NULL) + states[to] = xmlAutomataNewState(am); + ptr++; + min = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + ptr++; + max = scanNumber(&ptr); + if (*ptr != ' ') { + fprintf(stderr, + "Bad line %s\n", expr); + break; + } + ptr++; + xmlAutomataNewCountTrans(am, states[from], states[to], + BAD_CAST ptr, min, max, NULL); + } else if ((am != NULL) && (expr[0] == '-') && (expr[1] == '-')) { + /* end of the automata */ + regexp = xmlAutomataCompile(am); + xmlFreeAutomata(am); + am = NULL; + if (regexp == NULL) { + fprintf(stderr, + "Failed to compile the automata"); + break; + } + } else if ((expr[0] == '=') && (expr[1] == '>')) { + if (regexp == NULL) { + fprintf(output, "=> failed not compiled\n"); + } else { + if (exec == NULL) + exec = xmlRegNewExecCtxt(regexp, NULL, NULL); + if (ret == 0) { + ret = xmlRegExecPushString(exec, NULL, NULL); + } + if (ret == 1) + fprintf(output, "=> Passed\n"); + else if ((ret == 0) || (ret == -1)) + fprintf(output, "=> Failed\n"); + else if (ret < 0) + fprintf(output, "=> Error\n"); + xmlRegFreeExecCtxt(exec); + exec = NULL; + } + ret = 0; + } else if (regexp != NULL) { + if (exec == NULL) + exec = xmlRegNewExecCtxt(regexp, NULL, NULL); + ret = xmlRegExecPushString(exec, BAD_CAST expr, NULL); + } else { + fprintf(stderr, + "Unexpected line %s\n", expr); + } + } + } + fclose(output); + fclose(input); + if (regexp != NULL) + xmlRegFreeRegexp(regexp); + if (exec != NULL) + xmlRegFreeExecCtxt(exec); + if (am != NULL) + xmlFreeAutomata(am); + + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed in %s\n", filename, result); + res = 1; + } + if (temp != NULL) { + unlink(temp); + free(temp); + } + + return(res); +} + +#endif /* LIBXML_AUTOMATA_ENABLED */ + +/************************************************************************ + * * + * Tests Descriptions * + * * + ************************************************************************/ + +static +testDesc testDescriptions[] = { + { "XML regression tests" , + oldParseTest, "./test/*", "result/", "", NULL, + 0 }, + { "XML regression tests on memory" , + memParseTest, "./test/*", "result/", "", NULL, + 0 }, + { "XML entity subst regression tests" , + noentParseTest, "./test/*", "result/noent/", "", NULL, + XML_PARSE_NOENT }, + { "XML Namespaces regression tests", + errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err", + 0 }, +#ifdef LIBXML_VALID_ENABLED + { "Error cases regression tests", + errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", + 0 }, + { "Error cases regression tests from file descriptor", + fdParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", + 0 }, + { "Error cases regression tests with entity substitution", + errParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".ent", + XML_PARSE_NOENT }, + { "Error cases regression tests (old 1.0)", + errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err", + XML_PARSE_OLD10 }, +#endif +#ifdef LIBXML_READER_ENABLED +#ifdef LIBXML_VALID_ENABLED + { "Error cases stream regression tests", + streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str", + 0 }, +#endif + { "Reader regression tests", + streamParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, + { "Reader entities substitution regression tests", + streamParseTest, "./test/*", "result/", ".rde", NULL, + XML_PARSE_NOENT }, + { "Reader on memory regression tests", + streamMemParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, + { "Walker regression tests", + walkerParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, +#endif +#ifdef LIBXML_SAX1_ENABLED + { "SAX1 callbacks regression tests" , + saxParseTest, "./test/*", "result/", ".sax", NULL, + XML_PARSE_SAX1 }, +#endif + { "SAX2 callbacks regression tests" , + saxParseTest, "./test/*", "result/", ".sax2", NULL, + 0 }, + { "SAX2 callbacks regression tests with entity substitution" , + saxParseTest, "./test/*", "result/noent/", ".sax2", NULL, + XML_PARSE_NOENT }, +#ifdef LIBXML_PUSH_ENABLED + { "XML push regression tests" , + pushParseTest, "./test/*", "result/", "", NULL, + 0 }, + { "XML push boundary tests" , + pushBoundaryTest, "./test/*", "result/", "", NULL, + 0 }, +#endif +#ifdef LIBXML_HTML_ENABLED + { "HTML regression tests" , + errParseTest, "./test/HTML/*", "result/HTML/", "", ".err", + XML_PARSE_HTML }, + { "HTML regression tests from file descriptor", + fdParseTest, "./test/HTML/*", "result/HTML/", "", ".err", + XML_PARSE_HTML }, +#ifdef LIBXML_PUSH_ENABLED + { "Push HTML regression tests" , + pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err", + XML_PARSE_HTML }, + { "Push HTML boundary tests" , + pushBoundaryTest, "./test/HTML/*", "result/HTML/", "", NULL, + XML_PARSE_HTML }, +#endif + { "HTML SAX regression tests" , + saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL, + XML_PARSE_HTML }, +#endif +#ifdef LIBXML_VALID_ENABLED + { "Valid documents regression tests" , + errParseTest, "./test/VCM/*", NULL, NULL, NULL, + XML_PARSE_DTDVALID }, + { "Validity checking regression tests" , + errParseTest, "./test/VC/*", "result/VC/", NULL, "", + XML_PARSE_DTDVALID }, +#ifdef LIBXML_READER_ENABLED + { "Streaming validity checking regression tests" , + streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr", + XML_PARSE_DTDVALID }, + { "Streaming validity error checking regression tests" , + streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr", + XML_PARSE_DTDVALID }, +#endif + { "General documents valid regression tests" , + errParseTest, "./test/valid/*", "result/valid/", "", ".err", + XML_PARSE_DTDVALID }, +#endif +#ifdef LIBXML_XINCLUDE_ENABLED + { "XInclude regression tests" , + errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", ".err", + XML_PARSE_XINCLUDE }, +#ifdef LIBXML_READER_ENABLED + { "XInclude xmlReader regression tests", + streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", + ".err", XML_PARSE_XINCLUDE }, +#endif + { "XInclude regression tests stripping include nodes" , + errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", ".err", + XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, +#ifdef LIBXML_READER_ENABLED + { "XInclude xmlReader regression tests stripping include nodes", + streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", + ".err", XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, +#endif + { "XInclude regression tests without reader", + errParseTest, "./test/XInclude/without-reader/*", "result/XInclude/", "", + ".err", XML_PARSE_XINCLUDE }, +#endif +#ifdef LIBXML_XPATH_ENABLED +#ifdef LIBXML_DEBUG_ENABLED + { "XPath expressions regression tests" , + xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL, + 0 }, + { "XPath document queries regression tests" , + xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, + 0 }, +#ifdef LIBXML_XPTR_ENABLED + { "XPointer document queries regression tests" , + xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, + -1 }, +#endif +#ifdef LIBXML_XPTR_LOCS_ENABLED + { "XPointer xpointer() queries regression tests" , + xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, + 0 }, +#endif +#ifdef LIBXML_VALID_ENABLED + { "xml:id regression tests" , + xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err", + 0 }, +#endif +#endif +#endif + { "URI parsing tests" , + uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL, + 0 }, + { "URI base composition tests" , + uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL, + 0 }, + { "Path URI conversion tests" , + uriPathTest, NULL, NULL, NULL, NULL, + 0 }, +#ifdef LIBXML_SCHEMAS_ENABLED + { "Schemas regression tests" , + schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL, + 0 }, + { "Relax-NG regression tests" , + rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT }, +#ifdef LIBXML_READER_ENABLED + { "Relax-NG streaming regression tests" , + rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT }, +#endif +#endif +#ifdef LIBXML_PATTERN_ENABLED +#ifdef LIBXML_READER_ENABLED + { "Pattern regression tests" , + patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL, + 0 }, +#endif +#endif +#ifdef LIBXML_C14N_ENABLED + { "C14N with comments regression tests" , + c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL, + 0 }, + { "C14N without comments regression tests" , + c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL, + 0 }, + { "C14N exclusive without comments regression tests" , + c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL, + 0 }, + { "C14N 1.1 without comments regression tests" , + c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL, + 0 }, +#endif +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) + { "Catalog and Threads regression tests" , + threadsTest, NULL, NULL, NULL, NULL, + 0 }, +#endif + { "SVG parsing regression tests" , + oldParseTest, "./test/SVG/*.xml", "result/SVG/", "", NULL, + 0 }, +#if defined(LIBXML_REGEXP_ENABLED) + { "Regexp regression tests" , + regexpTest, "./test/regexp/*", "result/regexp/", "", ".err", + 0 }, +#endif +#if defined(LIBXML_AUTOMATA_ENABLED) + { "Automata regression tests" , + automataTest, "./test/automata/*", "result/automata/", "", NULL, + 0 }, +#endif + {NULL, NULL, NULL, NULL, NULL, NULL, 0} +}; + +/************************************************************************ + * * + * The main code driving the tests * + * * + ************************************************************************/ + +static int +launchTests(testDescPtr tst) { + int res = 0, err = 0; + size_t i; + char *result; + char *error; + int mem; + xmlCharEncodingHandlerPtr ebcdicHandler, ibm1141Handler, eucJpHandler; + + ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC); + ibm1141Handler = xmlFindCharEncodingHandler("IBM-1141"); + + /* + * When decoding EUC-JP, musl doesn't seem to support 0x8F control + * codes. + */ + eucJpHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EUC_JP); + if (eucJpHandler != NULL) { + xmlBufferPtr in, out; + + in = xmlBufferCreateSize(10); + xmlBufferCCat(in, "\x8f\xe9\xae"); + out = xmlBufferCreateSize(10); + if (xmlCharEncInFunc(eucJpHandler, out, in) != 3) { + xmlCharEncCloseFunc(eucJpHandler); + eucJpHandler = NULL; + } + xmlBufferFree(out); + xmlBufferFree(in); + } + + if (tst == NULL) return(-1); + if (tst->in != NULL) { + glob_t globbuf; + + globbuf.gl_offs = 0; + glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + if (!checkTestFile(globbuf.gl_pathv[i])) + continue; + if ((((ebcdicHandler == NULL) || (ibm1141Handler == NULL)) && + (strstr(globbuf.gl_pathv[i], "ebcdic") != NULL)) || + ((eucJpHandler == NULL) && + (strstr(globbuf.gl_pathv[i], "icu_parse_test") != NULL))) + continue; + if (tst->suffix != NULL) { + result = resultFilename(globbuf.gl_pathv[i], tst->out, + tst->suffix); + if (result == NULL) { + fprintf(stderr, "Out of memory !\n"); + fatalError(); + } + } else { + result = NULL; + } + if (tst->err != NULL) { + error = resultFilename(globbuf.gl_pathv[i], tst->out, + tst->err); + if (error == NULL) { + fprintf(stderr, "Out of memory !\n"); + fatalError(); + } + } else { + error = NULL; + } + mem = xmlMemUsed(); + extraMemoryFromResolver = 0; + testErrorsSize = 0; + testErrors[0] = 0; + res = tst->func(globbuf.gl_pathv[i], result, error, + tst->options | XML_PARSE_COMPACT); + xmlResetLastError(); + if (res != 0) { + fprintf(stderr, "File %s generated an error\n", + globbuf.gl_pathv[i]); + nb_errors++; + err++; + } + else if (xmlMemUsed() != mem) { + if ((xmlMemUsed() != mem) && + (extraMemoryFromResolver == 0)) { + fprintf(stderr, "File %s leaked %d bytes\n", + globbuf.gl_pathv[i], xmlMemUsed() - mem); + nb_leaks++; + err++; + } + } + testErrorsSize = 0; + if (result) + free(result); + if (error) + free(error); + } + globfree(&globbuf); + } else { + testErrorsSize = 0; + testErrors[0] = 0; + extraMemoryFromResolver = 0; + res = tst->func(NULL, NULL, NULL, tst->options); + if (res != 0) { + nb_errors++; + err++; + } + } + + xmlCharEncCloseFunc(ebcdicHandler); + xmlCharEncCloseFunc(ibm1141Handler); + xmlCharEncCloseFunc(eucJpHandler); + + return(err); +} + +static int verbose = 0; +static int tests_quiet = 0; + +static int +runtest(int i) { + int ret = 0, res; + int old_errors, old_tests, old_leaks; + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL)) + printf("## %s\n", testDescriptions[i].desc); + res = launchTests(&testDescriptions[i]); + if (res != 0) + ret++; + if (verbose) { + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) + printf("Ran %d tests, no errors\n", nb_tests - old_tests); + else + printf("Ran %d tests, %d errors, %d leaks\n", + nb_tests - old_tests, + nb_errors - old_errors, + nb_leaks - old_leaks); + } + return(ret); +} + +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + int i, a, ret = 0; + int subset = 0; + +#if defined(_WIN32) + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900 + _set_output_format(_TWO_DIGIT_EXPONENT); +#endif + + initializeLibxml2(); + + for (a = 1; a < argc;a++) { + if (!strcmp(argv[a], "-v")) + verbose = 1; + else if (!strcmp(argv[a], "-u")) + update_results = 1; + else if (!strcmp(argv[a], "-quiet")) + tests_quiet = 1; + else if (!strcmp(argv[a], "--out")) + temp_directory = argv[++a]; + else { + for (i = 0; testDescriptions[i].func != NULL; i++) { + if (strstr(testDescriptions[i].desc, argv[a])) { + ret += runtest(i); + subset++; + } + } + } + } + if (subset == 0) { + for (i = 0; testDescriptions[i].func != NULL; i++) { + ret += runtest(i); + } + } + if ((nb_errors == 0) && (nb_leaks == 0)) { + ret = 0; + printf("Total %d tests, no errors\n", + nb_tests); + } else { + ret = 1; + printf("Total %d tests, %d errors, %d leaks\n", + nb_tests, nb_errors, nb_leaks); + } + xmlCleanupParser(); + + return(ret); +} + +#else /* ! LIBXML_OUTPUT_ENABLED */ +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + fprintf(stderr, "runtest requires output to be enabled in libxml2\n"); + return(0); +} +#endif diff --git a/runxmlconf.c b/runxmlconf.c new file mode 100644 index 00000000000..18893039da2 --- /dev/null +++ b/runxmlconf.c @@ -0,0 +1,609 @@ +/* + * runxmlconf.c: C program to run XML W3C conformance testsuites + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#include "config.h" +#include +#include + +#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_VALID_ENABLED) + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define LOGFILE "runxmlconf.log" +static FILE *logfile = NULL; +static int verbose = 0; + +#define NB_EXPECTED_ERRORS 15 + + +const char *skipped_tests[] = { +/* http://lists.w3.org/Archives/Public/public-xml-testsuite/2008Jul/0000.html */ + "rmt-ns10-035", + NULL +}; + +/************************************************************************ + * * + * File name and path utilities * + * * + ************************************************************************/ + +static int checkTestFile(const char *filename) { + struct stat buf; + + if (stat(filename, &buf) == -1) + return(0); + +#if defined(_WIN32) + if (!(buf.st_mode & _S_IFREG)) + return(0); +#else + if (!S_ISREG(buf.st_mode)) + return(0); +#endif + + return(1); +} + +static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) { + char buf[500]; + + if (dir == NULL) return(xmlStrdup(path)); + if (path == NULL) return(NULL); + + snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path); + return(xmlStrdup((const xmlChar *) buf)); +} + +/************************************************************************ + * * + * Libxml2 specific routines * + * * + ************************************************************************/ + +static int nb_skipped = 0; +static int nb_tests = 0; +static int nb_errors = 0; +static int nb_leaks = 0; + +/* + * We need to trap calls to the resolver to not account memory for the catalog + * and not rely on any external resources. + */ +static xmlParserInputPtr +testExternalEntityLoader(const char *URL, const char *ID ATTRIBUTE_UNUSED, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr ret; + + ret = xmlNewInputFromFile(ctxt, (const char *) URL); + + return(ret); +} + +/* + * Trapping the error messages at the generic level to grab the equivalent of + * stderr messages on CLI tools. + */ +static char testErrors[32769]; +static int testErrorsSize = 0; +static int nbError = 0; +static int nbFatal = 0; + +static void test_log(const char *msg, ...) { + va_list args; + if (logfile != NULL) { + fprintf(logfile, "\n------------\n"); + va_start(args, msg); + vfprintf(logfile, msg, args); + va_end(args); + fprintf(logfile, "%s", testErrors); + testErrorsSize = 0; testErrors[0] = 0; + } + if (verbose) { + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + } +} + +static void +testErrorHandler(void *userData ATTRIBUTE_UNUSED, const xmlError *error) { + int res; + + if (testErrorsSize >= 32768) + return; + res = snprintf(&testErrors[testErrorsSize], + 32768 - testErrorsSize, + "%s:%d: %s\n", (error->file ? error->file : "entity"), + error->line, error->message); + if (error->level == XML_ERR_FATAL) + nbFatal++; + else if (error->level == XML_ERR_ERROR) + nbError++; + if (testErrorsSize + res >= 32768) { + /* buffer is full */ + testErrorsSize = 32768; + testErrors[testErrorsSize] = 0; + } else { + testErrorsSize += res; + } + testErrors[testErrorsSize] = 0; +} + +static xmlXPathContextPtr ctxtXPath; + +static void +initializeLibxml2(void) { + xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); + xmlInitParser(); + xmlSetExternalEntityLoader(testExternalEntityLoader); + ctxtXPath = xmlXPathNewContext(NULL); + /* + * Deactivate the cache if created; otherwise we have to create/free it + * for every test, since it will confuse the memory leak detection. + * Note that normally this need not be done, since the cache is not + * created until set explicitly with xmlXPathContextSetCache(); + * but for test purposes it is sometimes useful to activate the + * cache by default for the whole library. + */ + if (ctxtXPath->cache != NULL) + xmlXPathContextSetCache(ctxtXPath, 0, -1, 0); +} + +/************************************************************************ + * * + * Run the xmlconf test if found * + * * + ************************************************************************/ + +static int +xmlconfTestInvalid(const char *id, const char *filename, int options) { + xmlDocPtr doc; + xmlParserCtxtPtr ctxt; + int ret = 1; + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + test_log("test %s : %s out of memory\n", + id, filename); + return(0); + } + xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL); + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + if (doc == NULL) { + test_log("test %s : %s invalid document turned not well-formed too\n", + id, filename); + } else { + /* invalidity should be reported both in the context and in the document */ + if ((ctxt->valid != 0) || (doc->properties & XML_DOC_DTDVALID)) { + test_log("test %s : %s failed to detect invalid document\n", + id, filename); + nb_errors++; + ret = 0; + } + xmlFreeDoc(doc); + } + xmlFreeParserCtxt(ctxt); + return(ret); +} + +static int +xmlconfTestValid(const char *id, const char *filename, int options) { + xmlDocPtr doc; + xmlParserCtxtPtr ctxt; + int ret = 1; + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + test_log("test %s : %s out of memory\n", + id, filename); + return(0); + } + xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL); + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + if (doc == NULL) { + test_log("test %s : %s failed to parse a valid document\n", + id, filename); + nb_errors++; + ret = 0; + } else { + /* validity should be reported both in the context and in the document */ + if ((ctxt->valid == 0) || ((doc->properties & XML_DOC_DTDVALID) == 0)) { + test_log("test %s : %s failed to validate a valid document\n", + id, filename); + nb_errors++; + ret = 0; + } + xmlFreeDoc(doc); + } + xmlFreeParserCtxt(ctxt); + return(ret); +} + +static int +xmlconfTestNotNSWF(const char *id, const char *filename, int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + int ret = 1; + + ctxt = xmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL); + /* + * In case of Namespace errors, libxml2 will still parse the document + * but log a Namespace error. + */ + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + if (doc == NULL) { + test_log("test %s : %s failed to parse the XML\n", + id, filename); + nb_errors++; + ret = 0; + } else { + const xmlError *error = xmlGetLastError(); + + if ((error->code == XML_ERR_OK) || + (error->domain != XML_FROM_NAMESPACE)) { + test_log("test %s : %s failed to detect namespace error\n", + id, filename); + nb_errors++; + ret = 0; + } + xmlFreeDoc(doc); + } + xmlFreeParserCtxt(ctxt); + return(ret); +} + +static int +xmlconfTestNotWF(const char *id, const char *filename, int options) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + int ret = 1; + + ctxt = xmlNewParserCtxt(); + xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL); + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + if (doc != NULL) { + test_log("test %s : %s failed to detect not well formedness\n", + id, filename); + nb_errors++; + xmlFreeDoc(doc); + ret = 0; + } + xmlFreeParserCtxt(ctxt); + return(ret); +} + +static int +xmlconfTestItem(xmlDocPtr doc, xmlNodePtr cur) { + int ret = -1; + xmlChar *type = NULL; + xmlChar *filename = NULL; + xmlChar *uri = NULL; + xmlChar *base = NULL; + xmlChar *id = NULL; + xmlChar *rec = NULL; + xmlChar *version = NULL; + xmlChar *entities = NULL; + xmlChar *edition = NULL; + int options = 0; + int nstest = 0; + int mem, final; + int i; + + testErrorsSize = 0; testErrors[0] = 0; + nbError = 0; + nbFatal = 0; + id = xmlGetProp(cur, BAD_CAST "ID"); + if (id == NULL) { + test_log("test missing ID, line %ld\n", xmlGetLineNo(cur)); + goto error; + } + for (i = 0;skipped_tests[i] != NULL;i++) { + if (!strcmp(skipped_tests[i], (char *) id)) { + test_log("Skipping test %s from skipped list\n", (char *) id); + ret = 0; + nb_skipped++; + goto error; + } + } + type = xmlGetProp(cur, BAD_CAST "TYPE"); + if (type == NULL) { + test_log("test %s missing TYPE\n", (char *) id); + goto error; + } + uri = xmlGetProp(cur, BAD_CAST "URI"); + if (uri == NULL) { + test_log("test %s missing URI\n", (char *) id); + goto error; + } + base = xmlNodeGetBase(doc, cur); + filename = composeDir(base, uri); + if (!checkTestFile((char *) filename)) { + test_log("test %s missing file %s \n", id, + (filename ? (char *)filename : "NULL")); + goto error; + } + + version = xmlGetProp(cur, BAD_CAST "VERSION"); + + entities = xmlGetProp(cur, BAD_CAST "ENTITIES"); + if (!xmlStrEqual(entities, BAD_CAST "none")) { + options |= XML_PARSE_DTDLOAD; + options |= XML_PARSE_NOENT; + } + rec = xmlGetProp(cur, BAD_CAST "RECOMMENDATION"); + if ((rec == NULL) || + (xmlStrEqual(rec, BAD_CAST "XML1.0")) || + (xmlStrEqual(rec, BAD_CAST "XML1.0-errata2e")) || + (xmlStrEqual(rec, BAD_CAST "XML1.0-errata3e")) || + (xmlStrEqual(rec, BAD_CAST "XML1.0-errata4e"))) { + if ((version != NULL) && (!xmlStrEqual(version, BAD_CAST "1.0"))) { + test_log("Skipping test %s for %s\n", (char *) id, + (char *) version); + ret = 0; + nb_skipped++; + goto error; + } + ret = 1; + } else if ((xmlStrEqual(rec, BAD_CAST "NS1.0")) || + (xmlStrEqual(rec, BAD_CAST "NS1.0-errata1e"))) { + ret = 1; + nstest = 1; + } else { + test_log("Skipping test %s for REC %s\n", (char *) id, (char *) rec); + ret = 0; + nb_skipped++; + goto error; + } + edition = xmlGetProp(cur, BAD_CAST "EDITION"); + if ((edition != NULL) && (xmlStrchr(edition, '5') == NULL)) { + /* test limited to all versions before 5th */ + options |= XML_PARSE_OLD10; + } + + /* + * Reset errors and check memory usage before the test + */ + xmlResetLastError(); + testErrorsSize = 0; testErrors[0] = 0; + mem = xmlMemUsed(); + + if (xmlStrEqual(type, BAD_CAST "not-wf")) { + if (nstest == 0) + xmlconfTestNotWF((char *) id, (char *) filename, options); + else + xmlconfTestNotNSWF((char *) id, (char *) filename, options); + } else if (xmlStrEqual(type, BAD_CAST "valid")) { + options |= XML_PARSE_DTDVALID; + xmlconfTestValid((char *) id, (char *) filename, options); + } else if (xmlStrEqual(type, BAD_CAST "invalid")) { + options |= XML_PARSE_DTDVALID; + xmlconfTestInvalid((char *) id, (char *) filename, options); + } else if (xmlStrEqual(type, BAD_CAST "error")) { + test_log("Skipping error test %s \n", (char *) id); + ret = 0; + nb_skipped++; + goto error; + } else { + test_log("test %s unknown TYPE value %s\n", (char *) id, (char *)type); + ret = -1; + goto error; + } + + /* + * Reset errors and check memory usage after the test + */ + xmlResetLastError(); + final = xmlMemUsed(); + if (final > mem) { + test_log("test %s : %s leaked %d bytes\n", + id, filename, final - mem); + nb_leaks++; + } + nb_tests++; + +error: + if (type != NULL) + xmlFree(type); + if (entities != NULL) + xmlFree(entities); + if (edition != NULL) + xmlFree(edition); + if (version != NULL) + xmlFree(version); + if (filename != NULL) + xmlFree(filename); + if (uri != NULL) + xmlFree(uri); + if (base != NULL) + xmlFree(base); + if (id != NULL) + xmlFree(id); + if (rec != NULL) + xmlFree(rec); + return(ret); +} + +static int +xmlconfTestCases(xmlDocPtr doc, xmlNodePtr cur, int level) { + xmlChar *profile; + int ret = 0; + int tests = 0; + int output = 0; + + if (level == 1) { + profile = xmlGetProp(cur, BAD_CAST "PROFILE"); + if (profile != NULL) { + output = 1; + level++; + printf("Test cases: %s\n", (char *) profile); + xmlFree(profile); + } + } + cur = cur->children; + while (cur != NULL) { + /* look only at elements we ignore everything else */ + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) { + ret += xmlconfTestCases(doc, cur, level); + } else if (xmlStrEqual(cur->name, BAD_CAST "TEST")) { + if (xmlconfTestItem(doc, cur) >= 0) + ret++; + tests++; + } else { + fprintf(stderr, "Unhandled element %s\n", (char *)cur->name); + } + } + cur = cur->next; + } + if (output == 1) { + if (tests > 0) + printf("Test cases: %d tests\n", tests); + } + return(ret); +} + +static int +xmlconfTestSuite(xmlDocPtr doc, xmlNodePtr cur) { + xmlChar *profile; + int ret = 0; + + profile = xmlGetProp(cur, BAD_CAST "PROFILE"); + if (profile != NULL) { + printf("Test suite: %s\n", (char *) profile); + xmlFree(profile); + } else + printf("Test suite\n"); + cur = cur->children; + while (cur != NULL) { + /* look only at elements we ignore everything else */ + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) { + ret += xmlconfTestCases(doc, cur, 1); + } else { + fprintf(stderr, "Unhandled element %s\n", (char *)cur->name); + } + } + cur = cur->next; + } + return(ret); +} + +static void +xmlconfInfo(void) { + fprintf(stderr, " you need to fetch and extract the\n"); + fprintf(stderr, " latest XML Conformance Test Suites\n"); + fprintf(stderr, " http://www.w3.org/XML/Test/xmlts20080827.tar.gz\n"); + fprintf(stderr, " see http://www.w3.org/XML/Test/ for information\n"); +} + +static int +xmlconfTest(void) { + const char *confxml = "xmlconf/xmlconf.xml"; + xmlDocPtr doc; + xmlNodePtr cur; + int ret = 0; + + if (!checkTestFile(confxml)) { + fprintf(stderr, "%s is missing \n", confxml); + xmlconfInfo(); + return(-1); + } + doc = xmlReadFile(confxml, NULL, XML_PARSE_NOENT); + if (doc == NULL) { + fprintf(stderr, "%s is corrupted \n", confxml); + xmlconfInfo(); + return(-1); + } + + cur = xmlDocGetRootElement(doc); + if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "TESTSUITE"))) { + fprintf(stderr, "Unexpected format %s\n", confxml); + xmlconfInfo(); + ret = -1; + } else { + ret = xmlconfTestSuite(doc, cur); + } + xmlFreeDoc(doc); + return(ret); +} + +/************************************************************************ + * * + * The driver for the tests * + * * + ************************************************************************/ + +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + int ret = 0; + int old_errors, old_tests, old_leaks; + + logfile = fopen(LOGFILE, "w"); + if (logfile == NULL) { + fprintf(stderr, + "Could not open the log file, running in verbose mode\n"); + verbose = 1; + } + initializeLibxml2(); + + if ((argc >= 2) && (!strcmp(argv[1], "-v"))) + verbose = 1; + + + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + xmlconfTest(); + if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) + printf("Ran %d tests, no errors\n", nb_tests - old_tests); + else + printf("Ran %d tests, %d errors, %d leaks\n", + nb_tests - old_tests, + nb_errors - old_errors, + nb_leaks - old_leaks); + if ((nb_errors == 0) && (nb_leaks == 0)) { + ret = 0; + printf("Total %d tests, no errors\n", + nb_tests); + } else { + ret = 1; + printf("Total %d tests, %d errors, %d leaks\n", + nb_tests, nb_errors, nb_leaks); + printf("See %s for detailed output\n", LOGFILE); + if ((nb_leaks == 0) && (nb_errors == NB_EXPECTED_ERRORS)) { + printf("%d errors were expected\n", nb_errors); + ret = 0; + } + } + xmlXPathFreeContext(ctxtXPath); + xmlCleanupParser(); + + if (logfile != NULL) + fclose(logfile); + return(ret); +} + +#else /* ! LIBXML_XPATH_ENABLED */ +int +main(int argc ATTRIBUTE_UNUSED, char **argv) { + fprintf(stderr, "%s need XPath and validation support\n", argv[0]); + return(0); +} +#endif diff --git a/save.h b/save.h deleted file mode 100644 index 192b6741335..00000000000 --- a/save.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Summary: Internal Interfaces for saving in libxml2 - * Description: this module describes a few interfaces which were - * added along with the API changes in 2.9.0 - * those are private routines at this point - * - * Copy: See Copyright for the status of this software. - * - * Author: Daniel Veillard - */ - -#ifndef __XML_SAVE_H__ -#define __XML_SAVE_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef LIBXML_OUTPUT_ENABLED -void xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string); -void xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table); -void xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem); -void xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr); -void xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent); -#endif - -xmlChar *xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input); - -#ifdef __cplusplus -} -#endif -#endif /* __XML_SAVE_H__ */ - diff --git a/schematron.c b/schematron.c index 68a4c622ebd..1de25deb971 100644 --- a/schematron.c +++ b/schematron.c @@ -25,6 +25,7 @@ #ifdef LIBXML_SCHEMATRON_ENABLED +#include #include #include #include @@ -34,6 +35,8 @@ #include #include +#include "private/error.h" + #define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT #define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron" @@ -60,16 +63,6 @@ static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS; 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 @@ -239,13 +232,11 @@ struct _xmlSchematronParserCtxt { * Handle an out of memory condition */ static void -xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt) { if (ctxt != NULL) ctxt->nberrors++; - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, - extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_SCHEMASP, NULL); } /** @@ -266,6 +257,7 @@ xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error, xmlGenericErrorFunc channel = NULL; xmlStructuredErrorFunc schannel = NULL; void *data = NULL; + int res; if (ctxt != NULL) { ctxt->nberrors++; @@ -273,10 +265,18 @@ xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int 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); + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __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); + if (res < 0) + xmlSchematronPErrMemory(ctxt); } /** @@ -287,15 +287,53 @@ xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error, * Handle an out of memory condition */ static void -xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt) { if (ctxt != NULL) { ctxt->nberrors++; ctxt->err = XML_SCHEMAV_INTERNAL; } - __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, - extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_SCHEMASV, NULL); +} + +/** + * xmlSchematronVErr: + * @ctxt: the parsing context + * @node: the context node + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a validation error + */ +static void LIBXML_ATTR_FORMAT(3,0) +xmlSchematronVErr(xmlSchematronValidCtxtPtr ctxt, int error, + const char *msg, const xmlChar * str1) +{ + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + int res; + + if (ctxt != NULL) { + ctxt->nberrors++; + channel = ctxt->error; + data = ctxt->userData; + schannel = ctxt->serror; + } + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, ctxt, NULL, + XML_FROM_SCHEMASV, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, NULL, NULL, 0, 0, + msg, str1); + if (res < 0) + xmlSchematronVErrMemory(ctxt); } /************************************************************************ @@ -344,7 +382,7 @@ xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest)); if (ret == NULL) { - xmlSchematronPErrMemory(ctxt, "allocating schema test", node); + xmlSchematronPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchematronTest)); @@ -448,7 +486,7 @@ xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule)); if (ret == NULL) { - xmlSchematronPErrMemory(ctxt, "allocating schema rule", node); + xmlSchematronPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchematronRule)); @@ -529,7 +567,7 @@ xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt, ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern)); if (ret == NULL) { - xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node); + xmlSchematronPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchematronPattern)); @@ -581,7 +619,7 @@ xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt) ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron)); if (ret == NULL) { - xmlSchematronPErrMemory(ctxt, "allocating schema", NULL); + xmlSchematronPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchematron)); @@ -636,8 +674,7 @@ xmlSchematronNewParserCtxt(const char *URL) (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser context", - NULL); + xmlSchematronPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); @@ -647,8 +684,7 @@ xmlSchematronNewParserCtxt(const char *URL) ret->includes = NULL; ret->xctxt = xmlXPathNewContext(NULL); if (ret->xctxt == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", - NULL); + xmlSchematronPErrMemory(NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } @@ -678,8 +714,7 @@ xmlSchematronNewMemParserCtxt(const char *buffer, int size) (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser context", - NULL); + xmlSchematronPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); @@ -688,8 +723,7 @@ xmlSchematronNewMemParserCtxt(const char *buffer, int size) ret->dict = xmlDictCreate(); ret->xctxt = xmlXPathNewContext(NULL); if (ret->xctxt == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", - NULL); + xmlSchematronPErrMemory(NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } @@ -717,8 +751,7 @@ xmlSchematronNewDocParserCtxt(xmlDocPtr doc) (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser context", - NULL); + xmlSchematronPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); @@ -728,8 +761,7 @@ xmlSchematronNewDocParserCtxt(xmlDocPtr doc) ret->preserve = 1; ret->xctxt = xmlXPathNewContext(doc); if (ret->xctxt == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", - NULL); + xmlSchematronPErrMemory(NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } @@ -777,8 +809,7 @@ xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt, ctxt->includes = (xmlNodePtr *) xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr)); if (ctxt->includes == NULL) { - xmlSchematronPErrMemory(NULL, "allocating parser includes", - NULL); + xmlSchematronPErrMemory(NULL); return; } ctxt->nbIncludes = 0; @@ -789,8 +820,7 @@ xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt, xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 * sizeof(xmlNodePtr)); if (tmp == NULL) { - xmlSchematronPErrMemory(NULL, "allocating parser includes", - NULL); + xmlSchematronPErrMemory(NULL); return; } ctxt->includes = tmp; @@ -847,8 +877,7 @@ xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, ctxt->namespaces = (const xmlChar **) xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *)); if (ctxt->namespaces == NULL) { - xmlSchematronPErrMemory(NULL, "allocating parser namespaces", - NULL); + xmlSchematronPErrMemory(NULL); return; } ctxt->nbNamespaces = 0; @@ -859,8 +888,7 @@ xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 * sizeof(const xmlChar *)); if (tmp == NULL) { - xmlSchematronPErrMemory(NULL, "allocating parser namespaces", - NULL); + xmlSchematronPErrMemory(NULL); return; } ctxt->namespaces = tmp; @@ -1490,9 +1518,6 @@ xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, ret = xmlStrcat(ret, spacer); ret = xmlStrcat(ret, eval->nodesetval->nodeTab[indx]->name); } - } else { - xmlGenericError(xmlGenericErrorContext, - "Empty node set\n"); } break; } @@ -1506,19 +1531,20 @@ xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, int size; size = snprintf(NULL, 0, "%0g", eval->floatval); - buf = (xmlChar*) malloc(size * sizeof(xmlChar)); - /* xmlStrPrintf(buf, size, "%0g", eval->floatval); // doesn't work */ - sprintf((char*) buf, "%0g", eval->floatval); - ret = xmlStrcat(ret, buf); - free(buf); + buf = (xmlChar *) xmlMalloc(size + 1); + if (buf != NULL) { + snprintf((char *) buf, size + 1, "%0g", eval->floatval); + ret = xmlStrcat(ret, buf); + xmlFree(buf); + } break; } case XPATH_STRING: ret = xmlStrcat(ret, eval->stringval); break; default: - xmlGenericError(xmlGenericErrorContext, - "Unsupported XPATH Type: %d\n", eval->type); + xmlSchematronVErr(ctxt, XML_ERR_INTERNAL_ERROR, + "Unsupported XPATH Type\n", NULL); } xmlXPathFreeObject(eval); xmlXPathFreeCompExpr(comp); @@ -1577,15 +1603,15 @@ xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, (test->type == XML_SCHEMATRON_REPORT)) return; if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { - TODO + /* 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))) + if (((test->type == XML_SCHEMATRON_REPORT) && (!success)) || + ((test->type == XML_SCHEMATRON_ASSERT) && (success))) return; line = xmlGetLineNo(cur); path = xmlGetNodePath(cur); @@ -1608,26 +1634,33 @@ xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, 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; + xmlStructuredErrorFunc schannel; + xmlGenericErrorFunc channel; + void *data; + int res; + + schannel = ctxt->serror; + channel = ctxt->error; + data = ctxt->userData; + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; } - __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); + res = __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); + if (res < 0) + xmlSchematronVErrMemory(ctxt); } else { xmlSchematronReportOutput(ctxt, cur, &msg[0]); } @@ -1654,7 +1687,7 @@ xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, 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 + /* TODO */ } else { char msg[1000]; @@ -1709,8 +1742,7 @@ xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options) ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt)); if (ret == NULL) { - xmlSchematronVErrMemory(NULL, "allocating validation context", - NULL); + xmlSchematronVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronValidCtxt)); @@ -1719,8 +1751,7 @@ xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options) ret->xctxt = xmlXPathNewContext(NULL); ret->flags = options; if (ret->xctxt == NULL) { - xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", - NULL); + xmlSchematronPErrMemory(NULL); xmlSchematronFreeValidCtxt(ret); return (NULL); } @@ -1866,7 +1897,9 @@ xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt, * Returns -1 in case of errors, otherwise 0 */ static int -xmlSchematronRegisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let, +xmlSchematronRegisterVariables(xmlSchematronValidCtxtPtr vctxt, + xmlXPathContextPtr ctxt, + xmlSchematronLetPtr let, xmlDocPtr instance, xmlNodePtr cur) { xmlXPathObjectPtr let_eval; @@ -1876,13 +1909,14 @@ xmlSchematronRegisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let, while (let != NULL) { let_eval = xmlXPathCompiledEval(let->comp, ctxt); if (let_eval == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Evaluation of compiled expression failed\n"); + xmlSchematronVErr(vctxt, XML_ERR_INTERNAL_ERROR, + "Evaluation of compiled expression failed\n", + NULL); return -1; } if(xmlXPathRegisterVariableNS(ctxt, let->name, NULL, let_eval)) { - xmlGenericError(xmlGenericErrorContext, - "Registering a let variable failed\n"); + xmlSchematronVErr(vctxt, XML_ERR_INTERNAL_ERROR, + "Registering a let variable failed\n", NULL); return -1; } let = let->next; @@ -1900,12 +1934,14 @@ xmlSchematronRegisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let, * Returns -1 in case of errors, otherwise 0 */ static int -xmlSchematronUnregisterVariables(xmlXPathContextPtr ctxt, xmlSchematronLetPtr let) +xmlSchematronUnregisterVariables(xmlSchematronValidCtxtPtr vctxt, + xmlXPathContextPtr ctxt, + xmlSchematronLetPtr let) { while (let != NULL) { if (xmlXPathRegisterVariableNS(ctxt, let->name, NULL, NULL)) { - xmlGenericError(xmlGenericErrorContext, - "Unregistering a let variable failed\n"); + xmlSchematronVErr(vctxt, XML_ERR_INTERNAL_ERROR, + "Unregistering a let variable failed\n", NULL); return -1; } let = let->next; @@ -1937,7 +1973,7 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) ctxt->nberrors = 0; root = xmlDocGetRootElement(instance); if (root == NULL) { - TODO + /* TODO */ ctxt->nberrors++; return(1); } @@ -1954,7 +1990,8 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) if (xmlPatternMatch(rule->pattern, cur) == 1) { test = rule->tests; - if (xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets, instance, cur)) + if (xmlSchematronRegisterVariables(ctxt, ctxt->xctxt, + rule->lets, instance, cur)) return -1; while (test != NULL) { @@ -1962,7 +1999,8 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) test = test->next; } - if (xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets)) + if (xmlSchematronUnregisterVariables(ctxt, ctxt->xctxt, + rule->lets)) return -1; } @@ -1992,15 +2030,16 @@ xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) while (rule != NULL) { if (xmlPatternMatch(rule->pattern, cur) == 1) { test = rule->tests; - xmlSchematronRegisterVariables(ctxt->xctxt, rule->lets, - instance, cur); + xmlSchematronRegisterVariables(ctxt, ctxt->xctxt, + rule->lets, instance, cur); while (test != NULL) { xmlSchematronRunTest(ctxt, test, instance, cur, pattern); test = test->next; } - xmlSchematronUnregisterVariables(ctxt->xctxt, rule->lets); + xmlSchematronUnregisterVariables(ctxt, ctxt->xctxt, + rule->lets); } rule = rule->patnext; } @@ -2051,7 +2090,6 @@ main(void) xmlFreeDoc(instance); xmlCleanupParser(); - xmlMemoryDump(); return (0); } diff --git a/threads.c b/threads.c index 06191f2052f..9ecfd81319b 100644 --- a/threads.c +++ b/threads.c @@ -14,43 +14,62 @@ #include #include -#include - -#ifdef HAVE_PTHREAD_H -#include -#elif defined HAVE_WIN32_THREADS -#define WIN32_LEAN_AND_MEAN -#include -#ifndef HAVE_COMPILER_TLS -#include +#include +#ifdef LIBXML_CATALOG_ENABLED +#include #endif -#endif - -#ifdef HAVE_BEOS_THREADS -#include -#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include #endif #if defined(SOLARIS) #include #endif -/* #define DEBUG_THREADS */ +#include "private/dict.h" +#include "private/enc.h" +#include "private/globals.h" +#include "private/io.h" +#include "private/memory.h" +#include "private/threads.h" +#include "private/xpath.h" -#ifdef HAVE_PTHREAD_H +#if defined(HAVE_POSIX_THREADS) && \ + defined(__GLIBC__) && \ + __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234 -#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \ - defined(__GLIBC__) && defined(__linux__) +/* + * The modern way available since glibc 2.32. + * + * The check above is for glibc 2.34 which merged the pthread symbols into + * libc. Since we still allow linking without pthread symbols (see below), + * this only works if pthread symbols are guaranteed to be available. + */ -static int libxml_is_threaded = -1; +#include -#define XML_PTHREAD_WEAK +#define XML_IS_THREADED() (!__libc_single_threaded) +#define XML_IS_NEVER_THREADED() 0 + +#elif defined(HAVE_POSIX_THREADS) && \ + defined(__GLIBC__) && \ + defined(__GNUC__) + +/* + * The traditional way to check for single-threaded applications with + * glibc was to check whether the separate libpthread library is + * linked in. This works by not linking libxml2 with libpthread (see + * BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring + * pthread functions as weak symbols. + * + * In glibc 2.34, the pthread symbols were moved from libpthread to libc, + * so this doesn't work anymore. + * + * At some point, this legacy code and the BASE_THREAD_LIBS hack in + * configure.ac can probably be removed. + */ -#pragma weak pthread_once -#pragma weak pthread_getspecific -#pragma weak pthread_setspecific -#pragma weak pthread_key_create -#pragma weak pthread_key_delete #pragma weak pthread_mutex_init #pragma weak pthread_mutex_destroy #pragma weak pthread_mutex_lock @@ -60,17 +79,20 @@ static int libxml_is_threaded = -1; #pragma weak pthread_cond_wait #pragma weak pthread_equal #pragma weak pthread_self -#pragma weak pthread_key_create -#pragma weak pthread_key_delete #pragma weak pthread_cond_signal -#else /* __GNUC__, __GLIBC__, __linux__ */ +#define XML_PTHREAD_WEAK +#define XML_IS_THREADED() libxml_is_threaded +#define XML_IS_NEVER_THREADED() (!libxml_is_threaded) + +static int libxml_is_threaded = -1; -static int libxml_is_threaded = 1; +#else /* other POSIX platforms */ -#endif /* __GNUC__, __GLIBC__, __linux__ */ +#define XML_IS_THREADED() 1 +#define XML_IS_NEVER_THREADED() 0 -#endif /* HAVE_PTHREAD_H */ +#endif /* * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree @@ -78,27 +100,11 @@ static int libxml_is_threaded = 1; * 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 - CRITICAL_SECTION cs; -#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 +#ifdef HAVE_POSIX_THREADS pthread_mutex_t lock; unsigned int held; unsigned int waiters; @@ -106,55 +112,31 @@ struct _xmlRMutex { pthread_cond_t cv; #elif defined HAVE_WIN32_THREADS CRITICAL_SECTION cs; -#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_once_t once_control_init = 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; - LONG 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); +/** + * xmlInitMutex: + * @mutex: the mutex + * + * Initialize a mutex. + */ +void +xmlInitMutex(xmlMutexPtr mutex) +{ +#ifdef HAVE_POSIX_THREADS + if (XML_IS_NEVER_THREADED() == 0) + pthread_mutex_init(&mutex->lock, NULL); +#elif defined HAVE_WIN32_THREADS + InitializeCriticalSection(&mutex->cs); +#else + (void) mutex; #endif +} /** * xmlNewMutex: @@ -171,27 +153,34 @@ xmlNewMutex(void) if ((tok = malloc(sizeof(xmlMutex))) == NULL) return (NULL); -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) - pthread_mutex_init(&tok->lock, NULL); + xmlInitMutex(tok); + return (tok); +} + +/** + * xmlCleanupMutex: + * @mutex: the simple mutex + * + * Reclaim resources associated with a mutex. + */ +void +xmlCleanupMutex(xmlMutexPtr mutex) +{ +#ifdef HAVE_POSIX_THREADS + if (XML_IS_NEVER_THREADED() == 0) + pthread_mutex_destroy(&mutex->lock); #elif defined HAVE_WIN32_THREADS - InitializeCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) { - free(tok); - return NULL; - } - tok->tid = -1; + DeleteCriticalSection(&mutex->cs); +#else + (void) mutex; #endif - return (tok); } /** * xmlFreeMutex: * @tok: the simple mutex * - * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token - * struct. + * Free a mutex. */ void xmlFreeMutex(xmlMutexPtr tok) @@ -199,14 +188,7 @@ 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 - DeleteCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - delete_sem(tok->sem); -#endif + xmlCleanupMutex(tok); free(tok); } @@ -221,19 +203,15 @@ xmlMutexLock(xmlMutexPtr tok) { if (tok == NULL) return; -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) +#ifdef HAVE_POSIX_THREADS + /* + * This assumes that __libc_single_threaded won't change while the + * lock is held. + */ + if (XML_IS_THREADED() != 0) pthread_mutex_lock(&tok->lock); #elif defined HAVE_WIN32_THREADS EnterCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - if (acquire_sem(tok->sem) != B_NO_ERROR) { -#ifdef DEBUG_THREADS - xmlGenericError(xmlGenericErrorContext, - "xmlMutexLock():BeOS:Couldn't acquire semaphore\n"); -#endif - } - tok->tid = find_thread(NULL); #endif } @@ -249,16 +227,11 @@ xmlMutexUnlock(xmlMutexPtr tok) { if (tok == NULL) return; -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) +#ifdef HAVE_POSIX_THREADS + if (XML_IS_THREADED() != 0) pthread_mutex_unlock(&tok->lock); #elif defined HAVE_WIN32_THREADS LeaveCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - if (tok->tid == find_thread(NULL)) { - tok->tid = -1; - release_sem(tok->sem); - } #endif } @@ -279,8 +252,8 @@ xmlNewRMutex(void) if ((tok = malloc(sizeof(xmlRMutex))) == NULL) return (NULL); -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) { +#ifdef HAVE_POSIX_THREADS + if (XML_IS_NEVER_THREADED() == 0) { pthread_mutex_init(&tok->lock, NULL); tok->held = 0; tok->waiters = 0; @@ -288,12 +261,6 @@ xmlNewRMutex(void) } #elif defined HAVE_WIN32_THREADS InitializeCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - if ((tok->lock = xmlNewMutex()) == NULL) { - free(tok); - return NULL; - } - tok->count = 0; #endif return (tok); } @@ -310,15 +277,13 @@ xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED) { if (tok == NULL) return; -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) { +#ifdef HAVE_POSIX_THREADS + if (XML_IS_NEVER_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); } @@ -334,8 +299,8 @@ xmlRMutexLock(xmlRMutexPtr tok) { if (tok == NULL) return; -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded == 0) +#ifdef HAVE_POSIX_THREADS + if (XML_IS_THREADED() == 0) return; pthread_mutex_lock(&tok->lock); @@ -356,14 +321,6 @@ xmlRMutexLock(xmlRMutexPtr tok) pthread_mutex_unlock(&tok->lock); #elif defined HAVE_WIN32_THREADS EnterCriticalSection(&tok->cs); -#elif defined HAVE_BEOS_THREADS - if (tok->lock->tid == find_thread(NULL)) { - tok->count++; - return; - } else { - xmlMutexLock(tok->lock); - tok->count = 1; - } #endif } @@ -378,8 +335,8 @@ xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) { if (tok == NULL) return; -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded == 0) +#ifdef HAVE_POSIX_THREADS + if (XML_IS_THREADED() == 0) return; pthread_mutex_lock(&tok->lock); @@ -392,342 +349,6 @@ xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) pthread_mutex_unlock(&tok->lock); #elif defined HAVE_WIN32_THREADS 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. */ -#ifdef XML_PTHREAD_WEAK - if (&pthread_mutex_lock == NULL) - return; -#endif /* XML_PTHREAD_WEAK */ - 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((void **) &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"); -#endif - } -#endif -} - -void -__xmlGlobalInitMutexUnlock(void) -{ -#ifdef HAVE_PTHREAD_H -#ifdef XML_PTHREAD_WEAK - if (&pthread_mutex_unlock == NULL) - return; -#endif /* XML_PTHREAD_WEAK */ - 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 } @@ -740,6 +361,8 @@ xmlGetGlobalState(void) /** * xmlGetThreadId: * + * DEPRECATED: Internal function, do not use. + * * 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 @@ -749,11 +372,11 @@ xmlGetGlobalState(void) int xmlGetThreadId(void) { -#ifdef HAVE_PTHREAD_H +#ifdef HAVE_POSIX_THREADS pthread_t id; int ret; - if (libxml_is_threaded == 0) + if (XML_IS_THREADED() == 0) return (0); id = pthread_self(); /* horrible but preserves compat, see warning above */ @@ -761,49 +384,11 @@ xmlGetThreadId(void) 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: * @@ -813,9 +398,6 @@ xmlIsMainThread(void) void xmlLockLibrary(void) { -#ifdef DEBUG_THREADS - xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); -#endif xmlRMutexLock(xmlLibraryLock); } @@ -828,32 +410,67 @@ xmlLockLibrary(void) void xmlUnlockLibrary(void) { -#ifdef DEBUG_THREADS - xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); -#endif xmlRMutexUnlock(xmlLibraryLock); } /** * xmlInitThreads: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * xmlInitThreads() is used to to initialize all the thread related - * data of the libxml2 library. + * DEPRECATED: Alias for xmlInitParser. */ void xmlInitThreads(void) { -#ifdef HAVE_PTHREAD_H + xmlInitParser(); +} + +/** + * xmlCleanupThreads: + * + * DEPRECATED: This function is a no-op. Call xmlCleanupParser + * to free global state but see the warnings there. xmlCleanupParser + * should be only called once at program exit. In most cases, you don't + * have call cleanup functions at all. + */ +void +xmlCleanupThreads(void) +{ +} + +/************************************************************************ + * * + * Library wide initialization * + * * + ************************************************************************/ + +static int xmlParserInitialized = 0; +static int xmlParserInnerInitialized = 0; + + +#ifdef HAVE_POSIX_THREADS +static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; +#elif defined HAVE_WIN32_THREADS +static volatile LPCRITICAL_SECTION global_init_lock = NULL; +#endif + +/** + * xmlGlobalInitMutexLock + * + * Makes sure that the global initialization mutex is initialized and + * locks it. + */ +static void +xmlGlobalInitMutexLock(void) { +#ifdef HAVE_POSIX_THREADS + #ifdef XML_PTHREAD_WEAK - if (libxml_is_threaded == -1) { - if ((&pthread_once != NULL) && - (&pthread_getspecific != NULL) && - (&pthread_setspecific != NULL) && - (&pthread_key_create != NULL) && - (&pthread_key_delete != NULL) && + /* + * This is somewhat unreliable since libpthread could be loaded + * later with dlopen() and threads could be created. But it's + * long-standing behavior and hard to work around. + */ + if (libxml_is_threaded == -1) + libxml_is_threaded = (&pthread_mutex_init != NULL) && (&pthread_mutex_destroy != NULL) && (&pthread_mutex_lock != NULL) && @@ -861,189 +478,196 @@ xmlInitThreads(void) (&pthread_cond_init != NULL) && (&pthread_cond_destroy != NULL) && (&pthread_cond_wait != NULL) && - (&pthread_equal != NULL) && + /* + * pthread_equal can be inline, resuting in -Waddress warnings. + * Let's assume it's available if all the other functions are. + */ + /* (pthread_equal != NULL) && */ (&pthread_self != NULL) && - (&pthread_cond_signal != NULL)) { - libxml_is_threaded = 1; + (&pthread_cond_signal != NULL); +#endif -/* fprintf(stderr, "Running multithreaded\n"); */ - } else { + /* The mutex is statically initialized, so we just lock it. */ + if (XML_IS_THREADED() != 0) + 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) { + fprintf(stderr, "libxml2: xmlInitParser: out of memory\n"); + abort(); + } + InitializeCriticalSection(cs); -/* fprintf(stderr, "Running without multithread\n"); */ - libxml_is_threaded = 0; + /* Swap it into the global_init_lock */ +#ifdef InterlockedCompareExchangePointer + InterlockedCompareExchangePointer((void **) &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); } } -#endif /* XML_PTHREAD_WEAK */ + + /* Lock the chosen critical section */ + EnterCriticalSection(global_init_lock); + +#endif +} + +static void +xmlGlobalInitMutexUnlock(void) { +#ifdef HAVE_POSIX_THREADS + if (XML_IS_THREADED() != 0) + pthread_mutex_unlock(&global_init_lock); +#elif defined HAVE_WIN32_THREADS + if (global_init_lock != NULL) + LeaveCriticalSection(global_init_lock); #endif } /** - * xmlCleanupThreads: - * - * DEPRECATED: This function will be made private. Call xmlCleanupParser - * to free global state but see the warnings there. xmlCleanupParser - * should be only called once at program exit. In most cases, you don't - * have call cleanup functions at all. - * - * xmlCleanupThreads() is used to to cleanup all the thread related - * data of the libxml2 library once processing has ended. + * xmlGlobalInitMutexDestroy * - * 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 ! + * Makes sure that the global initialization mutex is destroyed before + * application termination. */ -void -xmlCleanupThreads(void) -{ -#ifdef DEBUG_THREADS - xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); -#endif -#ifdef HAVE_PTHREAD_H - if (libxml_is_threaded != 0) - pthread_key_delete(globalkey); - once_control = once_control_init; -#elif defined(HAVE_WIN32_THREADS) -#if !defined(HAVE_COMPILER_TLS) - if (globalkey != TLS_OUT_OF_INDEXES) { -#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL) - 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); -#endif - TlsFree(globalkey); - globalkey = TLS_OUT_OF_INDEXES; +static void +xmlGlobalInitMutexDestroy(void) { +#ifdef HAVE_POSIX_THREADS +#elif defined HAVE_WIN32_THREADS + if (global_init_lock != NULL) { + DeleteCriticalSection(global_init_lock); + free(global_init_lock); + global_init_lock = NULL; } -#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL) - DeleteCriticalSection(&cleanup_helpers_cs); -#endif -#endif - run_once.done = 0; - run_once.control = 0; #endif } -#ifdef LIBXML_THREAD_ENABLED - /** - * xmlOnceInit + * xmlInitParser: * - * 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. + * Initialization function for the XML parser. + * + * Call once from the main thread before using the library in + * multithreaded programs. */ -static void -xmlOnceInit(void) -{ -#ifdef HAVE_PTHREAD_H - (void) pthread_key_create(&globalkey, xmlFreeGlobalState); - mainthread = pthread_self(); - __xmlInitializeDict(); -#elif defined(HAVE_WIN32_THREADS) - if (!run_once.done) { - if (InterlockedIncrement(&run_once.control) == 1) { -#if !defined(HAVE_COMPILER_TLS) -#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL) - InitializeCriticalSection(&cleanup_helpers_cs); +void +xmlInitParser(void) { + /* + * Note that the initialization code must not make memory allocations. + */ + if (xmlParserInitialized != 0) + return; + + xmlGlobalInitMutexLock(); + + if (xmlParserInnerInitialized == 0) { +#if defined(_WIN32) && \ + !defined(LIBXML_THREAD_ALLOC_ENABLED) && \ + (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) + if (xmlFree == free) + atexit(xmlCleanupParser); #endif - globalkey = TlsAlloc(); + + xmlInitRandom(); /* Required by xmlInitGlobalsInternal */ + xmlInitMemoryInternal(); + xmlInitGlobalsInternal(); + xmlInitDictInternal(); + xmlInitEncodingInternal(); +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) + xmlInitXPathInternal(); #endif - mainthread = GetCurrentThreadId(); - __xmlInitializeDict(); - 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); - } + xmlInitIOCallbacks(); + + xmlParserInnerInitialized = 1; } -#elif defined HAVE_BEOS_THREADS - if (atomic_add(&run_once_init, 1) == 0) { - globalkey = tls_allocate(); - tls_set(globalkey, NULL); - mainthread = find_thread(NULL); - __xmlInitializeDict(); - } else - atomic_add(&run_once_init, -1); -#endif + + xmlGlobalInitMutexUnlock(); + + xmlParserInitialized = 1; } -#endif /** - * DllMain: - * @hinstDLL: handle to DLL instance - * @fdwReason: Reason code for entry - * @lpvReserved: generic pointer (depends upon reason code) + * xmlCleanupParser: + * + * This function name is somewhat misleading. It does not clean up + * parser state, it cleans up memory allocated by the library itself. + * It is a cleanup function for the XML library. It tries to reclaim all + * related global memory allocated for the library processing. + * It doesn't deallocate any document related memory. One should + * call xmlCleanupParser() only when the process has finished using + * the library and all XML/HTML documents built with it. + * See also xmlInitParser() which has the opposite function of preparing + * the library for operations. * - * Entry point for Windows library. It is being used to free thread-specific - * storage. - * - * Returns TRUE always + * 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 ! */ -#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) -int XMLCALL -xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason, - ATTRIBUTE_UNUSED void *lpvReserved) -#else -/* declare to avoid "no previous prototype for 'DllMain'" warning */ -/* Note that we do NOT want to include this function declaration in - a public header because it's meant to be called by Windows itself, - not a program that uses this library. This also has to be exported. */ - -XMLPUBFUN BOOL WINAPI -DllMain (HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved); - -BOOL WINAPI -DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason, - ATTRIBUTE_UNUSED LPVOID lpvReserved) +void +xmlCleanupParser(void) { + if (!xmlParserInitialized) + return; + + /* These functions can call xmlFree. */ + + xmlCleanupCharEncodingHandlers(); +#ifdef LIBXML_CATALOG_ENABLED + xmlCatalogCleanup(); #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; +#ifdef LIBXML_SCHEMAS_ENABLED + xmlSchemaCleanupTypes(); + xmlRelaxNGCleanupTypes(); +#endif + + /* These functions should never call xmlFree. */ + + xmlCleanupDictInternal(); + xmlCleanupRandom(); + xmlCleanupGlobalsInternal(); + /* + * Must come last. On Windows, xmlCleanupGlobalsInternal can call + * xmlFree which uses xmlMemMutex in debug mode. + */ + xmlCleanupMemoryInternal(); + + xmlGlobalInitMutexDestroy(); + + xmlParserInitialized = 0; + xmlParserInnerInitialized = 0; +} + +#if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && \ + !defined(LIBXML_THREAD_ALLOC_ENABLED) && \ + !defined(LIBXML_STATIC) && \ + !defined(_WIN32) +static void +ATTRIBUTE_DESTRUCTOR +xmlDestructor(void) { + /* + * Calling custom deallocation functions in a destructor can cause + * problems, for example with Nokogiri. + */ + if (xmlFree == free) + xmlCleanupParser(); } #endif + diff --git a/tree.c b/tree.c index df27aa11aba..53eae8e3b46 100644 --- a/tree.c +++ b/tree.c @@ -28,15 +28,13 @@ #include #endif -#include #include +#include #include #include #include -#include #include #include -#include #ifdef LIBXML_HTML_ENABLED #include #endif @@ -44,8 +42,10 @@ #include #endif -#include "buf.h" -#include "save.h" +#include "private/buf.h" +#include "private/entities.h" +#include "private/error.h" +#include "private/tree.h" int __xmlRegisterCallbacks = 0; @@ -55,58 +55,23 @@ int __xmlRegisterCallbacks = 0; * * ************************************************************************/ +static xmlNodePtr +xmlNewEntityRef(xmlDocPtr doc, xmlChar *name); + static xmlNsPtr -xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); +xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns); + +static xmlAttrPtr +xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, + const xmlChar *nsName, int useDTD); static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop); -/************************************************************************ - * * - * Tree memory error handler * - * * - ************************************************************************/ -/** - * xmlTreeErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ static void -xmlTreeErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} +xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree); -/** - * xmlTreeErr: - * @code: the error number - * @extra: extra information - * - * Handle an out of memory condition - */ static void -xmlTreeErr(int code, xmlNodePtr node, const char *extra) -{ - const char *msg = NULL; - - switch(code) { - case XML_TREE_INVALID_HEX: - msg = "invalid hexadecimal character value\n"; - break; - case XML_TREE_INVALID_DEC: - msg = "invalid decimal character value\n"; - break; - case XML_TREE_UNTERMINATED_ENTITY: - msg = "unterminated entity reference %15s\n"; - break; - case XML_TREE_NOT_UTF8: - msg = "string is not in UTF-8\n"; - break; - default: - msg = "unexpected error number\n"; - } - __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra); -} +xmlUnlinkNodeInternal(xmlNodePtr cur); /************************************************************************ * * @@ -122,27 +87,10 @@ const xmlChar xmlStringTextNoenc[] = const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 }; static int xmlCompressMode = 0; -static int xmlCheckDTD = 1; - -#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ - xmlNodePtr ulccur = (n)->children; \ - if (ulccur == NULL) { \ - (n)->last = NULL; \ - } else { \ - while (ulccur->next != NULL) { \ - ulccur->parent = (n); \ - ulccur = ulccur->next; \ - } \ - ulccur->parent = (n); \ - (n)->last = ulccur; \ -}} #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \ (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0)) -/* #define DEBUG_BUFFER */ -/* #define DEBUG_TREE */ - /************************************************************************ * * * Functions to move to entities.c once the * @@ -225,15 +173,19 @@ xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, if (ncname == NULL) return(NULL); if (prefix == NULL) return((xmlChar *) ncname); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Make allocation more likely */ + if (len > 8) + len = 8; +#endif + lenn = strlen((char *) ncname); lenp = strlen((char *) prefix); if ((memory == NULL) || (len < lenn + lenp + 2)) { ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); - if (ret == NULL) { - xmlTreeErrMemory("building QName"); + if (ret == NULL) return(NULL); - } } else { ret = memory; } @@ -249,6 +201,8 @@ xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, * @name: the full QName * @prefix: a xmlChar ** * + * DEPRECATED: This function doesn't report malloc failures. + * * parse an XML qualified name string * * [NS 5] QName ::= (Prefix ':')? LocalPart @@ -270,13 +224,6 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { *prefix = NULL; if (name == NULL) return(NULL); -#ifndef XML_XML_NAMESPACE - /* xml: prefix is not really a namespace */ - if ((name[0] == 'x') && (name[1] == 'm') && - (name[2] == 'l') && (name[3] == ':')) - return(NULL); -#endif - /* nasty but valid */ if (name[0] == ':') return(NULL); @@ -288,17 +235,14 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { while ((name[len] != 0) && (name[len] != ':')) len++; - if (name[len] == 0) + if ((name[len] == 0) || (name[len+1] == 0)) return(NULL); *prefix = xmlStrndup(name, len); - if (*prefix == NULL) { - xmlTreeErrMemory("QName split"); + if (*prefix == NULL) return(NULL); - } ret = xmlStrdup(&name[len + 1]); if (ret == NULL) { - xmlTreeErrMemory("QName split"); if (*prefix != NULL) { xmlFree(*prefix); *prefix = NULL; @@ -339,7 +283,7 @@ xmlSplitQName3(const xmlChar *name, int *len) { while ((name[l] != 0) && (name[l] != ':')) l++; - if (name[l] == 0) + if ((name[l] == 0) || (name[l+1] == 0)) return(NULL); *len = l; @@ -347,6 +291,53 @@ xmlSplitQName3(const xmlChar *name, int *len) { return(&name[l+1]); } +/** + * xmlSplitQName4: + * @name: the full QName + * @prefixPtr: pointer to resulting prefix + * + * Parse a QName. The return value points to the start of the local + * name in the input string. If the QName has a prefix, it will be + * allocated and stored in @prefixPtr. This string must be freed by + * the caller. If there's no prefix, @prefixPtr is set to NULL. + * + * Returns the local name or NULL if a memory allocation failed. + */ +const xmlChar * +xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) { + xmlChar *prefix; + int l = 0; + + if ((name == NULL) || (prefixPtr == NULL)) + return(NULL); + + *prefixPtr = NULL; + + /* nasty but valid */ + if (name[0] == ':') + return(name); + + /* + * we are not trying to validate but just to cut, and yes it will + * work even if this is as set of UTF-8 encoded chars + */ + while ((name[l] != 0) && (name[l] != ':')) + l++; + + /* + * TODO: What about names with multiple colons? + */ + if ((name[l] == 0) || (name[l+1] == 0)) + return(name); + + prefix = xmlStrndup(name, l); + if (prefix == NULL) + return(NULL); + + *prefixPtr = prefix; + return(&name[l+1]); +} + /************************************************************************ * * * Check Name, NCName and QName strings * @@ -355,7 +346,6 @@ xmlSplitQName3(const xmlChar *name, int *len) { #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_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED) /** * xmlValidateNCName: * @value: the value to check @@ -427,7 +417,6 @@ try_complex: return(0); } -#endif #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** @@ -713,19 +702,21 @@ xmlGetBufferAllocationScheme(void) { /** * xmlNewNs: - * @node: the element carrying the namespace + * @node: the element carrying the namespace (optional) * @href: the URI associated - * @prefix: the prefix for the namespace + * @prefix: the prefix for the namespace (optional) * - * Creation of a new Namespace. This function will refuse to create - * a namespace with a similar prefix than an existing one present on this - * node. - * Note that for a default namespace, @prefix should be NULL. + * Create a new namespace. For a default namespace, @prefix should be + * NULL. The namespace URI in @href is not checked. You should make sure + * to pass a valid URI. * - * We use href==NULL in the case of an element creation where the namespace - * was not defined. + * If @node is provided, it must be an element node. The namespace will + * be appended to the node's namespace declarations. It is an error if + * the node already has a definition for the prefix or default + * namespace. * - * Returns a new namespace pointer or NULL + * Returns a new namespace pointer or NULL if arguments are invalid, + * the prefix is already in use or a memory allocation failed. */ xmlNsPtr xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { @@ -734,35 +725,25 @@ xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) return(NULL); - if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { - /* xml namespace is predefined, no need to add it */ - if (xmlStrEqual(href, XML_XML_NAMESPACE)) - return(NULL); - - /* - * Problem, this is an attempt to bind xml prefix to a wrong - * namespace, which breaks - * Namespace constraint: Reserved Prefixes and Namespace Names - * from XML namespace. But documents authors may not care in - * their context so let's proceed. - */ - } - /* * Allocate a new Namespace and fill the fields. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("building namespace"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_LOCAL_NAMESPACE; - if (href != NULL) + if (href != NULL) { cur->href = xmlStrdup(href); - if (prefix != NULL) + if (cur->href == NULL) + goto error; + } + if (prefix != NULL) { cur->prefix = xmlStrdup(prefix); + if (cur->prefix == NULL) + goto error; + } /* * Add it at the end to preserve parsing order ... @@ -774,39 +755,36 @@ xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { } else { xmlNsPtr prev = node->nsDef; - if (((prev->prefix == NULL) && (cur->prefix == NULL)) || - (xmlStrEqual(prev->prefix, cur->prefix))) { - xmlFreeNs(cur); - return(NULL); - } + if ((xmlStrEqual(prev->prefix, cur->prefix)) && + (prev->href != NULL)) + goto error; while (prev->next != NULL) { prev = prev->next; - if (((prev->prefix == NULL) && (cur->prefix == NULL)) || - (xmlStrEqual(prev->prefix, cur->prefix))) { - xmlFreeNs(cur); - return(NULL); - } + if ((xmlStrEqual(prev->prefix, cur->prefix)) && + (prev->href != NULL)) + goto error; } prev->next = cur; } } return(cur); + +error: + xmlFreeNs(cur); + return(NULL); } /** * xmlSetNs: * @node: a node in the document - * @ns: a namespace pointer + * @ns: a namespace pointer (optional) * - * Associate a namespace to a node, a posteriori. + * Set the namespace of an element or attribute node. Passing a NULL + * namespace unsets the namespace. */ void xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { if (node == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlSetNs: node == NULL\n"); -#endif return; } if ((node->type == XML_ELEMENT_NODE) || @@ -818,15 +796,11 @@ xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { * xmlFreeNs: * @cur: the namespace pointer * - * Free up the structures associated to a namespace + * Free an xmlNs object. */ void xmlFreeNs(xmlNsPtr cur) { if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlFreeNs : ns == NULL\n"); -#endif return; } if (cur->href != NULL) xmlFree((char *) cur->href); @@ -838,16 +812,12 @@ xmlFreeNs(xmlNsPtr cur) { * xmlFreeNsList: * @cur: the first namespace pointer * - * Free up all the structures associated to the chained namespaces. + * Free a list of xmlNs objects. */ void xmlFreeNsList(xmlNsPtr cur) { xmlNsPtr next; if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlFreeNsList : ns == NULL\n"); -#endif return; } while (cur != NULL) { @@ -859,15 +829,21 @@ xmlFreeNsList(xmlNsPtr cur) { /** * xmlNewDtd: - * @doc: the document pointer - * @name: the DTD name - * @ExternalID: the external ID - * @SystemID: the system ID + * @doc: the document pointer (optional) + * @name: the DTD name (optional) + * @ExternalID: the external ID (optional) + * @SystemID: the system ID (optional) + * + * Create a DTD node. * - * Creation of a new DTD for the external subset. To create an - * internal subset, use xmlCreateIntSubset(). + * If a document is provided, it is an error if it already has an + * external subset. If the document has no external subset, it + * will be set to the created DTD. * - * Returns a pointer to the new DTD structure + * To create an internal subset, use xmlCreateIntSubset(). + * + * Returns a pointer to the new DTD object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const xmlChar *name, @@ -875,12 +851,6 @@ xmlNewDtd(xmlDocPtr doc, const xmlChar *name, 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); } @@ -888,19 +858,26 @@ xmlNewDtd(xmlDocPtr doc, const xmlChar *name, * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); - if (cur == NULL) { - xmlTreeErrMemory("building DTD"); + if (cur == NULL) return(NULL); - } memset(cur, 0 , sizeof(xmlDtd)); cur->type = XML_DTD_NODE; - if (name != NULL) + if (name != NULL) { cur->name = xmlStrdup(name); - if (ExternalID != NULL) + if (cur->name == NULL) + goto error; + } + if (ExternalID != NULL) { cur->ExternalID = xmlStrdup(ExternalID); - if (SystemID != NULL) + if (cur->ExternalID == NULL) + goto error; + } + if (SystemID != NULL) { cur->SystemID = xmlStrdup(SystemID); + if (cur->SystemID == NULL) + goto error; + } if (doc != NULL) doc->extSubset = cur; cur->doc = doc; @@ -908,16 +885,20 @@ xmlNewDtd(xmlDocPtr doc, const xmlChar *name, if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeDtd(cur); + return(NULL); } /** * xmlGetIntSubset: * @doc: the document pointer * - * Get the internal subset of a document - * Returns a pointer to the DTD structure or NULL if not found + * Get the internal subset of a document. + * + * Returns a pointer to the DTD object or NULL if not found. */ - xmlDtdPtr xmlGetIntSubset(const xmlDoc *doc) { xmlNodePtr cur; @@ -935,69 +916,55 @@ xmlGetIntSubset(const xmlDoc *doc) { /** * xmlCreateIntSubset: - * @doc: the document pointer - * @name: the DTD name - * @ExternalID: the external (PUBLIC) ID - * @SystemID: the system ID + * @doc: the document pointer (optional) + * @name: the DTD name (optional) + * @ExternalID: the external (PUBLIC) ID (optional) + * @SystemID: the system ID (optional) + * + * Create a DTD node. + * + * If a document is provided and it already has an internal subset, + * the existing DTD object is returned without creating a new object. + * If the document has no internal subset, it will be set to the + * created DTD. * - * Create the internal subset of a document - * Returns a pointer to the new DTD structure + * Returns a pointer to the new or existing DTD object or NULL if + * arguments are invalid or a memory allocation failed. */ xmlDtdPtr xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDtdPtr cur; - if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - - "xmlCreateIntSubset(): document %s already have an internal subset\n", - doc->name); -#endif - return(NULL); + if (doc != NULL) { + cur = xmlGetIntSubset(doc); + if (cur != NULL) + return(cur); } /* * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); - if (cur == NULL) { - xmlTreeErrMemory("building internal subset"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDtd)); cur->type = XML_DTD_NODE; if (name != NULL) { cur->name = xmlStrdup(name); - if (cur->name == NULL) { - xmlTreeErrMemory("building internal subset"); - xmlFree(cur); - return(NULL); - } + if (cur->name == NULL) + goto error; } if (ExternalID != NULL) { cur->ExternalID = xmlStrdup(ExternalID); - if (cur->ExternalID == NULL) { - xmlTreeErrMemory("building internal subset"); - if (cur->name != NULL) - xmlFree((char *)cur->name); - xmlFree(cur); - return(NULL); - } + if (cur->ExternalID == NULL) + goto error; } if (SystemID != NULL) { cur->SystemID = xmlStrdup(SystemID); - if (cur->SystemID == NULL) { - xmlTreeErrMemory("building internal subset"); - if (cur->name != NULL) - xmlFree((char *)cur->name); - if (cur->ExternalID != NULL) - xmlFree((char *)cur->ExternalID); - xmlFree(cur); - return(NULL); - } + if (cur->SystemID == NULL) + goto error; } if (doc != NULL) { doc->intSubset = cur; @@ -1041,6 +1008,10 @@ xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeDtd(cur); + return(NULL); } /** @@ -1055,42 +1026,6 @@ xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str)); - -/** - * DICT_COPY: - * @str: a string - * - * Copy a string using a "dict" dictionary in the current scope, - * if available. - */ -#define DICT_COPY(str, cpy) \ - if (str) { \ - if (dict) { \ - if (xmlDictOwns(dict, (const xmlChar *)(str))) \ - cpy = (xmlChar *) (str); \ - else \ - cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ - } else \ - cpy = xmlStrdup((const xmlChar *)(str)); } - -/** - * DICT_CONST_COPY: - * @str: a string - * - * Copy a string using a "dict" dictionary in the current scope, - * if available. - */ -#define DICT_CONST_COPY(str, cpy) \ - if (str) { \ - if (dict) { \ - if (xmlDictOwns(dict, (const xmlChar *)(str))) \ - cpy = (const xmlChar *) (str); \ - else \ - cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ - } else \ - cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); } - - /** * xmlFreeDtd: * @cur: the DTD structure to free up @@ -1118,11 +1053,10 @@ xmlFreeDtd(xmlDtdPtr cur) { */ while (c != NULL) { next = c->next; - if ((c->type != XML_NOTATION_NODE) && - (c->type != XML_ELEMENT_DECL) && + if ((c->type != XML_ELEMENT_DECL) && (c->type != XML_ATTRIBUTE_DECL) && (c->type != XML_ENTITY_DECL)) { - xmlUnlinkNode(c); + xmlUnlinkNodeInternal(c); xmlFreeNode(c); } c = next; @@ -1149,11 +1083,11 @@ xmlFreeDtd(xmlDtdPtr cur) { /** * xmlNewDoc: - * @version: xmlChar string giving the version of XML "1.0" + * @version: XML version string like "1.0" (optional) * - * Creates a new XML document + * Creates a new XML document. If version is NULL, "1.0" is used. * - * Returns a new document + * Returns a new document or NULL if a memory allocation failed. */ xmlDocPtr xmlNewDoc(const xmlChar *version) { @@ -1166,16 +1100,13 @@ xmlNewDoc(const xmlChar *version) { * Allocate a new document and fill the fields. */ cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); - if (cur == NULL) { - xmlTreeErrMemory("building doc"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDoc)); cur->type = XML_DOCUMENT_NODE; cur->version = xmlStrdup(version); if (cur->version == NULL) { - xmlTreeErrMemory("building doc"); xmlFree(cur); return(NULL); } @@ -1200,7 +1131,7 @@ xmlNewDoc(const xmlChar *version) { * xmlFreeDoc: * @cur: pointer to the document * - * Free up all the structures used by a document, tree included. + * Free a document including all children and associated DTDs. */ void xmlFreeDoc(xmlDocPtr cur) { @@ -1208,19 +1139,10 @@ xmlFreeDoc(xmlDocPtr cur) { 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; + dict = cur->dict; if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); @@ -1237,12 +1159,12 @@ xmlFreeDoc(xmlDocPtr cur) { if (intSubset == extSubset) extSubset = NULL; if (extSubset != NULL) { - xmlUnlinkNode((xmlNodePtr) cur->extSubset); + xmlUnlinkNodeInternal((xmlNodePtr) cur->extSubset); cur->extSubset = NULL; xmlFreeDtd(extSubset); } if (intSubset != NULL) { - xmlUnlinkNode((xmlNodePtr) cur->intSubset); + xmlUnlinkNodeInternal((xmlNodePtr) cur->intSubset); cur->intSubset = NULL; xmlFreeDtd(intSubset); } @@ -1259,38 +1181,52 @@ xmlFreeDoc(xmlDocPtr cur) { } /** - * xmlStringLenGetNodeList: - * @doc: the document - * @value: the value of the text - * @len: the length of the string value + * xmlNodeParseContentInternal: + * @doc: a document (optional) + * @parent: an element or attribute (optional) + * @value: an attribute value + * @len: maximum length of the attribute value + * @listPtr: pointer to the resulting node list (optional) * - * 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 + * See xmlNodeParseContent. + * + * Returns 0 on success, -1 if a memory allocation failed. */ -xmlNodePtr -xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { - xmlNodePtr ret = NULL, last = NULL; +static int +xmlNodeParseContentInternal(const xmlDoc *doc, xmlNodePtr parent, + const xmlChar *value, int len, + xmlNodePtr *listPtr) { + xmlNodePtr head = NULL, last = NULL; xmlNodePtr node; - xmlChar *val; - const xmlChar *cur, *end; + xmlChar *val = NULL; + const xmlChar *cur; const xmlChar *q; xmlEntityPtr ent; xmlBufPtr buf; + int remaining; + + if (listPtr != NULL) + *listPtr = NULL; + + if (len < 0) + remaining = INT_MAX; + else + remaining = len; + + if ((value == NULL) || (value[0] == 0)) + goto done; - if (value == NULL) return(NULL); cur = value; - end = cur + len; - buf = xmlBufCreateSize(0); - if (buf == NULL) return(NULL); + buf = xmlBufCreateSize(64); + if (buf == NULL) + return(-1); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); q = cur; - while ((cur < end) && (*cur != 0)) { + while ((remaining > 0) && (*cur != 0)) { if (cur[0] == '&') { int charval = 0; - xmlChar tmp; /* * Save the current text. @@ -1298,25 +1234,15 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { if (cur != q) { if (xmlBufAdd(buf, q, cur - q)) goto out; + q = cur; } - q = cur; - if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { + + if ((remaining > 2) && (cur[1] == '#') && (cur[2] == 'x')) { + int tmp = 0; + cur += 3; - if (cur < end) - tmp = *cur; - else - tmp = 0; - while (tmp != ';') { /* Non input consuming loop */ - /* - * If you find an integer overflow here when fuzzing, - * the bug is probably elsewhere. This function should - * only receive entities that were already validated by - * the parser, typically by xmlParseAttValueComplex - * calling xmlStringDecodeEntities. - * - * So it's better *not* to check for overflow to - * potentially discover new bugs. - */ + remaining -= 3; + while ((remaining > 0) && ((tmp = *cur) != ';')) { if ((tmp >= '0') && (tmp <= '9')) charval = charval * 16 + (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) @@ -1324,135 +1250,147 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { else if ((tmp >= 'A') && (tmp <= 'F')) charval = charval * 16 + (tmp - 'A') + 10; else { - xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, - NULL); charval = 0; break; } + if (charval > 0x110000) + charval = 0x110000; cur++; - if (cur < end) - tmp = *cur; - else - tmp = 0; + remaining--; } - if (tmp == ';') + if (tmp == ';') { cur++; + remaining--; + } q = cur; - } else if ((cur + 1 < end) && (cur[1] == '#')) { + } else if ((remaining > 1) && (cur[1] == '#')) { + int tmp = 0; + cur += 2; - if (cur < end) - tmp = *cur; - else - tmp = 0; - while (tmp != ';') { /* Non input consuming loops */ - /* Don't check for integer overflow, see above. */ + remaining -= 2; + while ((remaining > 0) && ((tmp = *cur) != ';')) { if ((tmp >= '0') && (tmp <= '9')) charval = charval * 10 + (tmp - '0'); else { - xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, - NULL); charval = 0; break; } + if (charval > 0x110000) + charval = 0x110000; cur++; - if (cur < end) - tmp = *cur; - else - tmp = 0; + remaining--; } - if (tmp == ';') + if (tmp == ';') { cur++; + remaining--; + } q = cur; } else { /* * Read the entity string */ cur++; + remaining--; q = cur; - while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; - if ((cur >= end) || (*cur == 0)) { - xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, - (const char *) q); - goto out; - } + while ((remaining > 0) && (*cur != 0) && (*cur != ';')) { + cur++; + remaining--; + } + if ((remaining <= 0) || (*cur == 0)) + break; if (cur != q) { - /* - * Predefined entities don't generate nodes - */ val = xmlStrndup(q, cur - q); + if (val == NULL) + goto out; ent = xmlGetDocEntity(doc, val); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - + /* + * Predefined entities don't generate nodes + */ if (xmlBufCat(buf, ent->content)) goto out; - } else { /* * Flush buffer so far */ if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); - if (node == NULL) { - if (val != NULL) xmlFree(val); + if (node == NULL) goto out; - } node->content = xmlBufDetach(buf); + node->parent = parent; if (last == NULL) { - last = ret = node; + head = node; } else { - last = xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } + last = node; + } + + if ((ent != NULL) && + ((ent->flags & XML_ENT_PARSED) == 0) && + ((ent->flags & XML_ENT_EXPANDING) == 0) && + (ent->content != NULL)) { + int res; + + ent->flags |= XML_ENT_EXPANDING; + res = xmlNodeParseContentInternal(doc, + (xmlNodePtr) ent, ent->content, -1, NULL); + ent->flags &= ~XML_ENT_EXPANDING; + if (res < 0) + goto out; + ent->flags |= XML_ENT_PARSED; } /* * Create a new REFERENCE_REF node */ - node = xmlNewReference(doc, val); - if (node == NULL) { - if (val != NULL) xmlFree(val); + node = xmlNewEntityRef((xmlDocPtr) doc, val); + val = NULL; + if (node == NULL) goto out; - } - else if ((ent != NULL) && (ent->children == NULL)) { - xmlNodePtr temp; - - /* Set to non-NULL value to avoid recursion. */ - ent->children = (xmlNodePtr) -1; - 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; - } - } + node->parent = parent; + node->last = (xmlNodePtr) ent; + if (ent != NULL) { + node->children = (xmlNodePtr) ent; + node->content = ent->content; + } + if (last == NULL) { - last = ret = node; + head = node; } else { - last = xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } + last = node; } xmlFree(val); + val = NULL; } cur++; + remaining--; q = cur; } if (charval != 0) { xmlChar buffer[10]; int l; + if (charval >= 0x110000) + charval = 0xFFFD; /* replacement character */ + l = xmlCopyCharMultiByte(buffer, charval); buffer[l] = 0; if (xmlBufCat(buf, buffer)) goto out; - charval = 0; } - } else + } else { cur++; + remaining--; + } } if (cur != q) { @@ -1465,391 +1403,258 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); - if (node == NULL) goto out; + if (node == NULL) + goto out; + node->parent = parent; node->content = xmlBufDetach(buf); if (last == NULL) { - ret = node; + head = node; } else { - xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } - } else if (ret == NULL) { - ret = xmlNewDocText(doc, BAD_CAST ""); + last = node; + } else if (head == NULL) { + head = xmlNewDocText(doc, BAD_CAST ""); + if (head == NULL) + goto out; + head->parent = parent; + last = head; + } + + xmlBufFree(buf); + +done: + if (parent != NULL) { + if (parent->children != NULL) + xmlFreeNodeList(parent->children); + parent->children = head; + parent->last = last; } + if (listPtr != NULL) + *listPtr = head; + + return(0); + out: xmlBufFree(buf); + if (val != NULL) + xmlFree(val); + if (head != NULL) + xmlFreeNodeList(head); + return(-1); +} + +/** + * xmlNodeParseContent: + * @node: an element or attribute + * @content: text content with XML references + * @len: maximum length of content + * + * Parse content and replace the node's children with the resulting + * node list. + * + * @content is expected to be a valid XML attribute value possibly + * containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * Only references are handled, nested elements, comments or PIs are + * not. + * + * Returns 0 on success, -1 if a memory allocation failed. + */ +int +xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len) { + return(xmlNodeParseContentInternal(node->doc, node, content, len, NULL)); +} + +/** + * xmlStringLenGetNodeList: + * @doc: a document (optional) + * @value: an attribute value + * @len: maximum length of the attribute value + * + * DEPRECATED: Use xmlNodeSetContentLen. + * + * See xmlStringGetNodeList. + * + * Returns a pointer to the first child or NULL if a memory + * allocation failed. + */ +xmlNodePtr +xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { + xmlNodePtr ret; + + xmlNodeParseContentInternal(doc, NULL, value, len, &ret); return(ret); } /** * xmlStringGetNodeList: - * @doc: the document - * @value: the value of the attribute + * @doc: a document (optional) + * @value: an attribute value + * + * DEPRECATED: Use xmlNodeSetContent. + * + * Parse an attribute value and build a node list containing only + * text and entity reference nodes. The resulting nodes will be + * associated with the document if provided. The document is also + * used to look up entities. + * + * The input is not validated. Syntax errors or references to + * undeclared entities will be ignored silently with unspecified + * results. * - * Parse the value string and build the node list associated. Should - * produce a flat tree with only TEXTs and ENTITY_REFs. - * Returns a pointer to the first child + * Returns a pointer to the first child or NULL if a memory + * allocation failed. */ xmlNodePtr xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) { - xmlNodePtr ret = NULL, last = NULL; - xmlNodePtr node; - xmlChar *val; - const xmlChar *cur = value; - const xmlChar *q; - xmlEntityPtr ent; + xmlNodePtr ret; + + xmlNodeParseContentInternal(doc, NULL, value, -1, &ret); + return(ret); +} + +/** + * xmlNodeListGetStringInternal: + * @doc: a document (optional) + * @node: a node list + * @escMode: escape mode (0 = no, 1 = elem, 2 = attr, 3 = raw) + * + * Returns a pointer to the string. + */ +static xmlChar * +xmlNodeListGetStringInternal(xmlDocPtr doc, const xmlNode *node, int escMode) { xmlBufPtr buf; + xmlChar *ret; - if (value == NULL) return(NULL); + if (node == NULL) + return(xmlStrdup(BAD_CAST "")); - buf = xmlBufCreateSize(0); - if (buf == NULL) return(NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + if ((escMode == 0) && + ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + (node->next == NULL)) { + if (node->content == NULL) + return(xmlStrdup(BAD_CAST "")); + return(xmlStrdup(node->content)); + } - q = cur; - while (*cur != 0) { - if (cur[0] == '&') { - int charval = 0; - xmlChar tmp; + buf = xmlBufCreateSize(64); + if (buf == NULL) + return(NULL); - /* - * Save the current text. - */ - if (cur != q) { - if (xmlBufAdd(buf, q, cur - q)) - goto out; - } - q = cur; - if ((cur[1] == '#') && (cur[2] == 'x')) { - cur += 3; - tmp = *cur; - while (tmp != ';') { /* Non input consuming loop */ - /* Don't check for integer overflow, see above. */ - if ((tmp >= '0') && (tmp <= '9')) - charval = charval * 16 + (tmp - '0'); - else if ((tmp >= 'a') && (tmp <= 'f')) - charval = charval * 16 + (tmp - 'a') + 10; - else if ((tmp >= 'A') && (tmp <= 'F')) - charval = charval * 16 + (tmp - 'A') + 10; - else { - xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, - NULL); - charval = 0; - break; - } - cur++; - tmp = *cur; - } - if (tmp == ';') - cur++; - q = cur; - } else if (cur[1] == '#') { - cur += 2; - tmp = *cur; - while (tmp != ';') { /* Non input consuming loops */ - /* Don't check for integer overflow, see above. */ - if ((tmp >= '0') && (tmp <= '9')) - charval = charval * 10 + (tmp - '0'); - else { - xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, - NULL); - charval = 0; - break; - } - cur++; - tmp = *cur; - } - if (tmp == ';') - cur++; - q = cur; - } else { - /* - * Read the entity string - */ - cur++; - q = cur; - while ((*cur != 0) && (*cur != ';')) cur++; - if (*cur == 0) { - xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, - (xmlNodePtr) doc, (const char *) q); - goto out; - } - if (cur != q) { - /* - * Predefined entities don't generate nodes - */ - val = xmlStrndup(q, cur - q); - ent = xmlGetDocEntity(doc, val); - if ((ent != NULL) && - (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - - if (xmlBufCat(buf, ent->content)) - goto out; - - } else { - /* - * Flush buffer so far - */ - if (!xmlBufIsEmpty(buf)) { - node = xmlNewDocText(doc, NULL); - if (node == NULL) { - if (val != NULL) xmlFree(val); - goto out; - } - node->content = xmlBufDetach(buf); - - if (last == NULL) { - last = ret = node; - } else { - last = xmlAddNextSibling(last, node); - } - } - - /* - * Create a new REFERENCE_REF node - */ - node = xmlNewReference(doc, val); - if (node == NULL) { - if (val != NULL) xmlFree(val); - goto out; - } - else if ((ent != NULL) && (ent->children == NULL)) { - xmlNodePtr temp; - - /* Set to non-NULL value to avoid recursion. */ - ent->children = (xmlNodePtr) -1; - 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 buffer[10]; - int len; - - len = xmlCopyCharMultiByte(buffer, charval); - buffer[len] = 0; - - if (xmlBufCat(buf, buffer)) - goto out; - charval = 0; - } - } else - cur++; - } - if ((cur != q) || (ret == NULL)) { - /* - * Handle the last piece of text. - */ - xmlBufAdd(buf, q, cur - q); - } - - if (!xmlBufIsEmpty(buf)) { - node = xmlNewDocText(doc, NULL); - if (node == NULL) { - xmlBufFree(buf); - return(NULL); + while (node != NULL) { + if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + if (node->content != NULL) { + if (escMode == 0) { + xmlBufCat(buf, node->content); + } else { + xmlChar *encoded; + + if (escMode == 1) + encoded = xmlEncodeEntitiesReentrant(doc, + node->content); + else if (escMode == 2) + encoded = xmlEncodeAttributeEntities(doc, + node->content); + else + encoded = xmlEncodeSpecialChars(doc, node->content); + if (encoded == NULL) + goto error; + xmlBufCat(buf, encoded); + xmlFree(encoded); + } + } + } else if (node->type == XML_ENTITY_REF_NODE) { + if (escMode == 0) { + xmlBufGetNodeContent(buf, node); + } else { + xmlBufAdd(buf, BAD_CAST "&", 1); + xmlBufCat(buf, node->name); + xmlBufAdd(buf, BAD_CAST ";", 1); + } } - node->content = xmlBufDetach(buf); - if (last == NULL) { - ret = node; - } else { - xmlAddNextSibling(last, node); - } + node = node->next; } -out: + ret = xmlBufDetach(buf); xmlBufFree(buf); return(ret); + +error: + xmlBufFree(buf); + return(NULL); } /** * xmlNodeListGetString: - * @doc: the document - * @list: a Node list - * @inLine: should we replace entity contents or show their external form + * @doc: a document (optional) + * @list: a node list of attribute children + * @inLine: whether entity references are substituted * - * Build the string equivalent to the text contained in the Node list - * made of TEXTs and ENTITY_REFs + * Serializes attribute children (text and entity reference nodes) + * into a string. * - * Returns a pointer to the string copy, the caller must free it with xmlFree(). + * If @inLine is true, entity references will be substituted. + * Otherwise, entity references will be kept and special characters + * like '&' as well as non-ASCII chars will be escaped. See + * xmlNodeListGetRawString for an alternative option. + * + * Returns a string or NULL if a memory allocation failed. */ xmlChar * xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine) { - const xmlNode *node = list; - xmlChar *ret = NULL; - xmlEntityPtr ent; - int attr; + int escMode; + /* backward compatibility */ if (list == NULL) - return (NULL); - if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE)) - attr = 1; - else - attr = 0; - - while (node != NULL) { - if ((node->type == XML_TEXT_NODE) || - (node->type == XML_CDATA_SECTION_NODE)) { - if (inLine) { - ret = xmlStrcat(ret, node->content); - } else { - xmlChar *buffer; + return(NULL); - if (attr) - buffer = xmlEncodeAttributeEntities(doc, node->content); - else - buffer = xmlEncodeEntitiesReentrant(doc, node->content); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } - } else if (node->type == XML_ENTITY_REF_NODE) { - if (inLine) { - ent = xmlGetDocEntity(doc, node->name); - if (ent != NULL) { - xmlChar *buffer; - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content. - * So it can contain text, CDATA section or nested - * entity reference nodes (among others). - * -> we recursive call xmlNodeListGetString() - * which handles these types */ - buffer = xmlNodeListGetString(doc, ent->children, 1); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } else { - ret = xmlStrcat(ret, node->content); - } - } else { - xmlChar buf[2]; - - buf[0] = '&'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - ret = xmlStrcat(ret, node->name); - buf[0] = ';'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - } - } -#if 0 - else { - xmlGenericError(xmlGenericErrorContext, - "xmlGetNodeListString : invalid node type %d\n", - node->type); - } -#endif - node = node->next; + if (inLine) { + escMode = 0; + } else { + if ((list->parent != NULL) && + (list->parent->type == XML_ATTRIBUTE_NODE)) + escMode = 2; + else + escMode = 1; } - return (ret); + + return(xmlNodeListGetStringInternal(doc, list, escMode)); } #ifdef LIBXML_TREE_ENABLED /** * xmlNodeListGetRawString: - * @doc: the document - * @list: a Node list - * @inLine: should we replace entity contents or show their external form + * @doc: a document (optional) + * @list: a node list of attribute children + * @inLine: whether entity references are substituted + * + * Serializes attribute children (text and entity reference nodes) + * into a string. * - * 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. + * If @inLine is true, entity references will be substituted. + * Otherwise, entity references will be kept and special characters + * like '&' will be escaped. * - * Returns a pointer to the string copy, the caller must free it with xmlFree(). + * Returns a string or NULL if a memory allocation failed. */ xmlChar * xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine) { - const xmlNode *node = list; - xmlChar *ret = NULL; - xmlEntityPtr ent; + int escMode = inLine ? 0 : 3; + /* backward compatibility */ if (list == NULL) - return (NULL); - - while (node != NULL) { - if ((node->type == XML_TEXT_NODE) || - (node->type == XML_CDATA_SECTION_NODE)) { - if (inLine) { - ret = xmlStrcat(ret, node->content); - } else { - xmlChar *buffer; + return(NULL); - buffer = xmlEncodeSpecialChars(doc, node->content); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } - } else if (node->type == XML_ENTITY_REF_NODE) { - if (inLine) { - ent = xmlGetDocEntity(doc, node->name); - if (ent != NULL) { - xmlChar *buffer; - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content. - * So it can contain text, CDATA section or nested - * entity reference nodes (among others). - * -> we recursive call xmlNodeListGetRawString() - * which handles these types */ - buffer = - xmlNodeListGetRawString(doc, ent->children, 1); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } else { - ret = xmlStrcat(ret, node->content); - } - } else { - xmlChar buf[2]; - - buf[0] = '&'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - ret = xmlStrcat(ret, node->name); - buf[0] = ';'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - } - } -#if 0 - else { - xmlGenericError(xmlGenericErrorContext, - "xmlGetNodeListString : invalid node type %d\n", - node->type); - } -#endif - node = node->next; - } - return (ret); + return(xmlNodeListGetStringInternal((xmlDocPtr) doc, list, escMode)); } #endif /* LIBXML_TREE_ENABLED */ @@ -1863,7 +1668,7 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { if ((eatname == 1) && - ((node->doc == NULL) || + ((node->doc == NULL) || (node->doc->dict == NULL) || (!(xmlDictOwns(node->doc->dict, name))))) xmlFree((xmlChar *) name); return (NULL); @@ -1876,9 +1681,9 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, if (cur == NULL) { if ((eatname == 1) && ((node == NULL) || (node->doc == NULL) || + (node->doc->dict == NULL) || (!(xmlDictOwns(node->doc->dict, name))))) xmlFree((xmlChar *) name); - xmlTreeErrMemory("building attribute"); return (NULL); } memset(cur, 0, sizeof(xmlAttr)); @@ -1896,6 +1701,8 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; } else cur->name = name; @@ -1903,6 +1710,8 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, xmlNodePtr tmp; cur->children = xmlNewDocText(doc, value); + if (cur->children == NULL) + goto error; cur->last = NULL; tmp = cur->children; while (tmp != NULL) { @@ -1911,6 +1720,15 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, cur->last = tmp; tmp = tmp->next; } + + if (doc != NULL) { + int res = xmlIsID(doc, node, cur); + + if (res < 0) + goto error; + if ((res == 1) && (xmlAddIDSafe(cur, value) < 0)) + goto error; + } } /* @@ -1929,34 +1747,38 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, } } - if ((value != NULL) && (node != NULL) && - (xmlIsID(node->doc, node, cur) == 1)) - xmlAddID(NULL, node->doc, value, cur); - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr) cur); return (cur); + +error: + xmlFreeProp(cur); + return(NULL); } #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) /** * xmlNewProp: - * @node: the holding node + * @node: the parent node (optional) * @name: the name of the attribute - * @value: the value of the attribute + * @value: the value of the attribute (optional) + * + * Create an attribute node. + * + * If provided, @value should be a raw, unescaped string. + * + * If @node is provided, the created attribute will be appended without + * checking for duplicate names. It is an error if @node is not an + * element. * - * Create a new property carried by a node. - * Returns a pointer to the attribute + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewProp : name == NULL\n"); -#endif return(NULL); } @@ -1966,23 +1788,27 @@ xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { /** * xmlNewNsProp: - * @node: the holding node - * @ns: the namespace - * @name: the name of the attribute - * @value: the value of the attribute + * @node: the parent node (optional) + * @ns: the namespace (optional) + * @name: the local name of the attribute + * @value: the value of the attribute (optional) + * + * Create an attribute object. + * + * If provided, @value should be a raw, unescaped string. * - * Create a new property tagged with a namespace and carried by a node. - * Returns a pointer to the attribute + * If @node is provided, the created attribute will be appended without + * checking for duplicate names. It is an error if @node is not an + * element. + * + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value) { if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewNsProp : name == NULL\n"); -#endif return(NULL); } @@ -1991,23 +1817,23 @@ xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, /** * xmlNewNsPropEatName: - * @node: the holding node - * @ns: the namespace - * @name: the name of the attribute - * @value: the value of the attribute + * @node: the parent node (optional) + * @ns: the namespace (optional) + * @name: the local name of the attribute + * @value: the value of the attribute (optional) + * + * Like xmlNewNsProp, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. * - * Create a new property tagged with a namespace and carried by a node. - * Returns a pointer to the attribute + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, const xmlChar *value) { if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewNsPropEatName : name == NULL\n"); -#endif return(NULL); } @@ -2016,27 +1842,25 @@ xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, /** * xmlNewDocProp: - * @doc: the document + * @doc: the target document (optional) * @name: the name of the attribute - * @value: the value of the attribute + * @value: attribute value with XML references (optional) * - * Create a new property carried by a document. - * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need - * entities support. + * Create an attribute object. * - * Returns a pointer to the attribute + * If provided, @value is expected to be a valid XML attribute value + * possibly containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * If you want to pass a raw string, see xmlNewProp. + * + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ 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); } @@ -2044,10 +1868,8 @@ xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { * Allocate a new property and fill the fields. */ cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); - if (cur == NULL) { - xmlTreeErrMemory("building attribute"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlAttr)); cur->type = XML_ATTRIBUTE_NODE; @@ -2055,32 +1877,28 @@ xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; cur->doc = doc; if (value != NULL) { - xmlNodePtr tmp; - - cur->children = xmlStringGetNodeList(doc, value); - cur->last = NULL; - - tmp = cur->children; - while (tmp != NULL) { - tmp->parent = (xmlNodePtr) cur; - if (tmp->next == NULL) - cur->last = tmp; - tmp = tmp->next; - } + if (xmlNodeParseContent((xmlNodePtr) cur, value, -1) < 0) + goto error; } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeProp(cur); + return(NULL); } /** * xmlFreePropList: - * @cur: the first property in the list + * @cur: the first attribute in the list * - * Free a property and all its siblings, all the children are freed too. + * Free an attribute list including all children. */ void xmlFreePropList(xmlAttrPtr cur) { @@ -2097,7 +1915,7 @@ xmlFreePropList(xmlAttrPtr cur) { * xmlFreeProp: * @cur: an attribute * - * Free one attribute, all the content is freed too + * Free an attribute including all children. */ void xmlFreeProp(xmlAttrPtr cur) { @@ -2122,26 +1940,22 @@ xmlFreeProp(xmlAttrPtr cur) { * xmlRemoveProp: * @cur: an attribute * - * Unlink and free one attribute, all the content is freed too - * Note this doesn't work for namespace definition attributes + * Unlink and free an attribute including all children. * - * Returns 0 if success and -1 in case of error. + * Note this doesn't work for namespace declarations. + * + * The attribute must have a non-NULL parent pointer. + * + * Returns 0 on success or -1 if the attribute was not found or + * arguments are invalid. */ int xmlRemoveProp(xmlAttrPtr cur) { 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; @@ -2162,31 +1976,25 @@ xmlRemoveProp(xmlAttrPtr cur) { } 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 + * @doc: the target document (optional) + * @name: the processing instruction target + * @content: the PI content (optional) * - * Creation of a processing instruction element. - * Returns a pointer to the new node object. + * Create a processing instruction object. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur; if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewPI : name == NULL\n"); -#endif return(NULL); } @@ -2194,37 +2002,44 @@ xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building PI"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_PI_NODE; + cur->doc = doc; if ((doc != NULL) && (doc->dict != NULL)) cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; } - cur->doc = doc; if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); } /** * xmlNewPI: - * @name: the processing instruction name - * @content: the PI content + * @name: the processing instruction target + * @content: the PI content (optional) * - * Creation of a processing instruction element. + * Create a processing instruction node. * * Use of this function is DISCOURAGED in favor of xmlNewDocPI. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewPI(const xmlChar *name, const xmlChar *content) { @@ -2233,124 +2048,122 @@ xmlNewPI(const xmlChar *name, const xmlChar *content) { /** * xmlNewNode: - * @ns: namespace if any + * @ns: namespace (optional) * @name: the node name * - * Creation of a new node element. @ns is optional (NULL). + * Create an element node. * * Use of this function is DISCOURAGED in favor of xmlNewDocNode. * - * Returns a pointer to the new node object. Uses xmlStrdup() to make - * copy of @name. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewNode(xmlNsPtr ns, const xmlChar *name) { - xmlNodePtr cur; - - if (name == NULL) { -#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); + return(xmlNewDocNode(NULL, ns, name, NULL)); } /** * xmlNewNodeEatName: - * @ns: namespace if any + * @ns: namespace (optional) * @name: the node name * - * Creation of a new node element. @ns is optional (NULL). + * Create an element node. * * Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName. * - * Returns a pointer to the new node object, with pointer @name as - * new node's name. Use xmlNewNode() if a copy of @name string is - * is needed as new node's name. + * Like xmlNewNode, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { - xmlNodePtr cur; + return(xmlNewDocNodeEatName(NULL, ns, name, NULL)); +} - if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewNode : name == NULL\n"); -#endif - return(NULL); - } +static xmlNodePtr +xmlNewElem(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, + const xmlChar *content) { + xmlNodePtr cur; - /* - * Allocate a new node and fill the fields. - */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building node"); - /* we can't check here that name comes from the doc dictionary */ + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); - cur->type = XML_ELEMENT_NODE; + cur->type = XML_ELEMENT_NODE; + cur->doc = doc; cur->name = name; cur->ns = ns; - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + if (content != NULL) { + if (xmlNodeParseContent(cur, content, -1) < 0) { + /* Don't free name on error */ + xmlFree(cur); + return(NULL); + } + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); } /** * xmlNewDocNode: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the XML text content if any + * @content: text content with XML references (optional) + * + * Create an element node. + * + * If provided, @content is expected to be a valid XML attribute value + * possibly containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * Only references are handled, nested elements, comments or PIs are + * not. See xmlNewDocRawNode for an alternative. + * + * General notes on object creation: * - * 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. + * Each node and all its children are associated with the same + * document. The document should be provided when creating nodes to + * avoid a performance penalty when adding the node to a document + * tree. Note that a document only owns nodes reachable from the root + * node. Unlinked subtrees must be freed manually. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur; + xmlChar *copy; - if ((doc != NULL) && (doc->dict != NULL)) - cur = xmlNewNodeEatName(ns, (xmlChar *) - xmlDictLookup(doc->dict, name, -1)); - else - cur = xmlNewNode(ns, name); - if (cur != NULL) { - cur->doc = doc; - if (content != NULL) { - cur->children = xmlStringGetNodeList(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) - } + if (name == NULL) + return(NULL); + + if ((doc != NULL) && (doc->dict != NULL)) { + const xmlChar *dictName = xmlDictLookup(doc->dict, name, -1); + + if (dictName == NULL) + return(NULL); + return(xmlNewElem(doc, ns, dictName, content)); + } + + copy = xmlStrdup(name); + if (copy == NULL) + return(NULL); + + cur = xmlNewElem(doc, ns, copy, content); + if (cur == NULL) { + xmlFree(copy); + return(NULL); } return(cur); @@ -2358,53 +2171,55 @@ xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, /** * xmlNewDocNodeEatName: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the XML text content if any + * @content: text content with XML references (optional) + * + * Create an element node. * - * Creation of a new node element within a document. @ns and @content - * are optional (NULL). - * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't - * need entities support. + * Like xmlNewDocNode, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, - xmlChar *name, const xmlChar *content) { + xmlChar *name, const xmlChar *content) { xmlNodePtr cur; - cur = xmlNewNodeEatName(ns, name); - if (cur != NULL) { - cur->doc = doc; - if (content != NULL) { - cur->children = xmlStringGetNodeList(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) - } - } else { - /* if name don't come from the doc dictionary free it here */ - if ((name != NULL) && (doc != NULL) && - (!(xmlDictOwns(doc->dict, name)))) - xmlFree(name); + if (name == NULL) + return(NULL); + + cur = xmlNewElem(doc, ns, name, content); + if (cur == NULL) { + /* if name doesn't come from the doc dictionary free it here */ + if ((doc == NULL) || + (doc->dict == NULL) || + (!xmlDictOwns(doc->dict, name))) + xmlFree(name); + return(NULL); } + return(cur); } #ifdef LIBXML_TREE_ENABLED /** * xmlNewDocRawNode: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the text content if any + * @content: raw text content (optional) + * + * Create an element node. * - * Creation of a new node element within a document. @ns and @content - * are optional (NULL). + * If provided, @value should be a raw, unescaped string. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, @@ -2415,8 +2230,17 @@ xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, if (cur != NULL) { cur->doc = doc; if (content != NULL) { - cur->children = xmlNewDocText(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) + xmlNodePtr text; + + text = xmlNewDocText(doc, content); + if (text == NULL) { + xmlFreeNode(cur); + return(NULL); + } + + cur->children = text; + cur->last = text; + text->parent = cur; } } return(cur); @@ -2424,10 +2248,12 @@ xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, /** * xmlNewDocFragment: - * @doc: the document owning the fragment + * @doc: the target document (optional) * - * Creation of a new Fragment node. - * Returns a pointer to the new node object. + * Create a document fragment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocFragment(xmlDocPtr doc) { @@ -2437,10 +2263,8 @@ xmlNewDocFragment(xmlDocPtr doc) { * Allocate a new DocumentFragment node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building fragment"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_DOCUMENT_FRAG_NODE; @@ -2454,13 +2278,14 @@ xmlNewDocFragment(xmlDocPtr doc) { /** * xmlNewText: - * @content: the text content + * @content: raw text content (optional) * - * Creation of a new text node. + * Create a text node. * * Use of this function is DISCOURAGED in favor of xmlNewDocText. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewText(const xmlChar *content) { @@ -2470,91 +2295,77 @@ xmlNewText(const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building text"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE; cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); } #ifdef LIBXML_TREE_ENABLED /** * xmlNewTextChild: * @parent: the parent node - * @ns: a namespace if any + * @ns: a namespace (optional) * @name: the name of the child - * @content: the text content of the child if any. + * @content: raw text content of the child (optional) + * + * Create a new child element and append it to a parent element. * - * Creation of a new child element, added at the end of @parent children list. - * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly - * created element inherits the namespace of @parent. If @content is non NULL, - * a child TEXT node will be created containing the string @content. - * NOTE: Use xmlNewChild() if @content will contain entities that need to be - * preserved. Use this function, xmlNewTextChild(), if you need to ensure that - * reserved XML chars that might appear in @content, such as the ampersand, - * greater-than or less-than signs, are automatically replaced by their XML - * escaped entity representations. + * If @ns is NULL, the newly created element inherits the namespace + * of the parent. * - * Returns a pointer to the new node object. + * If @content is provided, a text node will be added to the child + * element, see xmlNewDocRawNode. + * + * Returns a pointer to the new node object or NULL if arguments + * are invalid or a memory allocation failed. */ xmlNodePtr xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev; - if (parent == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextChild : parent == NULL\n"); -#endif + if ((parent == NULL) || (name == NULL)) return(NULL); - } - if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextChild : name == NULL\n"); -#endif - return(NULL); - } + switch (parent->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + break; - /* - * Allocate a new node - */ - if (parent->type == XML_ELEMENT_NODE) { - if (ns == NULL) - cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content); - else - cur = xmlNewDocRawNode(parent->doc, ns, name, content); - } else if ((parent->type == XML_DOCUMENT_NODE) || - (parent->type == XML_HTML_DOCUMENT_NODE)) { - if (ns == NULL) - cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content); - else - cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content); - } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { - cur = xmlNewDocRawNode( parent->doc, ns, name, content); - } else { - return(NULL); + case XML_ELEMENT_NODE: + if (ns == NULL) + ns = parent->ns; + break; + + default: + return(NULL); } - if (cur == NULL) return(NULL); + + cur = xmlNewDocRawNode(parent->doc, ns, name, content); + if (cur == NULL) + return(NULL); /* * add the new element at the end of the children list. */ - cur->type = XML_ELEMENT_NODE; cur->parent = parent; - cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; @@ -2570,55 +2381,92 @@ xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, #endif /* LIBXML_TREE_ENABLED */ /** - * xmlNewCharRef: - * @doc: the document - * @name: the char ref string, starting with # or "&# ... ;" + * xmlNewEntityRef: + * @doc: the target document (optional) + * @name: the entity name + * + * Create an empty entity reference node. This function doesn't attempt + * to look up the entity in @doc. * - * Creation of a new character reference node. - * Returns a pointer to the new node object. + * @name is consumed. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ -xmlNodePtr -xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { +static xmlNodePtr +xmlNewEntityRef(xmlDocPtr doc, xmlChar *name) { xmlNodePtr cur; - if (name == NULL) - return(NULL); - /* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { - xmlTreeErrMemory("building character reference"); + xmlFree(name); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE; - cur->doc = doc; + cur->name = name; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + + return(cur); +} + +/** + * xmlNewCharRef: + * @doc: the target document (optional) + * @name: the entity name + * + * This function is MISNAMED. It doesn't create a character reference + * but an entity reference. + * + * Create an empty entity reference node. This function doesn't attempt + * to look up the entity in @doc. + * + * Entity names like '&entity;' are handled as well. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. + */ +xmlNodePtr +xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { + xmlChar *copy; + + if (name == NULL) + return(NULL); + if (name[0] == '&') { int len; name++; len = xmlStrlen(name); if (name[len - 1] == ';') - cur->name = xmlStrndup(name, len - 1); + copy = xmlStrndup(name, len - 1); else - cur->name = xmlStrndup(name, len); + copy = xmlStrndup(name, len); } else - cur->name = xmlStrdup(name); + copy = xmlStrdup(name); + if (copy == NULL) + return(NULL); - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue(cur); - return(cur); + return(xmlNewEntityRef(doc, copy)); } /** * xmlNewReference: - * @doc: the document - * @name: the reference name, or the reference string with & and ; + * @doc: the target document (optional) + * @name: the entity name * - * Creation of a new reference node. - * Returns a pointer to the new node object. + * Create a new entity reference node, linking the result with the + * entity in @doc if found. + * + * Entity names like '&entity;' are handled as well. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewReference(const xmlDoc *doc, const xmlChar *name) { @@ -2632,10 +2480,8 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building reference"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE; @@ -2650,6 +2496,8 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { cur->name = xmlStrndup(name, len); } else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; ent = xmlGetDocEntity(doc, cur->name); if (ent != NULL) { @@ -2666,15 +2514,21 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); } /** * xmlNewDocText: - * @doc: the document - * @content: the text content + * @doc: the target document + * @content: raw text content (optional) * - * Creation of a new text node within a document. - * Returns a pointer to the new node object. + * Create a new text node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocText(const xmlDoc *doc, const xmlChar *content) { @@ -2687,13 +2541,13 @@ xmlNewDocText(const xmlDoc *doc, const xmlChar *content) { /** * xmlNewTextLen: - * @content: the text content - * @len: the text len. + * @content: raw text content (optional) + * @len: size of text content * * Use of this function is DISCOURAGED in favor of xmlNewDocTextLen. * - * Creation of a new text node with an extra parameter for the content's length - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewTextLen(const xmlChar *content, int len) { @@ -2703,16 +2557,18 @@ xmlNewTextLen(const xmlChar *content, int len) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building text"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE; cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrndup(content, len); + if (cur->content == NULL) { + xmlFreeNode(cur); + return(NULL); + } } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) @@ -2722,13 +2578,14 @@ xmlNewTextLen(const xmlChar *content, int len) { /** * xmlNewDocTextLen: - * @doc: the document - * @content: the text content - * @len: the text len. + * @doc: the target document + * @content: raw text content (optional) + * @len: size of text content + * + * Create a new text node. * - * Creation of a new text node with an extra content length parameter. The - * text node pertain to a given document. - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { @@ -2741,12 +2598,14 @@ xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { /** * xmlNewComment: - * @content: the comment content + * @content: the comment content (optional) * * Use of this function is DISCOURAGED in favor of xmlNewDocComment. * - * Creation of a new node containing a comment. - * Returns a pointer to the new node object. + * Create a comment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewComment(const xmlChar *content) { @@ -2756,31 +2615,37 @@ xmlNewComment(const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building comment"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_COMMENT_NODE; cur->name = xmlStringComment; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); } /** * xmlNewCDataBlock: - * @doc: the document - * @content: the CDATA block content content - * @len: the length of the block + * @doc: the target document (optional) + * @content: raw text content (optional) + * @len: size of text content * - * Creation of a new node containing a CDATA block. - * Returns a pointer to the new node object. + * Create a CDATA section node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { @@ -2790,16 +2655,18 @@ xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building CDATA"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_CDATA_SECTION_NODE; cur->doc = doc; if (content != NULL) { cur->content = xmlStrndup(content, len); + if (cur->content == NULL) { + xmlFree(cur); + return(NULL); + } } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) @@ -2812,8 +2679,10 @@ xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { * @doc: the document * @content: the comment content * - * Creation of a new node containing a comment within a document. - * Returns a pointer to the new node object. + * Create a comment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { @@ -2824,172 +2693,293 @@ xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { return(cur); } -static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) { - const xmlChar *newValue = oldValue; - if (oldValue) { - int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1); - if (oldDictOwnsOldValue) { +static void +xmlRemoveEntity(xmlEntityPtr ent) { + xmlDocPtr doc = ent->doc; + xmlDtdPtr intSubset, extSubset; + + if (doc == NULL) + return; + intSubset = doc->intSubset; + extSubset = doc->extSubset; + + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY)) { + if (intSubset != NULL) { + if (xmlHashLookup(intSubset->entities, ent->name) == ent) + xmlHashRemoveEntry(intSubset->entities, ent->name, NULL); + } + if (extSubset != NULL) { + if (xmlHashLookup(extSubset->entities, ent->name) == ent) + xmlHashRemoveEntry(extSubset->entities, ent->name, NULL); + } + } else if ((ent->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + if (intSubset != NULL) { + if (xmlHashLookup(intSubset->pentities, ent->name) == ent) + xmlHashRemoveEntry(intSubset->entities, ent->name, NULL); + } + if (extSubset != NULL) { + if (xmlHashLookup(extSubset->pentities, ent->name) == ent) + xmlHashRemoveEntry(extSubset->entities, ent->name, NULL); + } + } +} + +static int +xmlNodeSetDoc(xmlNodePtr node, xmlDocPtr doc) { + xmlDocPtr oldDoc; + xmlDictPtr oldDict, newDict; + int ret = 0; + + /* + * Remove name and content from old dictionary + */ + + oldDoc = node->doc; + oldDict = oldDoc ? oldDoc->dict : NULL; + newDict = doc ? doc->dict : NULL; + + if ((oldDict != NULL) && (oldDict != newDict)) { + if ((node->name != NULL) && + ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_ATTRIBUTE_NODE) || + (node->type == XML_PI_NODE) || + (node->type == XML_ENTITY_REF_NODE)) && + (xmlDictOwns(oldDict, node->name))) { if (newDict) - newValue = xmlDictLookup(newDict, oldValue, -1); + node->name = xmlDictLookup(newDict, node->name, -1); else - newValue = xmlStrdup(oldValue); + node->name = xmlStrdup(node->name); + if (node->name == NULL) + ret = -1; } + + if ((node->content != NULL) && + ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + (xmlDictOwns(oldDict, node->content))) { + node->content = xmlStrdup(node->content); + if (node->content == NULL) + ret = -1; + } + } + + switch (node->type) { + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr attr = (xmlAttrPtr) node; + + /* + * Handle IDs + * + * TODO: ID attributes should also be added to the new + * document, but it's not clear how to handle clashes. + */ + if (attr->atype == XML_ATTRIBUTE_ID) + xmlRemoveID(oldDoc, attr); + + break; + } + + case XML_ENTITY_REF_NODE: + /* + * Handle entity references + */ + node->children = NULL; + node->last = NULL; + node->content = NULL; + + if ((doc != NULL) && + ((doc->intSubset != NULL) || (doc->extSubset != NULL))) { + xmlEntityPtr ent; + + /* + * Assign new entity node if available + */ + ent = xmlGetDocEntity(doc, node->name); + if (ent != NULL) { + node->children = (xmlNodePtr) ent; + node->last = (xmlNodePtr) ent; + node->content = ent->content; + } + } + + break; + + case XML_DTD_NODE: + if (oldDoc != NULL) { + if (oldDoc->intSubset == (xmlDtdPtr) node) + oldDoc->intSubset = NULL; + if (oldDoc->extSubset == (xmlDtdPtr) node) + oldDoc->extSubset = NULL; + } + + break; + + case XML_ENTITY_DECL: + xmlRemoveEntity((xmlEntityPtr) node); + break; + + /* + * TODO: + * - Remove element decls from doc->elements + * - Remove attribtue decls form doc->attributes + */ + + default: + break; } - return newValue; + + /* + * Set new document + */ + node->doc = doc; + + return(ret); } /** * xmlSetTreeDoc: - * @tree: the top element - * @doc: the document + * @tree: root of a subtree + * @doc: new document + * + * This is an internal function which shouldn't be used. It is + * invoked by functions like xmlAddChild, xmlAddSibling or + * xmlReplaceNode. @tree must be the root node of an unlinked + * subtree. + * + * Associate all nodes in a tree with a new document. + * + * Also copy strings from the old document's dictionary and + * remove ID attributes from the old ID table. * - * update all nodes under the tree to point to the right document + * Returns 0 on success. If a memory allocation fails, returns -1. + * The whole tree will be updated on failure but some strings + * may be lost. */ -void +int xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { - xmlAttrPtr prop; + int ret = 0; if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) - return; - if (tree->doc != doc) { - xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL; - xmlDictPtr newDict = doc ? doc->dict : NULL; - - if(tree->type == XML_ELEMENT_NODE) { - prop = tree->properties; - while (prop != NULL) { - if (prop->atype == XML_ATTRIBUTE_ID) { - xmlRemoveID(tree->doc, prop); - } + return(0); + if (tree->doc == doc) + return(0); - if (prop->doc != doc) { - xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL; - prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name); - prop->doc = doc; - } - xmlSetListDoc(prop->children, doc); + if (tree->type == XML_ELEMENT_NODE) { + xmlAttrPtr prop = tree->properties; - /* - * TODO: ID attributes should be also added to the new - * document, but this breaks things like xmlReplaceNode. - * The underlying problem is that xmlRemoveID is only called - * if a node is destroyed, not if it's unlinked. - */ -#if 0 - if (xmlIsID(doc, tree, prop)) { - xmlChar *idVal = xmlNodeListGetString(doc, prop->children, - 1); - xmlAddID(NULL, doc, idVal, prop); - } -#endif + while (prop != NULL) { + if (prop->children != NULL) { + if (xmlSetListDoc(prop->children, doc) < 0) + ret = -1; + } - prop = prop->next; - } - } - if (tree->type == XML_ENTITY_REF_NODE) { - /* - * Clear 'children' which points to the entity declaration - * from the original document. - */ - tree->children = NULL; - } else if (tree->children != NULL) { - xmlSetListDoc(tree->children, doc); + if (xmlNodeSetDoc((xmlNodePtr) prop, doc) < 0) + ret = -1; + + prop = prop->next; } + } - tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name); - tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content); - /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */ - tree->doc = doc; + if ((tree->children != NULL) && + (tree->type != XML_ENTITY_REF_NODE)) { + if (xmlSetListDoc(tree->children, doc) < 0) + ret = -1; } + + if (xmlNodeSetDoc(tree, doc) < 0) + ret = -1; + + return(ret); } /** * xmlSetListDoc: - * @list: the first element - * @doc: the document + * @list: a node list + * @doc: new document + * + * Associate all subtrees in @list with a new document. * - * update all nodes in the list to point to the right document + * Internal function, see xmlSetTreeDoc. + * + * Returns 0 on success. If a memory allocation fails, returns -1. + * All subtrees will be updated on failure but some strings + * may be lost. */ -void +int xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { xmlNodePtr cur; + int ret = 0; if ((list == NULL) || (list->type == XML_NAMESPACE_DECL)) - return; - cur = list; + return(0); + + cur = list; while (cur != NULL) { - if (cur->doc != doc) - xmlSetTreeDoc(cur, doc); + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) + ret = -1; + } cur = cur->next; } + + return(ret); } #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** * xmlNewChild: * @parent: the parent node - * @ns: a namespace if any + * @ns: a namespace (optional) * @name: the name of the child - * @content: the XML content of the child if any. + * @content: text content with XML references (optional) + * + * Create a new child element and append it to a parent element. + * + * If @ns is NULL, the newly created element inherits the namespace + * of the parent. * - * Creation of a new child element, added at the end of @parent children list. - * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly - * created element inherits the namespace of @parent. If @content is non NULL, - * a child 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. + * If provided, @content is expected to be a valid XML attribute + * value possibly containing character and entity references. Text + * and entity reference node will be added to the child element, + * see xmlNewDocNode. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments + * are invalid or a memory allocation failed. */ xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev; - if (parent == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewChild : parent == NULL\n"); -#endif + if ((parent == NULL) || (name == NULL)) return(NULL); - } - if (name == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewChild : name == NULL\n"); -#endif - return(NULL); - } + switch (parent->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + break; - /* - * Allocate a new node - */ - if (parent->type == XML_ELEMENT_NODE) { - if (ns == NULL) - cur = xmlNewDocNode(parent->doc, parent->ns, name, content); - else - cur = xmlNewDocNode(parent->doc, ns, name, content); - } else if ((parent->type == XML_DOCUMENT_NODE) || - (parent->type == XML_HTML_DOCUMENT_NODE)) { - if (ns == NULL) - cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content); - else - cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content); - } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { - cur = xmlNewDocNode( parent->doc, ns, name, content); - } else { - return(NULL); + case XML_ELEMENT_NODE: + if (ns == NULL) + ns = parent->ns; + break; + + default: + return(NULL); } - if (cur == NULL) return(NULL); + + cur = xmlNewDocNode(parent->doc, ns, name, content); + if (cur == NULL) + return(NULL); /* * add the new element at the end of the children list. */ - cur->type = XML_ELEMENT_NODE; cur->parent = parent; - cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; @@ -3004,297 +2994,274 @@ xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, } #endif /* LIBXML_TREE_ENABLED */ -/** - * xmlAddPropSibling: - * @prev: the attribute to which @prop is added after - * @cur: the base attribute passed to calling function - * @prop: the new attribute - * - * Add a new attribute after @prev using @cur as base attribute. - * When inserting before @cur, @prev is passed as @cur->prev. - * When inserting after @cur, @prev is passed as @cur. - * If an existing attribute is found it is destroyed prior to adding @prop. - * - * See the note regarding namespaces in xmlAddChild. - * - * Returns the attribute being inserted or NULL in case of error. - */ +static void +xmlTextSetContent(xmlNodePtr text, xmlChar *content) { + if ((text->content != NULL) && + (text->content != (xmlChar *) &text->properties)) { + xmlDocPtr doc = text->doc; + + if ((doc == NULL) || + (doc->dict == NULL) || + (!xmlDictOwns(doc->dict, text->content))) + xmlFree(text->content); + } + + text->content = content; + text->properties = NULL; +} + +static int +xmlTextAddContent(xmlNodePtr text, const xmlChar *content, int len) { + xmlChar *merged; + + if (content == NULL) + return(0); + + merged = xmlStrncatNew(text->content, content, len); + if (merged == NULL) + return(-1); + + xmlTextSetContent(text, merged); + return(0); +} + static xmlNodePtr -xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { - xmlAttrPtr attr; +xmlInsertProp(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent, + xmlNodePtr prev, xmlNodePtr next) { + xmlAttrPtr attr; - if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) || - (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) || - ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE))) - return(NULL); + if (((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)) || + ((next != NULL) && (next->type != XML_ATTRIBUTE_NODE))) + return(NULL); - /* check if an attribute with the same name exists */ - if (prop->ns == NULL) - attr = xmlHasNsProp(cur->parent, prop->name, NULL); - else - attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href); + /* check if an attribute with the same name exists */ + attr = xmlGetPropNodeInternal(parent, cur->name, + cur->ns ? cur->ns->href : NULL, 0); - if (prop->doc != cur->doc) { - xmlSetTreeDoc(prop, cur->doc); - } - prop->parent = cur->parent; - prop->prev = prev; - if (prev != NULL) { - prop->next = prev->next; - prev->next = prop; - if (prop->next) - prop->next->prev = prop; - } else { - prop->next = cur; - cur->prev = prop; + xmlUnlinkNodeInternal(cur); + + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) + return(NULL); + } + + cur->parent = parent; + cur->prev = prev; + cur->next = next; + + if (prev == NULL) { + if (parent != NULL) + parent->properties = (xmlAttrPtr) cur; + } else { + prev->next = cur; + } + if (next != NULL) { + next->prev = cur; + } + + if ((attr != NULL) && (attr != (xmlAttrPtr) cur)) { + /* different instance, destroy it (attributes must be unique) */ + xmlRemoveProp((xmlAttrPtr) attr); + } + + return cur; +} + +static xmlNodePtr +xmlInsertNode(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent, + xmlNodePtr prev, xmlNodePtr next, int coalesce) { + xmlNodePtr oldParent; + + if (cur->type == XML_ATTRIBUTE_NODE) + return xmlInsertProp(doc, cur, parent, prev, next); + + /* + * Coalesce text nodes + */ + if ((coalesce) && (cur->type == XML_TEXT_NODE)) { + if ((prev != NULL) && (prev->type == XML_TEXT_NODE) && + (prev->name == cur->name)) { + if (xmlTextAddContent(prev, cur->content, -1) < 0) + return(NULL); + xmlUnlinkNodeInternal(cur); + xmlFreeNode(cur); + return(prev); } - if (prop->prev == NULL && prop->parent != NULL) - prop->parent->properties = (xmlAttrPtr) prop; - if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) { - /* different instance, destroy it (attributes must be unique) */ - xmlRemoveProp((xmlAttrPtr) attr); + + if ((next != NULL) && (next->type == XML_TEXT_NODE) && + (next->name == cur->name)) { + if (cur->content != NULL) { + xmlChar *merged; + + merged = xmlStrncatNew(cur->content, next->content, -1); + if (merged == NULL) + return(NULL); + xmlTextSetContent(next, merged); + } + + xmlUnlinkNodeInternal(cur); + xmlFreeNode(cur); + return(next); } - return prop; + } + + /* Unlink */ + oldParent = cur->parent; + if (oldParent != NULL) { + if (oldParent->children == cur) + oldParent->children = cur->next; + if (oldParent->last == cur) + oldParent->last = cur->prev; + } + if (cur->next != NULL) + cur->next->prev = cur->prev; + if (cur->prev != NULL) + cur->prev->next = cur->next; + + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) { + /* + * We shouldn't make any modifications to the inserted + * tree if a memory allocation fails, but that's hard to + * implement. The tree has been moved to the target + * document now but some contents are corrupted. + * Unlinking is the best we can do. + */ + cur->parent = NULL; + cur->prev = NULL; + cur->next = NULL; + return(NULL); + } + } + + cur->parent = parent; + cur->prev = prev; + cur->next = next; + + if (prev == NULL) { + if (parent != NULL) + parent->children = cur; + } else { + prev->next = cur; + } + if (next == NULL) { + if (parent != NULL) + parent->last = cur; + } else { + next->prev = cur; + } + + return(cur); } /** * xmlAddNextSibling: - * @cur: the child node - * @elem: the new node + * @prev: the target node + * @cur: the new node * - * Add a new node @elem as the next sibling of @cur - * If the new node was already inserted in a document it is - * first unlinked from its existing context. - * As a result of text merging @elem may be freed. - * If the new node is ATTRIBUTE, it is added into properties instead of children. - * If there is an attribute with equal name, it is first destroyed. + * Unlinks @cur and inserts it as next sibling after @prev. * - * See the note regarding namespaces in xmlAddChild. + * Unlike xmlAddChild this function does not merge text nodes. * - * Returns the new node or NULL in case of error. + * If @cur is an attribute node, it is inserted after attribute + * @prev. If the attribute list contains an attribute with a name + * matching @cur, the old attribute is destroyed. + * + * See the notes in xmlAddChild. + * + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAddNextSibling : cur == NULL\n"); -#endif - return(NULL); - } - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { -#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 +xmlAddNextSibling(xmlNodePtr prev, xmlNodePtr cur) { + if ((prev == NULL) || (prev->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == prev)) return(NULL); - } - xmlUnlinkNode(elem); - - if (elem->type == XML_TEXT_NODE) { - if (cur->type == XML_TEXT_NODE) { - xmlNodeAddContent(cur, elem->content); - xmlFreeNode(elem); - return(cur); - } - if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) && - (cur->name == cur->next->name)) { - xmlChar *tmp; - - tmp = xmlStrdup(elem->content); - tmp = xmlStrcat(tmp, cur->next->content); - xmlNodeSetContent(cur->next, tmp); - xmlFree(tmp); - xmlFreeNode(elem); - return(cur->next); - } - } else if (elem->type == XML_ATTRIBUTE_NODE) { - return xmlAddPropSibling(cur, cur, elem); - } + if (cur == prev->next) + return(cur); - if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - elem->parent = cur->parent; - elem->prev = cur; - elem->next = cur->next; - cur->next = elem; - if (elem->next != NULL) - elem->next->prev = elem; - if ((elem->parent != NULL) && (elem->parent->last == cur)) - elem->parent->last = elem; - return(elem); + return(xmlInsertNode(prev->doc, cur, prev->parent, prev, prev->next, 0)); } #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) /** * xmlAddPrevSibling: - * @cur: the child node - * @elem: the new node + * @next: the target node + * @cur: the new node + * + * Unlinks @cur and inserts it as previous sibling before @next. + * + * Unlike xmlAddChild this function does not merge text nodes. * - * 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. + * If @cur is an attribute node, it is inserted before attribute + * @next. If the attribute list contains an attribute with a name + * matching @cur, the old attribute is destroyed. * - * See the note regarding namespaces in xmlAddChild. + * See the notes in xmlAddChild. * - * Returns the new node or NULL in case of error. + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAddPrevSibling : cur == NULL\n"); -#endif - return(NULL); - } - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { -#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 +xmlAddPrevSibling(xmlNodePtr next, xmlNodePtr cur) { + if ((next == NULL) || (next->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == next)) 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 (cur == next->prev) + return(cur); - if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - elem->parent = cur->parent; - elem->next = cur; - elem->prev = cur->prev; - cur->prev = elem; - if (elem->prev != NULL) - elem->prev->next = elem; - if ((elem->parent != NULL) && (elem->parent->children == cur)) { - elem->parent->children = elem; - } - return(elem); + return(xmlInsertNode(next->doc, cur, next->parent, next->prev, next, 0)); } #endif /* LIBXML_TREE_ENABLED */ /** * xmlAddSibling: - * @cur: the child node - * @elem: the new node + * @node: the target node + * @cur: the new node + * + * Unlinks @cur and inserts it as last sibling of @node. + * + * If @cur is a text node, it may be merged with an adjacent text + * node and freed. In this case the text node containing the merged + * content is returned. * - * 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. + * If @cur is an attribute node, it is appended to the attribute + * list containing @node. If the attribute list contains an attribute + * with a name matching @cur, the old attribute is destroyed. * - * See the note regarding namespaces in xmlAddChild. + * See the notes in xmlAddChild. * - * Returns the new element or NULL in case of error. + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { - xmlNodePtr parent; - - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAddSibling : cur == NULL\n"); -#endif - return(NULL); - } - - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { -#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 +xmlAddSibling(xmlNodePtr node, xmlNodePtr cur) { + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == node)) return(NULL); - } /* * Constant time is we can rely on the ->parent->last to find * the last sibling. */ - if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) && - (cur->parent->children != NULL) && - (cur->parent->last != NULL) && - (cur->parent->last->next == NULL)) { - cur = cur->parent->last; + if ((node->type != XML_ATTRIBUTE_NODE) && (node->parent != NULL)) { + if (node->parent->last != NULL) + node = node->parent->last; } else { - while (cur->next != NULL) cur = cur->next; - } - - xmlUnlinkNode(elem); - - if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) && - (cur->name == elem->name)) { - xmlNodeAddContent(cur, elem->content); - xmlFreeNode(elem); - return(cur); - } else if (elem->type == XML_ATTRIBUTE_NODE) { - return xmlAddPropSibling(cur, cur, elem); + while (node->next != NULL) + node = node->next; } - if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - parent = cur->parent; - elem->prev = cur; - elem->next = NULL; - elem->parent = parent; - cur->next = elem; - if (parent != NULL) - parent->last = elem; + if (cur == node) + return(cur); - return(elem); + return(xmlInsertNode(node->doc, cur, node->parent, node, NULL, 1)); } /** @@ -3302,40 +3269,35 @@ xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { * @parent: the parent node * @cur: the first node in the list * - * Add a list of node at the end of the child list of the parent - * merging adjacent TEXT nodes (@cur may be freed) + * Append a node list to another node. * - * See the note regarding namespaces in xmlAddChild. + * See xmlAddChild. * * Returns the last child or NULL in case of error. */ xmlNodePtr xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { + xmlNodePtr iter; xmlNodePtr prev; + int oom; if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAddChildList : parent == NULL\n"); -#endif return(NULL); } if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { -#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 + oom = 0; + for (iter = cur; iter != NULL; iter = iter->next) { + if (iter->doc != parent->doc) { + if (xmlSetTreeDoc(iter, parent->doc) < 0) + oom = 1; + } } + if (oom) + return(NULL); /* * add the first element at the end of the children list. @@ -3344,40 +3306,36 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { if (parent->children == NULL) { parent->children = cur; } else { + prev = parent->last; + /* * If cur and parent->last both are TEXT nodes, then merge them. */ if ((cur->type == XML_TEXT_NODE) && - (parent->last->type == XML_TEXT_NODE) && - (cur->name == parent->last->name)) { - xmlNodeAddContent(parent->last, cur->content); + (prev->type == XML_TEXT_NODE) && + (cur->name == prev->name)) { + xmlNodePtr next; + + if (xmlTextAddContent(prev, cur->content, -1) < 0) + return(NULL); + next = cur->next; + xmlFreeNode(cur); /* * if it's the only child, nothing more to be done. */ - if (cur->next == NULL) { - xmlFreeNode(cur); - return(parent->last); - } - prev = cur; - cur = cur->next; - xmlFreeNode(prev); + if (next == NULL) + return(prev); + cur = next; } - prev = parent->last; + prev->next = cur; cur->prev = prev; } while (cur->next != NULL) { cur->parent = parent; - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); - } cur = cur->next; } cur->parent = parent; - /* the parent may not be linked to a doc ! */ - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); - } parent->last = cur; return(cur); @@ -3388,150 +3346,91 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { * @parent: the parent node * @cur: the child node * - * Add a new node to @parent, at the end of the child (or property) list - * merging adjacent TEXT nodes (in which case @cur is freed) - * If the new node is ATTRIBUTE, it is added into properties instead of children. - * If there is an attribute with equal name, it is first destroyed. + * Unlink @cur and append it to the children of @parent. + * + * If @cur is a text node, it may be merged with an adjacent text + * node and freed. In this case the text node containing the merged + * content is returned. + * + * If @cur is an attribute node, it is appended to the attributes of + * @parent. If the attribute list contains an attribute with a name + * matching @elem, the old attribute is destroyed. + * + * General notes: + * + * Move operations like xmlAddChild can cause element or attribute + * nodes to reference namespaces that aren't declared in one of + * their ancestors. This can lead to use-after-free errors if the + * elements containing the declarations are freed later, especially + * when moving nodes from one document to another. You should + * consider calling xmlReconciliateNs after a move operation to + * normalize namespaces. Another option is to call + * xmlDOMWrapAdoptNode with the target parent before moving a node. * - * All tree manipulation functions can safely move nodes within a document. - * But when moving nodes from one document to another, references to - * namespaces in element or attribute nodes are NOT fixed. In this case, - * you MUST call xmlReconciliateNs after the move operation to avoid - * memory errors. + * For the most part, move operations don't check whether the + * resulting tree structure is valid. Users must make sure that + * parent nodes only receive children of valid types. Inserted + * child nodes must never be an ancestor of the parent node to + * avoid cycles in the tree structure. In general, only + * document, document fragments, elements and attributes + * should be used as parent nodes. * - * Returns the child or NULL in case of error. + * When moving a node between documents and a memory allocation + * fails, the node's content will be corrupted and it will be + * unlinked. In this case, the node must be freed manually. + * + * Moving DTDs between documents isn't supported. + * + * Returns @elem or a sibling if @elem was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { xmlNodePtr prev; - if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAddChild : parent == NULL\n"); -#endif - return(NULL); - } - - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { -#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); - } - } + if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (parent == cur)) + return(NULL); /* - * add the new element at the end of the children list. + * If parent is a text node, call xmlTextAddContent. This + * undocumented quirk should probably be removed. */ - prev = cur->parent; - cur->parent = parent; - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); + if (parent->type == XML_TEXT_NODE) { + if (xmlTextAddContent(parent, cur->content, -1) < 0) + return(NULL); + xmlFreeNode(cur); + return(parent); } - /* this check prevents a loop on tree-traversions if a developer - * tries to add a node to its parent multiple times - */ - if (prev == parent) - return(cur); - /* - * Coalescing - */ - if ((parent->type == XML_TEXT_NODE) && - (parent->content != NULL) && - (parent != cur)) { - xmlNodeAddContent(parent, cur->content); - xmlFreeNode(cur); - return(parent); - } if (cur->type == XML_ATTRIBUTE_NODE) { - if (parent->type != XML_ELEMENT_NODE) - return(NULL); - if (parent->properties != NULL) { - /* check if an attribute with the same name exists */ - xmlAttrPtr lastattr; - - if (cur->ns == NULL) - lastattr = xmlHasNsProp(parent, cur->name, NULL); - else - lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href); - if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) { - /* different instance, destroy it (attributes must be unique) */ - xmlUnlinkNode((xmlNodePtr) lastattr); - xmlFreeProp(lastattr); - } - if (lastattr == (xmlAttrPtr) cur) - return(cur); - - } - if (parent->properties == NULL) { - parent->properties = (xmlAttrPtr) cur; - } else { - /* find the end */ - xmlAttrPtr lastattr = parent->properties; - while (lastattr->next != NULL) { - lastattr = lastattr->next; - } - lastattr->next = (xmlAttrPtr) cur; - ((xmlAttrPtr) cur)->prev = lastattr; - } + prev = (xmlNodePtr) parent->properties; + if (prev != NULL) { + while (prev->next != NULL) + prev = prev->next; + } } else { - if (parent->children == NULL) { - parent->children = cur; - parent->last = cur; - } else { - prev = parent->last; - prev->next = cur; - cur->prev = prev; - parent->last = cur; - } + prev = parent->last; } - return(cur); + + if (cur == prev) + return(cur); + + return(xmlInsertNode(parent->doc, cur, parent, prev, NULL, 1)); } /** * xmlGetLastChild: * @parent: the parent node * - * Search the last child of a node. - * Returns the last child or NULL if none. + * Find the last child of a node. + * + * Returns the last child or NULL if parent has no children. */ xmlNodePtr xmlGetLastChild(const xmlNode *parent) { if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlGetLastChild : parent == NULL\n"); -#endif return(NULL); } return(parent->last); @@ -3546,13 +3445,12 @@ xmlGetLastChild(const xmlNode *parent) { * xmlChildElementCount: * @parent: the parent node * - * Finds the current number of child nodes of that element which are - * element nodes. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Count the number of child nodes which are elements. * - * Returns the count of element child or 0 if not available + * Note that entity references are not expanded. + * + * Returns the number of element children or 0 if arguments are + * invalid. */ unsigned long xmlChildElementCount(xmlNodePtr parent) { @@ -3563,10 +3461,10 @@ xmlChildElementCount(xmlNodePtr parent) { return(0); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->children; break; default: @@ -3584,12 +3482,11 @@ xmlChildElementCount(xmlNodePtr parent) { * xmlFirstElementChild: * @parent: the parent node * - * Finds the first child node of that element which is a Element node - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the first child node which is an element. * - * Returns the first element child or NULL if not available + * Note that entity references are not expanded. + * + * Returns the first element or NULL if parent has no children. */ xmlNodePtr xmlFirstElementChild(xmlNodePtr parent) { @@ -3599,10 +3496,10 @@ xmlFirstElementChild(xmlNodePtr parent) { return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->children; break; default: @@ -3620,12 +3517,11 @@ xmlFirstElementChild(xmlNodePtr parent) { * xmlLastElementChild: * @parent: the parent node * - * Finds the last child node of that element which is a Element node - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the last child node which is an element. * - * Returns the last element child or NULL if not available + * Note that entity references are not expanded. + * + * Returns the last element or NULL if parent has no children. */ xmlNodePtr xmlLastElementChild(xmlNodePtr parent) { @@ -3635,10 +3531,10 @@ xmlLastElementChild(xmlNodePtr parent) { return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->last; break; default: @@ -3656,13 +3552,11 @@ xmlLastElementChild(xmlNodePtr parent) { * xmlPreviousElementSibling: * @node: the current node * - * Finds the first closest previous sibling of the node which is an - * element node. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the closest preceding sibling which is a element. * - * Returns the previous element sibling or NULL if not available + * Note that entity references are not expanded. + * + * Returns the sibling or NULL if no sibling was found. */ xmlNodePtr xmlPreviousElementSibling(xmlNodePtr node) { @@ -3673,7 +3567,6 @@ xmlPreviousElementSibling(xmlNodePtr node) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: @@ -3695,13 +3588,11 @@ xmlPreviousElementSibling(xmlNodePtr node) { * xmlNextElementSibling: * @node: the current node * - * Finds the first closest next sibling of the node which is an - * element node. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the closest following sibling which is a element. + * + * Note that entity references are not expanded. * - * Returns the next element sibling or NULL if not available + * Returns the sibling or NULL if no sibling was found. */ xmlNodePtr xmlNextElementSibling(xmlNodePtr node) { @@ -3712,7 +3603,6 @@ xmlNextElementSibling(xmlNodePtr node) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DTD_NODE: @@ -3737,8 +3627,7 @@ xmlNextElementSibling(xmlNodePtr node) { * xmlFreeNodeList: * @cur: the first node in the list * - * Free a node and all its siblings, this is a recursive behaviour, all - * the children are freed too. + * Free a node list including all children. */ void xmlFreeNodeList(xmlNodePtr cur) { @@ -3768,8 +3657,14 @@ xmlFreeNodeList(xmlNodePtr cur) { if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { xmlFreeDoc((xmlDocPtr) cur); - } else if (cur->type != XML_DTD_NODE) { - + } else if (cur->type == XML_DTD_NODE) { + /* + * TODO: We should consider freeing the DTD if it isn't + * referenced from doc->intSubset or doc->extSubset. + */ + cur->prev = NULL; + cur->next = NULL; + } else { if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur); @@ -3820,8 +3715,10 @@ xmlFreeNodeList(xmlNodePtr cur) { * xmlFreeNode: * @cur: the node * - * Free a node, this is a recursive behaviour, all the children are freed too. - * This doesn't unlink the child from the list, use xmlUnlinkNode() first. + * Free a node including all the children. + * + * This doesn't unlink the node from the tree. Call xmlUnlinkNode first + * unless @cur is a root node. */ void xmlFreeNode(xmlNodePtr cur) { @@ -3842,17 +3739,16 @@ xmlFreeNode(xmlNodePtr cur) { xmlFreeProp((xmlAttrPtr) cur); return; } + if (cur->type == XML_ENTITY_DECL) { + xmlFreeEntity((xmlEntityPtr) cur); + return; + } if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur); if (cur->doc != NULL) dict = cur->doc->dict; - if (cur->type == XML_ENTITY_DECL) { - xmlEntityPtr ent = (xmlEntityPtr) cur; - DICT_FREE(ent->SystemID); - DICT_FREE(ent->ExternalID); - } if ((cur->children != NULL) && (cur->type != XML_ENTITY_REF_NODE)) xmlFreeNodeList(cur->children); @@ -3884,58 +3780,16 @@ xmlFreeNode(xmlNodePtr cur) { } /** - * xmlUnlinkNode: + * xmlUnlinkNodeInternal: * @cur: the node * - * Unlink a node from it's current context, the node is not freed - * If one need to free the node, use xmlFreeNode() routine after the - * unlink to discard it. - * Note that namespace nodes can't be unlinked as they do not have - * pointer to their parent. + * Unlink a node from its tree. + * + * This function only unlinks the node from the tree. It doesn't + * clear references to DTD nodes. */ -void -xmlUnlinkNode(xmlNodePtr cur) { - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlUnlinkNode : node == NULL\n"); -#endif - return; - } - if (cur->type == XML_NAMESPACE_DECL) - return; - if (cur->type == XML_DTD_NODE) { - xmlDocPtr doc; - doc = cur->doc; - if (doc != NULL) { - if (doc->intSubset == (xmlDtdPtr) cur) - doc->intSubset = NULL; - if (doc->extSubset == (xmlDtdPtr) cur) - doc->extSubset = NULL; - } - } - if (cur->type == XML_ENTITY_DECL) { - xmlDocPtr doc; - doc = cur->doc; - if (doc != NULL) { - if (doc->intSubset != NULL) { - if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) - xmlHashRemoveEntry(doc->intSubset->entities, cur->name, - NULL); - if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) - xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, - NULL); - } - if (doc->extSubset != NULL) { - if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) - xmlHashRemoveEntry(doc->extSubset->entities, cur->name, - NULL); - if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) - xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, - NULL); - } - } - } +static void +xmlUnlinkNodeInternal(xmlNodePtr cur) { if (cur->parent != NULL) { xmlNodePtr parent; parent = cur->parent; @@ -3950,61 +3804,89 @@ xmlUnlinkNode(xmlNodePtr cur) { } cur->parent = NULL; } + if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; - cur->next = cur->prev = NULL; + cur->next = NULL; + cur->prev = NULL; +} + +/** + * xmlUnlinkNode: + * @cur: the node + * + * Unlink a node from its tree. + * + * The node is not freed. Unless it is reinserted, it must be managed + * manually and freed eventually by calling xmlFreeNode. + */ +void +xmlUnlinkNode(xmlNodePtr cur) { + if (cur == NULL) + return; + + if (cur->type == XML_NAMESPACE_DECL) + return; + + if (cur->type == XML_DTD_NODE) { + xmlDocPtr doc = cur->doc; + + if (doc != NULL) { + if (doc->intSubset == (xmlDtdPtr) cur) + doc->intSubset = NULL; + if (doc->extSubset == (xmlDtdPtr) cur) + doc->extSubset = NULL; + } + } + + if (cur->type == XML_ENTITY_DECL) + xmlRemoveEntity((xmlEntityPtr) cur); + + xmlUnlinkNodeInternal(cur); } #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) /** * xmlReplaceNode: * @old: the old node - * @cur: the node + * @cur: the node (optional) * - * Unlink the old node 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. + * Unlink the old node. If @cur is provided, it is unlinked and + * inserted in place of @old. * - * See the note regarding namespaces in xmlAddChild. + * It is an error if @old has no parent. * - * Returns the @old node + * Unlike xmlAddChild, this function doesn't merge text nodes or + * delete duplicate attributes. + * + * See the notes in xmlAddChild. + * + * Returns @old or NULL if arguments are invalid or a memory + * allocation failed. */ xmlNodePtr xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { if (old == cur) return(NULL); if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) || (old->parent == NULL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlReplaceNode : old == NULL or without parent\n"); -#endif return(NULL); } if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { + /* Don't call xmlUnlinkNodeInternal to handle DTDs. */ xmlUnlinkNode(old); return(old); } - if (cur == old) { - return(old); - } if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { -#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); + xmlUnlinkNodeInternal(cur); + if (xmlSetTreeDoc(cur, old->doc) < 0) + return(NULL); cur->parent = old->parent; cur->next = old->next; if (cur->next != NULL) @@ -4039,9 +3921,10 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { * xmlCopyNamespace: * @cur: the namespace * - * Do a copy of the namespace. + * Copy a namespace. * - * Returns: a new #xmlNsPtr, or NULL in case of error. + * Returns the copied namespace or NULL if a memory allocation + * failed. */ xmlNsPtr xmlCopyNamespace(xmlNsPtr cur) { @@ -4053,10 +3936,6 @@ xmlCopyNamespace(xmlNsPtr cur) { 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); @@ -4066,9 +3945,10 @@ xmlCopyNamespace(xmlNsPtr cur) { * xmlCopyNamespaceList: * @cur: the first namespace * - * Do a copy of an namespace list. + * Copy a namespace list. * - * Returns: a new #xmlNsPtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNsPtr xmlCopyNamespaceList(xmlNsPtr cur) { @@ -4077,6 +3957,10 @@ xmlCopyNamespaceList(xmlNsPtr cur) { while (cur != NULL) { q = xmlCopyNamespace(cur); + if (q == NULL) { + xmlFreeNsList(ret); + return(NULL); + } if (p == NULL) { ret = p = q; } else { @@ -4088,12 +3972,9 @@ xmlCopyNamespaceList(xmlNsPtr cur) { return(ret); } -static xmlNodePtr -xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); - static xmlAttrPtr xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { - xmlAttrPtr ret; + xmlAttrPtr ret = NULL; if (cur == NULL) return(NULL); if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) @@ -4113,15 +3994,20 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { if ((cur->ns != NULL) && (target != NULL)) { xmlNsPtr ns; + int res; - ns = xmlSearchNs(target->doc, target, cur->ns->prefix); + res = xmlSearchNsSafe(target, cur->ns->prefix, &ns); + if (res < 0) + goto error; if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined * out of the new tree scope. Search it in the original tree * and add it at the top of the new tree */ - ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); + res = xmlSearchNsSafe(cur->parent, cur->ns->prefix, &ns); + if (res < 0) + goto error; if (ns != NULL) { xmlNodePtr root = target; xmlNodePtr pred = NULL; @@ -4135,6 +4021,8 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { root = pred; } ret->ns = xmlNewNs(root, ns->href, ns->prefix); + if (ret->ns == NULL) + goto error; } } else { /* @@ -4150,7 +4038,9 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { * we are in trouble: we need a new reconciled namespace. * This is expensive */ - ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns); + ret->ns = xmlNewReconciledNs(target, cur->ns); + if (ret->ns == NULL) + goto error; } } @@ -4161,6 +4051,8 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { xmlNodePtr tmp; ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); + if (ret->children == NULL) + goto error; ret->last = NULL; tmp = ret->children; while (tmp != NULL) { @@ -4173,20 +4065,31 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { /* * Try to handle IDs */ - if ((target!= NULL) && (cur!= NULL) && + if ((target != NULL) && (cur != NULL) && (target->doc != NULL) && (cur->doc != NULL) && - (cur->doc->ids != NULL) && (cur->parent != NULL)) { - if (xmlIsID(cur->doc, cur->parent, cur)) { + (cur->parent != NULL) && + (cur->children != NULL)) { + int res = xmlIsID(cur->doc, cur->parent, cur); + + if (res < 0) + goto error; + if (res != 0) { xmlChar *id; - id = xmlNodeListGetString(cur->doc, cur->children, 1); - if (id != NULL) { - xmlAddID(NULL, target->doc, id, ret); - xmlFree(id); - } + id = xmlNodeGetContent((xmlNodePtr) cur); + if (id == NULL) + goto error; + res = xmlAddIDSafe(ret, id); + xmlFree(id); + if (res < 0) + goto error; } } return(ret); + +error: + xmlFreeProp(ret); + return(NULL); } /** @@ -4194,9 +4097,14 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { * @target: the element where the attribute will be grafted * @cur: the attribute * - * Do a copy of the attribute. + * Create a copy of the attribute. This function sets the parent + * pointer of the copy to @target but doesn't set the attribute on + * the target element. Users should consider to set the attribute + * by calling xmlAddChild afterwards or reset the parent pointer to + * NULL. * - * Returns: a new #xmlAttrPtr, or NULL in case of error. + * Returns the copied attribute or NULL if a memory allocation + * failed. */ xmlAttrPtr xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { @@ -4208,9 +4116,12 @@ xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { * @target: the element where the attributes will be grafted * @cur: the first attribute * - * Do a copy of an attribute list. + * Create a copy of an attribute list. This function sets the + * parent pointers of the copied attributes to @target but doesn't + * set the attributes on the target element. * - * Returns: a new #xmlAttrPtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlAttrPtr xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { @@ -4221,8 +4132,10 @@ xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { return(NULL); while (cur != NULL) { q = xmlCopyProp(target, cur); - if (q == NULL) + if (q == NULL) { + xmlFreePropList(ret); return(NULL); + } if (p == NULL) { ret = p = q; } else { @@ -4254,7 +4167,18 @@ xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { * namespace info, but don't recurse on children. */ -static xmlNodePtr +/** + * xmlStaticCopyNode: + * @node: source node + * @doc: target document + * @parent: target parent + * @extended: flags + * + * Copy a node. + * + * Returns the copy or NULL if a memory allocation failed. + */ +xmlNodePtr xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, int extended) { xmlNodePtr ret; @@ -4266,7 +4190,6 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, case XML_ELEMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: @@ -4282,12 +4205,7 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, #ifdef LIBXML_TREE_ENABLED return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended)); #endif /* LIBXML_TREE_ENABLED */ - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: + default: return(NULL); } @@ -4295,10 +4213,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, * Allocate a new node and fill the fields. */ ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (ret == NULL) { - xmlTreeErrMemory("copying node"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlNode)); ret->type = node->type; @@ -4315,6 +4231,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, ret->name = xmlDictLookup(doc->dict, node->name, -1); else ret->name = xmlStrdup(node->name); + if (ret->name == NULL) + goto error; } if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL) && @@ -4322,60 +4240,51 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, (node->type != XML_XINCLUDE_END) && (node->type != XML_XINCLUDE_START)) { ret->content = xmlStrdup(node->content); + if (ret->content == NULL) + goto error; }else{ if (node->type == XML_ELEMENT_NODE) ret->line = node->line; } - if (parent != NULL) { - xmlNodePtr tmp; - - /* - * this is a tricky part for the node register thing: - * in case ret does get coalesced in xmlAddChild - * the deregister-node callback is called; so we register ret now already - */ - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue((xmlNodePtr)ret); - - /* - * Note that since ret->parent is already set, xmlAddChild will - * return early and not actually insert the node. It will only - * coalesce text nodes and unnecessarily call xmlSetTreeDoc. - * Assuming that the subtree to be copied always has its text - * nodes coalesced, the somewhat confusing call to xmlAddChild - * could be removed. - */ - tmp = xmlAddChild(parent, ret); - /* node could have coalesced */ - if (tmp != ret) - return(tmp); - } if (!extended) goto out; if (((node->type == XML_ELEMENT_NODE) || - (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) + (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) { ret->nsDef = xmlCopyNamespaceList(node->nsDef); + if (ret->nsDef == NULL) + goto error; + } - if (node->ns != NULL) { - xmlNsPtr ns; + if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) { + xmlNsPtr ns = NULL; + int res; - ns = xmlSearchNs(doc, ret, node->ns->prefix); + res = xmlSearchNsSafe(ret, node->ns->prefix, &ns); + if (res < 0) + goto error; if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined * out of the new tree scope. Search it in the original tree - * and add it at the top of the new tree + * and add it at the top of the new tree. + * + * TODO: Searching the original tree seems unnecessary. We + * already have a namespace URI. */ - ns = xmlSearchNs(node->doc, node, node->ns->prefix); + res = xmlSearchNsSafe(node, node->ns->prefix, &ns); + if (res < 0) + goto error; if (ns != NULL) { xmlNodePtr root = ret; while (root->parent != NULL) root = root->parent; ret->ns = xmlNewNs(root, ns->href, ns->prefix); - } else { - ret->ns = xmlNewReconciledNs(doc, ret, node->ns); + } else { + ret->ns = xmlNewReconciledNs(ret, node->ns); } + if (ret->ns == NULL) + goto error; } else { /* * reference the existing namespace definition in our own tree. @@ -4383,9 +4292,11 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, ret->ns = ns; } } - if (((node->type == XML_ELEMENT_NODE) || - (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) + if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) { ret->properties = xmlCopyPropList(ret, node->properties); + if (ret->properties == NULL) + goto error; + } if (node->type == XML_ENTITY_REF_NODE) { if ((doc == NULL) || (node->doc != doc)) { /* @@ -4406,10 +4317,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, insert = ret; while (cur != NULL) { xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2); - if (copy == NULL) { - xmlFreeNode(ret); - return(NULL); - } + if (copy == NULL) + goto error; /* Check for coalesced text nodes */ if (insert->last != copy) { @@ -4446,40 +4355,78 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, } out: - /* if parent != NULL we already registered the node above */ - if ((parent == NULL) && - ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)ret); return(ret); + +error: + xmlFreeNode(ret); + return(NULL); } -static xmlNodePtr +/** + * xmlStaticCopyNodeList: + * @node: node to copy + * @doc: target document + * @parent: target node (optional) + * + * Copy a node list. If @parent is provided, sets the parent pointer + * of the copied nodes, but doesn't update the children and last + * pointer of @parent. + * + * Returns a the copy or NULL in case of error. + */ +xmlNodePtr xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { xmlNodePtr ret = NULL; xmlNodePtr p = NULL,q; + xmlDtdPtr newSubset = NULL; + int linkedSubset = 0; while (node != NULL) { + xmlNodePtr next = node->next; + #ifdef LIBXML_TREE_ENABLED if (node->type == XML_DTD_NODE ) { if (doc == NULL) { - node = node->next; + node = next; continue; } - if (doc->intSubset == NULL) { + if ((doc->intSubset == NULL) && (newSubset == NULL)) { q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); - if (q == NULL) return(NULL); - q->doc = doc; + if (q == NULL) goto error; + /* Can't fail on DTD */ + xmlSetTreeDoc(q, doc); q->parent = parent; - doc->intSubset = (xmlDtdPtr) q; - xmlAddChild(parent, q); + newSubset = (xmlDtdPtr) q; } else { + /* + * We don't allow multiple internal subsets in a document, + * so we move the DTD instead of creating a copy. + */ + linkedSubset = 1; q = (xmlNodePtr) doc->intSubset; - xmlAddChild(parent, q); + /* Unlink */ + if (q->prev == NULL) { + if (q->parent != NULL) + q->parent->children = q->next; + } else { + q->prev->next = q->next; + } + if (q->next == NULL) { + if (q->parent != NULL) + q->parent->last = q->prev; + } else { + q->next->prev = q->prev; + } + q->parent = parent; + q->next = NULL; + q->prev = NULL; } } else #endif /* LIBXML_TREE_ENABLED */ q = xmlStaticCopyNode(node, doc, parent, 1); - if (q == NULL) return(NULL); + if (q == NULL) goto error; if (ret == NULL) { q->prev = NULL; ret = p = q; @@ -4489,9 +4436,20 @@ xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { q->prev = p; p = q; } - node = node->next; + node = next; } + if ((doc != NULL) && (newSubset != NULL)) + doc->intSubset = newSubset; return(ret); +error: + xmlFreeNodeList(ret); + if (newSubset != NULL) + xmlFreeDtd(newSubset); + if (linkedSubset != 0) { + doc->intSubset->next = NULL; + doc->intSubset->prev = NULL; + } + return(NULL); } /** @@ -4501,9 +4459,11 @@ xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { * when applicable) * if 2 copy properties and namespaces (when applicable) * - * Do a copy of the node. + * Copy a node. + * + * Use of this function is DISCOURAGED in favor of xmlDocCopyNode. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the copied node or NULL if a memory allocation failed. */ xmlNodePtr xmlCopyNode(xmlNodePtr node, int extended) { @@ -4521,9 +4481,9 @@ xmlCopyNode(xmlNodePtr node, int extended) { * when applicable) * if 2 copy properties and namespaces (when applicable) * - * Do a copy of the node to a given document. + * Copy a node into another document. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the copied node or NULL if a memory allocation failed. */ xmlNodePtr xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { @@ -4538,9 +4498,10 @@ xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { * @doc: the target document * @node: the first node in the list. * - * Do a recursive copy of the node list. + * Copy a node list and all children into a new document. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); @@ -4551,10 +4512,12 @@ xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { * xmlCopyNodeList: * @node: the first node in the list. * - * Do a recursive copy of the node list. - * Use xmlDocCopyNodeList() if possible to ensure string interning. + * Copy a node list and all children. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Use of this function is DISCOURAGED in favor of xmlDocCopyNodeList. + * + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); @@ -4564,11 +4527,11 @@ xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { #if defined(LIBXML_TREE_ENABLED) /** * xmlCopyDtd: - * @dtd: the dtd + * @dtd: the DTD * - * Do a copy of the dtd. + * Copy a DTD. * - * Returns: a new #xmlDtdPtr, or NULL in case of error. + * Returns the copied DTD or NULL if a memory allocation failed. */ xmlDtdPtr xmlCopyDtd(xmlDtdPtr dtd) { @@ -4578,21 +4541,36 @@ xmlCopyDtd(xmlDtdPtr dtd) { if (dtd == NULL) return(NULL); ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); if (ret == NULL) return(NULL); - if (dtd->entities != NULL) + if (dtd->entities != NULL) { ret->entities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->entities); - if (dtd->notations != NULL) + if (ret->entities == NULL) + goto error; + } + if (dtd->notations != NULL) { ret->notations = (void *) xmlCopyNotationTable( (xmlNotationTablePtr) dtd->notations); - if (dtd->elements != NULL) + if (ret->notations == NULL) + goto error; + } + if (dtd->elements != NULL) { ret->elements = (void *) xmlCopyElementTable( (xmlElementTablePtr) dtd->elements); - if (dtd->attributes != NULL) + if (ret->elements == NULL) + goto error; + } + if (dtd->attributes != NULL) { ret->attributes = (void *) xmlCopyAttributeTable( (xmlAttributeTablePtr) dtd->attributes); - if (dtd->pentities != NULL) + if (ret->attributes == NULL) + goto error; + } + if (dtd->pentities != NULL) { ret->pentities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->pentities); + if (ret->pentities == NULL) + goto error; + } cur = dtd->children; while (cur != NULL) { @@ -4624,6 +4602,8 @@ xmlCopyDtd(xmlDtdPtr dtd) { xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); } else if (cur->type == XML_COMMENT_NODE) { q = xmlCopyNode(cur, 0); + if (q == NULL) + goto error; } if (q == NULL) { @@ -4645,6 +4625,10 @@ xmlCopyDtd(xmlDtdPtr dtd) { } return(ret); + +error: + xmlFreeDtd(ret); + return(NULL); } #endif @@ -4654,10 +4638,11 @@ xmlCopyDtd(xmlDtdPtr dtd) { * @doc: the document * @recursive: if not zero do a recursive copy. * - * Do a copy of the document info. If recursive, the content tree will + * Copy a document. If recursive, the content tree will * be copied too as well as DTD, namespaces and entities. * - * Returns: a new #xmlDocPtr, or NULL in case of error. + * Returns the copied document or NULL if a memory allocation + * failed. */ xmlDocPtr xmlCopyDoc(xmlDocPtr doc, int recursive) { @@ -4667,12 +4652,21 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { ret = xmlNewDoc(doc->version); if (ret == NULL) return(NULL); ret->type = doc->type; - if (doc->name != NULL) + if (doc->name != NULL) { ret->name = xmlMemStrdup(doc->name); - if (doc->encoding != NULL) + if (ret->name == NULL) + goto error; + } + if (doc->encoding != NULL) { ret->encoding = xmlStrdup(doc->encoding); - if (doc->URL != NULL) + if (ret->encoding == NULL) + goto error; + } + if (doc->URL != NULL) { ret->URL = xmlStrdup(doc->URL); + if (ret->URL == NULL) + goto error; + } ret->charset = doc->charset; ret->compression = doc->compression; ret->standalone = doc->standalone; @@ -4683,21 +4677,24 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { #ifdef LIBXML_TREE_ENABLED if (doc->intSubset != NULL) { ret->intSubset = xmlCopyDtd(doc->intSubset); - if (ret->intSubset == NULL) { - xmlFreeDoc(ret); - return(NULL); - } + if (ret->intSubset == NULL) + goto error; + /* Can't fail on DTD */ xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); - ret->intSubset->parent = ret; } #endif - if (doc->oldNs != NULL) + if (doc->oldNs != NULL) { ret->oldNs = xmlCopyNamespaceList(doc->oldNs); + if (ret->oldNs == NULL) + goto error; + } if (doc->children != NULL) { xmlNodePtr tmp; ret->children = xmlStaticCopyNodeList(doc->children, ret, (xmlNodePtr)ret); + if (ret->children == NULL) + goto error; ret->last = NULL; tmp = ret->children; while (tmp != NULL) { @@ -4707,6 +4704,10 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { } } return(ret); + +error: + xmlFreeDoc(ret); + return(NULL); } #endif /* LIBXML_TREE_ENABLED */ @@ -4808,14 +4809,11 @@ xmlGetNodePath(const xmlNode *node) return (NULL); buf_len = 500; - buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); - if (buffer == NULL) { - xmlTreeErrMemory("getting node path"); + buffer = (xmlChar *) xmlMallocAtomic(buf_len); + if (buffer == NULL) return (NULL); - } - buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); + buf = (xmlChar *) xmlMallocAtomic(buf_len); if (buf == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buffer); return (NULL); } @@ -5002,7 +5000,6 @@ xmlGetNodePath(const xmlNode *node) 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; temp = (xmlChar *) xmlRealloc(buffer, buf_len); if (temp == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); @@ -5010,7 +5007,6 @@ xmlGetNodePath(const xmlNode *node) buffer = temp; temp = (xmlChar *) xmlRealloc(buf, buf_len); if (temp == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); @@ -5038,7 +5034,7 @@ xmlGetNodePath(const xmlNode *node) * Get the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * - * Returns the #xmlNodePtr for the root or NULL + * Returns the root element or NULL if no element was found. */ xmlNodePtr xmlDocGetRootElement(const xmlDoc *doc) { @@ -5064,7 +5060,10 @@ xmlDocGetRootElement(const xmlDoc *doc) { * Set the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * - * Returns the old root element if any was found, NULL if root was NULL + * @root must be an element node. It is unlinked before insertion. + * + * Returns the unlinked old root element or NULL if the document + * didn't have a root element or a memory allocation failed. */ xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { @@ -5073,15 +5072,18 @@ xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { if (doc == NULL) return(NULL); if ((root == NULL) || (root->type == XML_NAMESPACE_DECL)) return(NULL); - xmlUnlinkNode(root); - xmlSetTreeDoc(root, doc); - root->parent = (xmlNodePtr) doc; old = doc->children; while (old != NULL) { if (old->type == XML_ELEMENT_NODE) break; old = old->next; } + if (old == root) + return(old); + xmlUnlinkNodeInternal(root); + if (xmlSetTreeDoc(root, doc) < 0) + return(NULL); + root->parent = (xmlNodePtr) doc; if (old == NULL) { if (doc->children == NULL) { doc->children = root; @@ -5104,40 +5106,27 @@ xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { * * Set the language of a node, i.e. the values of the xml:lang * attribute. + * + * Return 0 on success, 1 if arguments are invalid, -1 if a + * memory allocation failed. */ -void +int xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { xmlNsPtr ns; + xmlAttrPtr attr; + int res; - if (cur == NULL) return; - switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; - case XML_ELEMENT_NODE: - case XML_ATTRIBUTE_NODE: - break; - } - ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); - if (ns == NULL) - return; - xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(1); + + res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); + if (res != 0) + return(res); + attr = xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); + if (attr == NULL) + return(-1); + + return(0); } #endif /* LIBXML_TREE_ENABLED */ @@ -5154,15 +5143,22 @@ xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { xmlChar * xmlNodeGetLang(const xmlNode *cur) { xmlChar *lang; + int res; if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(NULL); + while (cur != NULL) { - lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); + res = xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE, + &lang); + if (res < 0) + return(NULL); if (lang != NULL) return(lang); + cur = cur->parent; } + return(NULL); } @@ -5175,47 +5171,34 @@ xmlNodeGetLang(const xmlNode *cur) { * * Set (or reset) the space preserving behaviour of a node, i.e. the * value of the xml:space attribute. + * + * Return 0 on success, 1 if arguments are invalid, -1 if a + * memory allocation failed. */ -void +int xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { xmlNsPtr ns; + xmlAttrPtr attr; + const char *string; + int res; - if (cur == NULL) return; - switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; - case XML_ELEMENT_NODE: - case XML_ATTRIBUTE_NODE: - break; - } - ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); - if (ns == NULL) - return; - switch (val) { - case 0: - xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); - break; - case 1: - xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); - break; - } + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(1); + + res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); + if (res != 0) + return(res); + + if (val == 0) + string = "default"; + else + string = "preserve"; + + attr = xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST string); + if (attr == NULL) + return(-1); + + return(0); } #endif /* LIBXML_TREE_ENABLED */ @@ -5232,11 +5215,16 @@ xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { int xmlNodeGetSpacePreserve(const xmlNode *cur) { xmlChar *space; + int res; if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) return(-1); + while (cur != NULL) { - space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); + res = xmlNodeGetAttrValue(cur, BAD_CAST "space", XML_XML_NAMESPACE, + &space); + if (res < 0) + return(-1); if (space != NULL) { if (xmlStrEqual(space, BAD_CAST "preserve")) { xmlFree(space); @@ -5248,8 +5236,10 @@ xmlNodeGetSpacePreserve(const xmlNode *cur) { } xmlFree(space); } + cur = cur->parent; } + return(-1); } @@ -5265,51 +5255,39 @@ void xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { xmlDocPtr doc; xmlDictPtr dict; - const xmlChar *freeme = NULL; + const xmlChar *copy; + const xmlChar *oldName; if (cur == NULL) return; if (name == NULL) return; switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: case XML_PI_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_DTD_NODE: - case XML_DOCUMENT_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: break; + default: + return; } + doc = cur->doc; if (doc != NULL) dict = doc->dict; else dict = NULL; - if (dict != NULL) { - if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) - freeme = cur->name; - cur->name = xmlDictLookup(dict, name, -1); - } else { - if (cur->name != NULL) - freeme = cur->name; - cur->name = xmlStrdup(name); - } - if (freeme) - xmlFree((xmlChar *) freeme); + if (dict != NULL) + copy = xmlDictLookup(dict, name, -1); + else + copy = xmlStrdup(name); + if (copy == NULL) + return; + + oldName = cur->name; + cur->name = copy; + if ((oldName != NULL) && + ((dict == NULL) || (!xmlDictOwns(dict, oldName)))) + xmlFree((xmlChar *) oldName); } #endif @@ -5321,31 +5299,17 @@ xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { * * Set (or reset) the base URI of a node, i.e. the value of the * xml:base attribute. + * + * Returns 0 on success, -1 on error. */ -void +int xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { xmlNsPtr ns; xmlChar* fixed; - if (cur == NULL) return; + if (cur == NULL) + return(-1); switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; @@ -5355,31 +5319,40 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { if (doc->URL != NULL) xmlFree((xmlChar *) doc->URL); - if (uri == NULL) + if (uri == NULL) { doc->URL = NULL; - else + } else { doc->URL = xmlPathToURI(uri); - return; + if (doc->URL == NULL) + return(-1); + } + return(0); } + default: + return(-1); } - ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); + xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); if (ns == NULL) - return; + return(-1); fixed = xmlPathToURI(uri); - if (fixed != NULL) { - xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); - xmlFree(fixed); - } else { - xmlSetNsProp(cur, ns, BAD_CAST "base", uri); + if (fixed == NULL) + return(-1); + if (xmlSetNsProp(cur, ns, BAD_CAST "base", fixed) == NULL) { + xmlFree(fixed); + return(-1); } + xmlFree(fixed); + + return(0); } #endif /* LIBXML_TREE_ENABLED */ /** - * xmlNodeGetBase: + * xmlNodeGetBaseSafe: * @doc: the document the node pertains to * @cur: the node being checked + * @baseOut: pointer to base * * Searches for the BASE URL. The code should work on both XML * and HTML document even if base mechanisms are completely different. @@ -5390,19 +5363,27 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { * However it does not return the document base (5.1.3), use * doc->URL in this case * - * Returns a pointer to the base URL, or NULL if not found - * It's up to the caller to free the memory with xmlFree(). + * Available since 2.13.0. + * + * Return 0 in case of success, 1 if a URI or argument is invalid, -1 if a + * memory allocation failed. */ -xmlChar * -xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { - xmlChar *oldbase = NULL; +int +xmlNodeGetBaseSafe(const xmlDoc *doc, const xmlNode *cur, xmlChar **baseOut) { + xmlChar *ret = NULL; xmlChar *base, *newbase; + int res; + if (baseOut == NULL) + return(1); + *baseOut = NULL; if ((cur == NULL) && (doc == NULL)) - return(NULL); + return(1); if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - return(NULL); - if (doc == NULL) doc = cur->doc; + return(1); + if (doc == NULL) + doc = cur->doc; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { cur = doc->children; while ((cur != NULL) && (cur->name != NULL)) { @@ -5419,50 +5400,91 @@ xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { continue; } if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { - return(xmlGetProp(cur, BAD_CAST "href")); + if (xmlNodeGetAttrValue(cur, BAD_CAST "href", NULL, &ret) < 0) + return(-1); + if (ret == NULL) + return(1); + goto found; } cur = cur->next; } - return(NULL); + return(0); } + while (cur != NULL) { if (cur->type == XML_ENTITY_DECL) { xmlEntityPtr ent = (xmlEntityPtr) cur; - return(xmlStrdup(ent->URI)); + + if (ent->URI == NULL) + break; + xmlFree(ret); + ret = xmlStrdup(ent->URI); + if (ret == NULL) + return(-1); + goto found; } if (cur->type == XML_ELEMENT_NODE) { - base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); + if (xmlNodeGetAttrValue(cur, BAD_CAST "base", XML_XML_NAMESPACE, + &base) < 0) { + xmlFree(ret); + return(-1); + } if (base != NULL) { - if (oldbase != NULL) { - newbase = xmlBuildURI(oldbase, base); - if (newbase != NULL) { - xmlFree(oldbase); - xmlFree(base); - oldbase = newbase; - } else { - xmlFree(oldbase); - xmlFree(base); - return(NULL); - } + if (ret != NULL) { + res = xmlBuildURISafe(ret, base, &newbase); + xmlFree(ret); + xmlFree(base); + if (res != 0) + return(res); + ret = newbase; } else { - oldbase = base; + ret = base; } - if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || - (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || - (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) - return(oldbase); + if ((!xmlStrncmp(ret, BAD_CAST "http://", 7)) || + (!xmlStrncmp(ret, BAD_CAST "ftp://", 6)) || + (!xmlStrncmp(ret, BAD_CAST "urn:", 4))) + goto found; } } cur = cur->parent; } + if ((doc != NULL) && (doc->URL != NULL)) { - if (oldbase == NULL) - return(xmlStrdup(doc->URL)); - newbase = xmlBuildURI(oldbase, doc->URL); - xmlFree(oldbase); - return(newbase); + if (ret == NULL) { + ret = xmlStrdup(doc->URL); + if (ret == NULL) + return(-1); + } else { + res = xmlBuildURISafe(ret, doc->URL, &newbase); + xmlFree(ret); + if (res != 0) + return(res); + ret = newbase; + } } - return(oldbase); + +found: + *baseOut = ret; + return(0); +} + +/** + * xmlNodeGetBase: + * @doc: the document the node pertains to + * @cur: the node being checked + * + * See xmlNodeGetBaseSafe. This function doesn't allow to distinguish + * memory allocation failures from a non-existing base. + * + * Returns a pointer to the base URL, or NULL if not found + * It's up to the caller to free the memory with xmlFree(). + */ +xmlChar * +xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { + xmlChar *base; + + xmlNodeGetBaseSafe(doc, cur, &base); + return(base); } /** @@ -5493,6 +5515,69 @@ xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur) return(0); } +static void +xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) { + xmlEntityPtr ent; + + if (ref->children != NULL) { + ent = (xmlEntityPtr) ref->children; + } else { + /* lookup entity declaration */ + ent = xmlGetDocEntity(ref->doc, ref->name); + if (ent == NULL) + return; + } + + /* + * The parser should always expand predefined entities but it's + * possible to create references to predefined entities using + * the tree API. + */ + if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) { + xmlBufCat(buf, ent->content); + return; + } + + if (ent->flags & XML_ENT_EXPANDING) + return; + + ent->flags |= XML_ENT_EXPANDING; + xmlBufGetChildContent(buf, (xmlNodePtr) ent); + ent->flags &= ~XML_ENT_EXPANDING; +} + +static void +xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree) { + const xmlNode *cur = tree->children; + + while (cur != NULL) { + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + xmlBufCat(buf, cur->content); + break; + + case XML_ENTITY_REF_NODE: + xmlBufGetEntityRefContent(buf, cur); + break; + + default: + if (cur->children != NULL) { + cur = cur->children; + continue; + } + break; + } + + while (cur->next == NULL) { + cur = cur->parent; + if (cur == tree) + return; + } + cur = cur->next; + } +} + /** * xmlBufGetNodeContent: * @buf: a buffer xmlBufPtr @@ -5509,127 +5594,38 @@ xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur) int xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur) { - if ((cur == NULL) || (buf == NULL)) return(-1); + if ((cur == NULL) || (buf == NULL)) + return(-1); + switch (cur->type) { - case XML_CDATA_SECTION_NODE: - case XML_TEXT_NODE: - xmlBufCat(buf, cur->content); - break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: - case XML_ELEMENT_NODE:{ - const xmlNode *tmp = cur; - - while (tmp != NULL) { - switch (tmp->type) { - case XML_CDATA_SECTION_NODE: - case XML_TEXT_NODE: - if (tmp->content != NULL) - xmlBufCat(buf, tmp->content); - break; - case XML_ENTITY_REF_NODE: - xmlBufGetNodeContent(buf, tmp); - break; - default: - break; - } - /* - * Skip to next node - */ - if (tmp->children != NULL) { - if (tmp->children->type != XML_ENTITY_DECL) { - tmp = tmp->children; - continue; - } - } - if (tmp == cur) - break; - - if (tmp->next != NULL) { - tmp = tmp->next; - continue; - } - - do { - tmp = tmp->parent; - if (tmp == NULL) - break; - if (tmp == cur) { - tmp = NULL; - break; - } - if (tmp->next != NULL) { - tmp = tmp->next; - break; - } - } while (tmp != NULL); - } - break; - } - case XML_ATTRIBUTE_NODE:{ - xmlAttrPtr attr = (xmlAttrPtr) cur; - xmlNodePtr tmp = attr->children; + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_ENTITY_DECL: + xmlBufGetChildContent(buf, cur); + break; - while (tmp != NULL) { - if (tmp->type == XML_TEXT_NODE) - xmlBufCat(buf, tmp->content); - else - xmlBufGetNodeContent(buf, tmp); - tmp = tmp->next; - } - break; - } + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: xmlBufCat(buf, cur->content); break; - case XML_ENTITY_REF_NODE:{ - xmlEntityPtr ent; - xmlNodePtr tmp; - /* lookup entity declaration */ - ent = xmlGetDocEntity(cur->doc, cur->name); - if (ent == NULL) - return(-1); - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content - * -> we iterate through child nodes and recursive call - * xmlNodeGetContent() which handles all possible node types */ - tmp = ent->children; - while (tmp) { - xmlBufGetNodeContent(buf, tmp); - tmp = tmp->next; - } - break; - } - case XML_ENTITY_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: + case XML_ENTITY_REF_NODE: + xmlBufGetEntityRefContent(buf, cur); break; - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - cur = cur->children; - while (cur!= NULL) { - if ((cur->type == XML_ELEMENT_NODE) || - (cur->type == XML_TEXT_NODE) || - (cur->type == XML_CDATA_SECTION_NODE)) { - xmlBufGetNodeContent(buf, cur); - } - cur = cur->next; - } - break; + case XML_NAMESPACE_DECL: xmlBufCat(buf, ((xmlNsPtr) cur)->href); break; - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: + + default: break; } + return(0); } @@ -5647,167 +5643,131 @@ xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur) xmlChar * xmlNodeGetContent(const xmlNode *cur) { + xmlBufPtr buf; + xmlChar *ret; + if (cur == NULL) return (NULL); + switch (cur->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_REF_NODE: + break; + case XML_DOCUMENT_FRAG_NODE: - case XML_ELEMENT_NODE:{ - xmlBufPtr buf; - xmlChar *ret; - - buf = xmlBufCreateSize(64); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - xmlBufGetNodeContent(buf, cur); - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); - } + case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: - return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); - case XML_COMMENT_NODE: - case XML_PI_NODE: - if (cur->content != NULL) - return (xmlStrdup(cur->content)); - return (NULL); - case XML_ENTITY_REF_NODE:{ - xmlEntityPtr ent; - xmlBufPtr buf; - xmlChar *ret; - - /* lookup entity declaration */ - ent = xmlGetDocEntity(cur->doc, cur->name); - if (ent == NULL) - return (NULL); - - buf = xmlBufCreate(); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - - xmlBufGetNodeContent(buf, cur); - - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); + case XML_ENTITY_DECL: { + xmlNodePtr children = cur->children; + + if (children == NULL) + return(xmlStrdup(BAD_CAST "")); + + /* Optimization for single text children */ + if (((children->type == XML_TEXT_NODE) || + (children->type == XML_CDATA_SECTION_NODE)) && + (children->next == NULL)) { + if (children->content == NULL) + return(xmlStrdup(BAD_CAST "")); + return(xmlStrdup(children->content)); } - case XML_ENTITY_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return (NULL); - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: { - xmlBufPtr buf; - xmlChar *ret; - buf = xmlBufCreate(); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - - xmlBufGetNodeContent(buf, (xmlNodePtr) cur); - - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); - } - case XML_NAMESPACE_DECL: { - xmlChar *tmp; + break; + } - tmp = xmlStrdup(((xmlNsPtr) cur)->href); - return (tmp); - } - case XML_ELEMENT_DECL: - /* TODO !!! */ - return (NULL); - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - return (NULL); - case XML_ENTITY_DECL: - /* TODO !!! */ - return (NULL); case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: if (cur->content != NULL) - return (xmlStrdup(cur->content)); - return (NULL); + return(xmlStrdup(cur->content)); + else + return(xmlStrdup(BAD_CAST "")); + + case XML_NAMESPACE_DECL: + return(xmlStrdup(((xmlNsPtr) cur)->href)); + + default: + return(NULL); } - return (NULL); + + buf = xmlBufCreateSize(64); + if (buf == NULL) + return (NULL); + xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + xmlBufGetNodeContent(buf, cur); + ret = xmlBufDetach(buf); + xmlBufFree(buf); + + return(ret); } -/** - * xmlNodeSetContent: - * @cur: the node being modified - * @content: the new value of the content - * - * Replace the content of a node. - * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). - */ -void -xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { +static int +xmlNodeSetContentInternal(xmlNodePtr cur, const xmlChar *content, int len) { if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeSetContent : node == NULL\n"); -#endif - return; + return(1); } switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->children = xmlStringGetNodeList(cur->doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) + if (xmlNodeParseContent(cur, content, len) < 0) + return(-1); break; + case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: - case XML_COMMENT_NODE: - if ((cur->content != NULL) && - (cur->content != (xmlChar *) &(cur->properties))) { - if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && - (xmlDictOwns(cur->doc->dict, cur->content)))) - xmlFree(cur->content); - } - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->last = cur->children = NULL; + case XML_COMMENT_NODE: { + xmlChar *copy = NULL; + if (content != NULL) { - cur->content = xmlStrdup(content); - } else - cur->content = NULL; - cur->properties = NULL; - break; - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_NOTATION_NODE: - break; - case XML_DTD_NODE: - break; - case XML_NAMESPACE_DECL: - break; - case XML_ELEMENT_DECL: - /* TODO !!! */ - break; - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - break; - case XML_ENTITY_DECL: - /* TODO !!! */ + if (len < 0) + copy = xmlStrdup(content); + else + copy = xmlStrndup(content, len); + if (copy == NULL) + return(-1); + } + + xmlTextSetContent(cur, copy); break; + } + + default: + break; } + + return(0); +} + +/** + * xmlNodeSetContent: + * @cur: the node being modified + * @content: the new value of the content + * + * Replace the text content of a node. + * + * Sets the raw text content of text, CDATA, comment or PI nodes. + * + * For element and attribute nodes, removes all children and + * replaces them by parsing @content which is expected to be a + * valid XML attribute value possibly containing character and + * entity references. Syntax errors and references to undeclared + * entities are ignored silently. Unfortunately, there isn't an + * API to pass raw content directly. An inefficient work-around + * is to escape the content with xmlEncodeSpecialChars before + * passing it. A better trick is clearing the old content + * with xmlNodeSetContent(node, NULL) first and then calling + * xmlNodeAddContent(node, content). Unlike this function, + * xmlNodeAddContent accepts raw text. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. + */ +int +xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { + return(xmlNodeSetContentInternal(cur, content, -1)); } #ifdef LIBXML_TREE_ENABLED @@ -5817,67 +5777,13 @@ xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { * @content: the new value of the content * @len: the size of @content * - * Replace the content of a node. - * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). + * See xmlNodeSetContent. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { - if (cur == NULL) { -#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; - break; - case XML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_ELEMENT_DECL: - /* TODO !!! */ - break; - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - break; - case XML_ENTITY_DECL: - /* TODO !!! */ - break; - } + return(xmlNodeSetContentInternal(cur, content, len)); } #endif /* LIBXML_TREE_ENABLED */ @@ -5891,67 +5797,43 @@ xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeAddContentLen : node == NULL\n"); -#endif - return; - } - if (len <= 0) return; + if (cur == NULL) + return(1); + if ((content == NULL) || (len <= 0)) + return(0); + switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: { - xmlNodePtr last, newNode, tmp; + xmlNodePtr newNode, tmp; - last = cur->last; newNode = xmlNewDocTextLen(cur->doc, content, len); - if (newNode != NULL) { - tmp = xmlAddChild(cur, newNode); - if (tmp != newNode) - return; - if ((last != NULL) && (last->next == newNode)) { - xmlTextMerge(last, newNode); - } - } + if (newNode == NULL) + return(-1); + tmp = xmlAddChild(cur, newNode); + if (tmp == NULL) { + xmlFreeNode(newNode); + return(-1); + } break; } case XML_ATTRIBUTE_NODE: break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: - case XML_NOTATION_NODE: - if (content != NULL) { - if ((cur->content == (xmlChar *) &(cur->properties)) || - ((cur->doc != NULL) && (cur->doc->dict != NULL) && - xmlDictOwns(cur->doc->dict, cur->content))) { - cur->content = xmlStrncatNew(cur->content, content, len); - cur->properties = NULL; - } else { - cur->content = xmlStrncat(cur->content, content, len); - } - } - break; - case XML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - break; + return(xmlTextAddContent(cur, content, len)); + default: + break; } + + return(0); } /** @@ -5963,21 +5845,12 @@ xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { - int len; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeAddContent : node == NULL\n"); -#endif - return; - } - if (content == NULL) return; - len = xmlStrlen(content); - xmlNodeAddContentLen(cur, content, len); + return(xmlNodeAddContentLen(cur, content, xmlStrlen(content))); } /** @@ -5985,120 +5858,246 @@ xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { * @first: the first text node * @second: the second text node being merged * - * Merge two text nodes into one - * Returns the first text node augmented + * Merge the second text node into the first. The second node is + * unlinked and freed. + * + * Returns the first text node augmented or NULL in case of error. */ xmlNodePtr xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { - if (first == NULL) return(second); - if (second == NULL) return(first); - if (first->type != XML_TEXT_NODE) return(first); - if (second->type != XML_TEXT_NODE) return(first); - if (second->name != first->name) - return(first); - xmlNodeAddContent(first, second->content); - xmlUnlinkNode(second); + if ((first == NULL) || (first->type != XML_TEXT_NODE) || + (second == NULL) || (second->type != XML_TEXT_NODE) || + (first == second) || + (first->name != second->name)) + return(NULL); + + if (xmlTextAddContent(first, second->content, -1) < 0) + return(NULL); + + xmlUnlinkNodeInternal(second); xmlFreeNode(second); return(first); } #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** - * xmlGetNsList: + * xmlGetNsListSafe: * @doc: the document * @node: the current node + * @out: the returned namespace array + * + * Find all in-scope namespaces of a node. @out returns a NULL + * terminated array of namespace pointers that must be freed by + * the caller. * - * Search all the namespace applying to a given element. - * Returns an NULL terminated array of all the #xmlNsPtr found - * that need to be freed by the caller or NULL if no - * namespace if defined + * Available since 2.13.0. + * + * Returns 0 on success, 1 if no namespaces were found, -1 if a + * memory allocation failed. */ -xmlNsPtr * -xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node) +int +xmlGetNsListSafe(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node, + xmlNsPtr **out) { xmlNsPtr cur; - xmlNsPtr *ret = NULL; + xmlNsPtr *namespaces = NULL; int nbns = 0; - int maxns = 10; + int maxns = 0; int i; + if (out == NULL) + return(1); + *out = NULL; if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) - return(NULL); + return(1); while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { - 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))) + if ((cur->prefix == namespaces[i]->prefix) || + (xmlStrEqual(cur->prefix, namespaces[i]->prefix))) break; } if (i >= nbns) { if (nbns >= maxns) { - maxns *= 2; - ret = (xmlNsPtr *) xmlRealloc(ret, - (maxns + - 1) * + xmlNsPtr *tmp; + + maxns = maxns ? maxns * 2 : 10; + tmp = (xmlNsPtr *) xmlRealloc(namespaces, + (maxns + 1) * sizeof(xmlNsPtr)); - if (ret == NULL) { - xmlTreeErrMemory("getting namespace list"); - return (NULL); + if (tmp == NULL) { + xmlFree(namespaces); + return(-1); } + namespaces = tmp; } - ret[nbns++] = cur; - ret[nbns] = NULL; + namespaces[nbns++] = cur; + namespaces[nbns] = NULL; } - cur = cur->next; + cur = cur->next; + } + } + node = node->parent; + } + + *out = namespaces; + return((namespaces == NULL) ? 1 : 0); +} + +/** + * xmlGetNsList: + * @doc: the document + * @node: the current node + * + * Find all in-scope namespaces of a node. + * + * Use xmlGetNsListSafe for better error reporting. + * + * Returns a NULL terminated array of namespace pointers that must + * be freed by the caller or NULL if no namespaces were found or + * a memory allocation failed. + */ +xmlNsPtr * +xmlGetNsList(const xmlDoc *doc, const xmlNode *node) +{ + xmlNsPtr *ret; + + xmlGetNsListSafe(doc, node, &ret); + return(ret); +} +#endif /* LIBXML_TREE_ENABLED */ + +static xmlNsPtr +xmlNewXmlNs(void) { + xmlNsPtr ns; + + ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (ns == NULL) + return(NULL); + memset(ns, 0, sizeof(xmlNs)); + ns->type = XML_LOCAL_NAMESPACE; + ns->href = xmlStrdup(XML_XML_NAMESPACE); + if (ns->href == NULL) { + xmlFreeNs(ns); + return(NULL); + } + ns->prefix = xmlStrdup(BAD_CAST "xml"); + if (ns->prefix == NULL) { + xmlFreeNs(ns); + return(NULL); + } + + return(ns); +} + +/* +* xmlTreeEnsureXMLDecl: +* @doc: the doc +* +* Ensures that there is an XML namespace declaration on the doc. +* +* Returns the XML ns-struct or NULL if a memory allocation failed. +*/ +static xmlNsPtr +xmlTreeEnsureXMLDecl(xmlDocPtr doc) +{ + xmlNsPtr ns; + + ns = doc->oldNs; + if (ns != NULL) + return (ns); + + ns = xmlNewXmlNs(); + doc->oldNs = ns; + + return(ns); +} + +/** + * xmlSearchNsSafe: + * @node: a node + * @prefix: a namespace prefix + * @out: pointer to resulting namespace + * + * Search a namespace with @prefix in scope of @node. + * + * Returns 0 on success, -1 if a memory allocation failed, 1 on + * other errors. + */ +int +xmlSearchNsSafe(xmlNodePtr node, const xmlChar *prefix, + xmlNsPtr *out) { + xmlNsPtr cur; + xmlDocPtr doc; + xmlNodePtr orig = node; + xmlNodePtr parent; + + if (out == NULL) + return(1); + *out = NULL; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) + return(1); + + doc = node->doc; + + if ((doc != NULL) && (IS_STR_XML(prefix))) { + cur = xmlTreeEnsureXMLDecl(doc); + if (cur == NULL) + return(-1); + *out = cur; + return(0); + } + + while (node->type != XML_ELEMENT_NODE) { + node = node->parent; + if (node == NULL) + return(0); + } + + parent = node; + + while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { + cur = node->nsDef; + while (cur != NULL) { + if ((xmlStrEqual(cur->prefix, prefix)) && + (cur->href != NULL)) { + *out = cur; + return(0); } + cur = cur->next; } - node = node->parent; + if (orig != node) { + cur = node->ns; + if ((cur != NULL) && + (xmlStrEqual(cur->prefix, prefix)) && + (cur->href != NULL)) { + *out = cur; + return(0); + } + } + + 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); + /* + * The XML-1.0 namespace is normally held on the document + * element. In this case exceptionally create it on the + * node element. + */ + if ((doc == NULL) && (IS_STR_XML(prefix))) { + cur = xmlNewXmlNs(); + if (cur == NULL) + return(-1); + cur->next = parent->nsDef; + parent->nsDef = cur; + *out = cur; } + + return(0); } /** @@ -6115,82 +6114,17 @@ xmlTreeEnsureXMLDecl(xmlDocPtr doc) * the namespace within those you will be in troubles !!! A warning * is generated to cover this case. * - * Returns the namespace pointer or NULL. + * Returns the namespace pointer or NULL if no namespace was found or + * a memory allocation failed. Allocations can only fail if the "xml" + * namespace is queried. */ xmlNsPtr -xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { - +xmlSearchNs(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, + const xmlChar *nameSpace) { xmlNsPtr cur; - const xmlNode *orig = node; - if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL); - if ((nameSpace != NULL) && - (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { - if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { - /* - * The XML-1.0 namespace is normally held on the root - * element. In this case exceptionally create it on the - * node element. - */ - cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("searching namespace"); - return(NULL); - } - memset(cur, 0, sizeof(xmlNs)); - cur->type = XML_LOCAL_NAMESPACE; - cur->href = xmlStrdup(XML_XML_NAMESPACE); - cur->prefix = xmlStrdup((const xmlChar *)"xml"); - cur->next = node->nsDef; - node->nsDef = cur; - return(cur); - } - if (doc == NULL) { - doc = node->doc; - if (doc == NULL) - return(NULL); - } - /* - * Return the XML namespace declaration held by the doc. - */ - if (doc->oldNs == NULL) - return(xmlTreeEnsureXMLDecl(doc)); - else - return(doc->oldNs); - } - while (node != NULL) { - if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || - (node->type == XML_ENTITY_DECL)) - return(NULL); - if (node->type == XML_ELEMENT_NODE) { - cur = node->nsDef; - while (cur != NULL) { - if ((cur->prefix == NULL) && (nameSpace == NULL) && - (cur->href != NULL)) - return(cur); - if ((cur->prefix != NULL) && (nameSpace != NULL) && - (cur->href != NULL) && - (xmlStrEqual(cur->prefix, nameSpace))) - return(cur); - cur = cur->next; - } - if (orig != node) { - cur = node->ns; - if (cur != NULL) { - if ((cur->prefix == NULL) && (nameSpace == NULL) && - (cur->href != NULL)) - return(cur); - if ((cur->prefix != NULL) && (nameSpace != NULL) && - (cur->href != NULL) && - (xmlStrEqual(cur->prefix, nameSpace))) - return(cur); - } - } - } - node = node->parent; - } - return(NULL); + xmlSearchNsSafe(node, nameSpace, &cur); + return(cur); } /** @@ -6213,7 +6147,6 @@ xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, while ((node != NULL) && (node != ancestor)) { if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || (node->type == XML_ENTITY_DECL)) return (-1); if (node->type == XML_ELEMENT_NODE) { @@ -6237,92 +6170,117 @@ xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, } /** - * xmlSearchNsByHref: - * @doc: the document - * @node: the current node - * @href: the namespace value + * xmlSearchNsByHrefSafe: + * @node: a node + * @href: a namespace URI + * @out: pointer to resulting namespace * - * Search a Ns aliasing a given URI. Recurse on the parents until it finds - * the defined namespace or return NULL otherwise. - * Returns the namespace pointer or NULL. + * Search a namespace matching @URI in scope of @node. + * + * Returns 0 on success, -1 if a memory allocation failed, 1 on + * other errors. */ -xmlNsPtr -xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) -{ +int +xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, + xmlNsPtr *out) { xmlNsPtr cur; + xmlDocPtr doc; xmlNodePtr orig = node; + xmlNodePtr parent; int is_attr; - if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL)) - return (NULL); - if (xmlStrEqual(href, XML_XML_NAMESPACE)) { - /* - * Only the document can hold the XML spec namespace. - */ - if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { - /* - * The XML-1.0 namespace is normally held on the root - * element. In this case exceptionally create it on the - * node element. - */ - cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("searching namespace"); - return (NULL); - } - memset(cur, 0, sizeof(xmlNs)); - cur->type = XML_LOCAL_NAMESPACE; - cur->href = xmlStrdup(XML_XML_NAMESPACE); - cur->prefix = xmlStrdup((const xmlChar *) "xml"); - cur->next = node->nsDef; - node->nsDef = cur; - return (cur); - } - if (doc == NULL) { - doc = node->doc; - if (doc == NULL) - return(NULL); - } - /* - * Return the XML namespace declaration held by the doc. - */ - if (doc->oldNs == NULL) - return(xmlTreeEnsureXMLDecl(doc)); - else - return(doc->oldNs); + if (out == NULL) + return(1); + *out = NULL; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) + return(1); + + doc = node->doc; + + if ((doc != NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) { + cur = xmlTreeEnsureXMLDecl(doc); + if (cur == NULL) + return(-1); + *out = cur; + return(0); } + is_attr = (node->type == XML_ATTRIBUTE_NODE); - while (node != NULL) { - if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || - (node->type == XML_ENTITY_DECL)) - return (NULL); - if (node->type == XML_ELEMENT_NODE) { - cur = node->nsDef; - while (cur != NULL) { - if ((cur->href != NULL) && (href != NULL) && - (xmlStrEqual(cur->href, href))) { - if (((!is_attr) || (cur->prefix != NULL)) && - (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) - return (cur); + + while (node->type != XML_ELEMENT_NODE) { + node = node->parent; + if (node == NULL) + return(0); + } + + parent = node; + + while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { + cur = node->nsDef; + while (cur != NULL) { + if (xmlStrEqual(cur->href, href)) { + if (((!is_attr) || (cur->prefix != NULL)) && + (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) { + *out = cur; + return(0); } - cur = cur->next; } - if (orig != node) { - cur = node->ns; - if (cur != NULL) { - if ((cur->href != NULL) && (href != NULL) && - (xmlStrEqual(cur->href, href))) { - if (((!is_attr) || (cur->prefix != NULL)) && - (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) - return (cur); + cur = cur->next; + } + if (orig != node) { + cur = node->ns; + if (cur != NULL) { + if (xmlStrEqual(cur->href, href)) { + if (((!is_attr) || (cur->prefix != NULL)) && + (xmlNsInScope(doc, orig, node, + cur->prefix) == 1)) { + *out = cur; + return(0); } } } } + node = node->parent; } - return (NULL); + + /* + * The XML-1.0 namespace is normally held on the document + * element. In this case exceptionally create it on the + * node element. + */ + if ((doc == NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) { + cur = xmlNewXmlNs(); + if (cur == NULL) + return(-1); + cur->next = parent->nsDef; + parent->nsDef = cur; + *out = cur; + } + + return(0); +} + +/** + * xmlSearchNsByHref: + * @doc: the document + * @node: the current node + * @href: the namespace value + * + * Search a Ns aliasing a given URI. Recurse on the parents until it finds + * the defined namespace or return NULL otherwise. + * + * Returns the namespace pointer or NULL if no namespace was found or + * a memory allocation failed. Allocations can only fail if the "xml" + * namespace is queried. + */ +xmlNsPtr +xmlSearchNsByHref(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, + const xmlChar * href) { + xmlNsPtr cur; + + xmlSearchNsByHrefSafe(node, href, &cur); + return(cur); } /** @@ -6339,29 +6297,24 @@ xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) * Returns the (new) namespace definition or NULL in case of error */ static xmlNsPtr -xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { +xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns) { xmlNsPtr def; xmlChar prefix[50]; int counter = 1; + int res; if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewReconciledNs : tree == NULL\n"); -#endif return(NULL); } if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNewReconciledNs : ns == NULL\n"); -#endif return(NULL); } /* * Search an existing namespace definition inherited. */ - def = xmlSearchNsByHref(doc, tree, ns->href); + res = xmlSearchNsByHrefSafe(tree, ns->href, &def); + if (res < 0) + return(NULL); if (def != NULL) return(def); @@ -6374,7 +6327,9 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { else snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); - def = xmlSearchNs(doc, tree, prefix); + res = xmlSearchNsSafe(tree, prefix, &def); + if (res < 0) + return(NULL); while (def != NULL) { if (counter > 1000) return(NULL); if (ns->prefix == NULL) @@ -6382,7 +6337,9 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { else snprintf((char *) prefix, sizeof(prefix), "%.20s%d", (char *)ns->prefix, counter++); - def = xmlSearchNs(doc, tree, prefix); + res = xmlSearchNsSafe(tree, prefix, &def); + if (res < 0) + return(NULL); } /* @@ -6393,6 +6350,12 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { } #ifdef LIBXML_TREE_ENABLED + +typedef struct { + xmlNsPtr oldNs; + xmlNsPtr newNs; +} xmlNsCache; + /** * xmlReconciliateNs: * @doc: the document @@ -6405,12 +6368,12 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { * as possible the function try to reuse the existing namespaces found in * the new environment. If not possible the new namespaces are redeclared * on @tree at the top of the given subtree. - * Returns the number of namespace declarations created or -1 in case of error. + * + * Returns 0 on success or -1 in case of error. */ int xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { - xmlNsPtr *oldNs = NULL; - xmlNsPtr *newNs = NULL; + xmlNsCache *cache = NULL; int sizeCache = 0; int nbCache = 0; @@ -6420,35 +6383,15 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { int ret = 0, i; if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); - if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); if (node->doc != doc) return(-1); while (node != NULL) { /* * Reconciliate the node namespace */ if (node->ns != NULL) { - /* - * initialize the cache if needed - */ - if (sizeCache == 0) { - sizeCache = 10; - oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - return(-1); - } - newNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } - } - for (i = 0;i < nbCache;i++) { - if (oldNs[i] == node->ns) { - node->ns = newNs[i]; + for (i = 0; i < nbCache; i++) { + if (cache[i].oldNs == node->ns) { + node->ns = cache[i].newNs; break; } } @@ -6456,32 +6399,31 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { /* * OK we need to recreate a new namespace definition */ - n = xmlNewReconciledNs(doc, tree, node->ns); - if (n != NULL) { /* :-( what if else ??? */ + n = xmlNewReconciledNs(tree, node->ns); + if (n == NULL) { + ret = -1; + } else { /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { - sizeCache *= 2; - oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(newNs); - return(-1); - } - newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } + xmlNsCache *tmp; + size_t newSize = sizeCache ? sizeCache * 2 : 10; + + tmp = xmlRealloc(cache, newSize * sizeof(tmp[0])); + if (tmp == NULL) { + ret = -1; + } else { + cache = tmp; + sizeCache = newSize; + } } - newNs[nbCache] = n; - oldNs[nbCache++] = node->ns; - node->ns = n; + if (nbCache < sizeCache) { + cache[nbCache].newNs = n; + cache[nbCache++].oldNs = node->ns; + } } + node->ns = n; } } /* @@ -6491,28 +6433,9 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { attr = node->properties; while (attr != NULL) { if (attr->ns != NULL) { - /* - * initialize the cache if needed - */ - if (sizeCache == 0) { - sizeCache = 10; - oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - return(-1); - } - newNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } - } - for (i = 0;i < nbCache;i++) { - if (oldNs[i] == attr->ns) { - attr->ns = newNs[i]; + for (i = 0; i < nbCache; i++) { + if (cache[i].oldNs == attr->ns) { + attr->ns = cache[i].newNs; break; } } @@ -6520,32 +6443,33 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { /* * OK we need to recreate a new namespace definition */ - n = xmlNewReconciledNs(doc, tree, attr->ns); - if (n != NULL) { /* :-( what if else ??? */ + n = xmlNewReconciledNs(tree, attr->ns); + if (n == NULL) { + ret = -1; + } else { /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { - sizeCache *= 2; - oldNs = (xmlNsPtr *) xmlRealloc(oldNs, - sizeCache * sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(newNs); - return(-1); - } - newNs = (xmlNsPtr *) xmlRealloc(newNs, - sizeCache * sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } + xmlNsCache *tmp; + size_t newSize = sizeCache ? + sizeCache * 2 : 10; + + tmp = xmlRealloc(cache, + newSize * sizeof(tmp[0])); + if (tmp == NULL) { + ret = -1; + } else { + cache = tmp; + sizeCache = newSize; + } + } + if (nbCache < sizeCache) { + cache[nbCache].newNs = n; + cache[nbCache++].oldNs = attr->ns; } - newNs[nbCache] = n; - oldNs[nbCache++] = attr->ns; - attr->ns = n; } + attr->ns = n; } } attr = attr->next; @@ -6581,10 +6505,8 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { } else break; } - if (oldNs != NULL) - xmlFree(oldNs); - if (newNs != NULL) - xmlFree(newNs); + if (cache != NULL) + xmlFree(cache); return(ret); } #endif /* LIBXML_TREE_ENABLED */ @@ -6646,7 +6568,11 @@ xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, */ if ((node->ns != NULL) && (node->ns->prefix != NULL)) { tmpstr = xmlStrdup(node->ns->prefix); + if (tmpstr == NULL) + return(NULL); tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); + if (tmpstr == NULL) + return(NULL); tmpstr = xmlStrcat(tmpstr, node->name); if (tmpstr == NULL) return(NULL); @@ -6722,28 +6648,7 @@ xmlGetPropNodeValueInternal(const xmlAttr *prop) if (prop == NULL) return(NULL); if (prop->type == XML_ATTRIBUTE_NODE) { - /* - * Note that we return at least the empty string. - * TODO: Do we really always want that? - */ - if (prop->children != NULL) { - if ((prop->children->next == NULL) && - ((prop->children->type == XML_TEXT_NODE) || - (prop->children->type == XML_CDATA_SECTION_NODE))) - { - /* - * Optimization for the common case: only 1 text node. - */ - return(xmlStrdup(prop->children->content)); - } else { - xmlChar *ret; - - ret = xmlNodeListGetString(prop->doc, prop->children, 1); - if (ret != NULL) - return(ret); - } - } - return(xmlStrdup((xmlChar *)"")); + return(xmlNodeGetContent((xmlNodePtr) prop)); } else if (prop->type == XML_ATTRIBUTE_DECL) { return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); } @@ -6757,10 +6662,11 @@ xmlGetPropNodeValueInternal(const xmlAttr *prop) * * Search an attribute associated to a node * This function also looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * * Returns the attribute or the attribute declaration or NULL if - * neither was found. + * neither was found. Also returns NULL if a memory allocation failed + * making this function unreliable. */ xmlAttrPtr xmlHasProp(const xmlNode *node, const xmlChar *name) { @@ -6779,7 +6685,6 @@ xmlHasProp(const xmlNode *node, const xmlChar *name) { } prop = prop->next; } - if (!xmlCheckDTD) return(NULL); /* * Check if there is a default declaration in the internal @@ -6811,16 +6716,53 @@ xmlHasProp(const xmlNode *node, const xmlChar *name) { * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * Note that a namespace of NULL indicates to use the default namespace. * - * Returns the attribute or the attribute declaration or NULL - * if neither was found. + * Returns the attribute or the attribute declaration or NULL if + * neither was found. Also returns NULL if a memory allocation failed + * making this function unreliable. */ xmlAttrPtr xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { - return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); + return(xmlGetPropNodeInternal(node, name, nameSpace, 1)); +} + +/** + * xmlNodeGetAttrValue: + * @node: the node + * @name: the attribute name + * @nsUri: the URI of the namespace + * @out: the returned string + * + * Search and get the value of an attribute associated to a node + * This attribute has to be anchored in the namespace specified. + * This does the entity substitution. The returned value must be + * freed by the caller. + * + * Available since 2.13.0. + * + * Returns 0 on success, 1 if no attribute was found, -1 if a + * memory allocation failed. + */ +int +xmlNodeGetAttrValue(const xmlNode *node, const xmlChar *name, + const xmlChar *nsUri, xmlChar **out) { + xmlAttrPtr prop; + + if (out == NULL) + return(1); + *out = NULL; + + prop = xmlGetPropNodeInternal(node, name, nsUri, 0); + if (prop == NULL) + return(1); + + *out = xmlGetPropNodeValueInternal(prop); + if (*out == NULL) + return(-1); + return(0); } /** @@ -6831,13 +6773,17 @@ xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. - * NOTE: this function acts independently of namespaces associated + * default declaration values. + * + * NOTE: This function acts independently of namespaces associated * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() * for namespace aware processing. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetProp(const xmlNode *node, const xmlChar *name) { @@ -6857,18 +6803,21 @@ xmlGetProp(const xmlNode *node, const xmlChar *name) { * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * This function is similar to xmlGetProp except it will accept only * an attribute in no namespace. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { xmlAttrPtr prop; - prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); + prop = xmlGetPropNodeInternal(node, name, NULL, 1); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop)); @@ -6884,16 +6833,19 @@ xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { xmlAttrPtr prop; - prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); + prop = xmlGetPropNodeInternal(node, name, nameSpace, 1); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop)); @@ -6916,7 +6868,7 @@ xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { prop = xmlGetPropNodeInternal(node, name, NULL, 0); if (prop == NULL) return(-1); - xmlUnlinkNode((xmlNodePtr) prop); + xmlUnlinkNodeInternal((xmlNodePtr) prop); xmlFreeProp(prop); return(0); } @@ -6934,10 +6886,11 @@ int xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { xmlAttrPtr prop; - prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + prop = xmlGetPropNodeInternal(node, name, + (ns != NULL) ? ns->href : NULL, 0); if (prop == NULL) return(-1); - xmlUnlinkNode((xmlNodePtr) prop); + xmlUnlinkNodeInternal((xmlNodePtr) prop); xmlFreeProp(prop); return(0); } @@ -6960,8 +6913,10 @@ xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { */ xmlAttrPtr xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { - int len; - const xmlChar *nqname; + xmlNsPtr ns = NULL; + const xmlChar *localname; + xmlChar *prefix; + int res; if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) return(NULL); @@ -6969,16 +6924,19 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { /* * handle QNames */ - nqname = xmlSplitQName3(name, &len); - if (nqname != NULL) { - xmlNsPtr ns; - xmlChar *prefix = xmlStrndup(name, len); - ns = xmlSearchNs(node->doc, node, prefix); - if (prefix != NULL) - xmlFree(prefix); - if (ns != NULL) - return(xmlSetNsProp(node, ns, nqname, value)); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + + if (prefix != NULL) { + res = xmlSearchNsSafe(node, prefix, &ns); + xmlFree(prefix); + if (res < 0) + return(NULL); + if (ns != NULL) + return(xmlSetNsProp(node, ns, localname, value)); } + return(xmlSetNsProp(node, NULL, name, value)); } @@ -7002,11 +6960,22 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, if (ns && (ns->href == NULL)) return(NULL); - prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + if (name == NULL) + return(NULL); + prop = xmlGetPropNodeInternal(node, name, + (ns != NULL) ? ns->href : NULL, 0); if (prop != NULL) { + xmlNodePtr children = NULL; + /* * Modify the attribute's value. */ + if (value != NULL) { + children = xmlNewDocText(node->doc, value); + if (children == NULL) + return(NULL); + } + if (prop->atype == XML_ATTRIBUTE_ID) { xmlRemoveID(node->doc, prop); prop->atype = XML_ATTRIBUTE_ID; @@ -7019,7 +6988,7 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, if (value != NULL) { xmlNodePtr tmp; - prop->children = xmlNewDocText(node->doc, value); + prop->children = children; prop->last = NULL; tmp = prop->children; while (tmp != NULL) { @@ -7029,8 +6998,10 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, tmp = tmp->next; } } - if (prop->atype == XML_ATTRIBUTE_ID) - xmlAddID(NULL, node->doc, value, prop); + if ((prop->atype == XML_ATTRIBUTE_ID) && + (xmlAddIDSafe(prop, value) < 0)) { + return(NULL); + } return(prop); } /* @@ -7089,37 +7060,25 @@ xmlIsBlankNode(const xmlNode *node) { * @content: the content * @len: @content length * - * Concat the given string at the end of the existing node content + * Concat the given string at the end of the existing node content. + * + * If @len is -1, the string length will be calculated. * * Returns -1 in case of error, 0 otherwise */ int xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { - if (node == NULL) return(-1); + if (node == NULL) + return(-1); if ((node->type != XML_TEXT_NODE) && (node->type != XML_CDATA_SECTION_NODE) && (node->type != XML_COMMENT_NODE) && - (node->type != XML_PI_NODE)) { -#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) + (node->type != XML_PI_NODE)) return(-1); - return(0); + + return(xmlTextAddContent(node, content, len)); } /************************************************************************ @@ -7139,16 +7098,13 @@ xmlBufferCreate(void) { xmlBufferPtr ret; ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); - if (ret == NULL) { - xmlTreeErrMemory("creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->size = xmlDefaultBufferSize; ret->alloc = xmlBufferAllocScheme; - ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } @@ -7171,17 +7127,14 @@ xmlBufferCreateSize(size_t size) { if (size >= UINT_MAX) return(NULL); ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); - if (ret == NULL) { - xmlTreeErrMemory("creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->alloc = xmlBufferAllocScheme; ret->size = (size ? size + 1 : 0); /* +1 for ending null */ if (ret->size){ - ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } @@ -7208,8 +7161,6 @@ xmlBufferDetach(xmlBufferPtr buf) { if (buf == NULL) return(NULL); - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) - return(NULL); ret = buf->content; buf->content = NULL; @@ -7225,31 +7176,14 @@ xmlBufferDetach(xmlBufferPtr buf) { * @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. + * Returns an XML buffer initialized with bytes. */ xmlBufferPtr xmlBufferCreateStatic(void *mem, size_t size) { - xmlBufferPtr ret; + xmlBufferPtr buf = xmlBufferCreateSize(size); - if ((mem == NULL) || (size == 0)) - return(NULL); - if (size > UINT_MAX) - 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); + xmlBufferAdd(buf, mem, size); + return(buf); } /** @@ -7263,18 +7197,12 @@ 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 (buf->alloc == XML_BUFFER_ALLOC_IO) return; if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || (scheme == XML_BUFFER_ALLOC_EXACT) || - (scheme == XML_BUFFER_ALLOC_HYBRID) || - (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) + (scheme == XML_BUFFER_ALLOC_HYBRID)) buf->alloc = scheme; } @@ -7288,18 +7216,13 @@ xmlBufferSetAllocationScheme(xmlBufferPtr buf, 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)) { + } else if (buf->content != NULL) { xmlFree(buf->content); } xmlFree(buf); @@ -7316,10 +7239,7 @@ 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)) { + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { size_t start_buf = buf->content - buf->contentIO; buf->size += start_buf; @@ -7346,8 +7266,7 @@ xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { 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))) { + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { /* * we just move the content pointer, but also make sure * the perceived buffer size has shrunk accordingly @@ -7391,13 +7310,10 @@ xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { if (buf == NULL) return(-1); - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); if (len < buf->size - buf->use) return(0); - if (len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if (len >= UINT_MAX - buf->use) return(-1); - } if (buf->size > (size_t) len) { size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2; @@ -7410,18 +7326,14 @@ xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { size_t start_buf = buf->content - buf->contentIO; newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); - if (newbuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (newbuf == NULL) return(-1); - } buf->contentIO = newbuf; buf->content = newbuf + start_buf; } else { newbuf = (xmlChar *) xmlRealloc(buf->content, size); - if (newbuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (newbuf == NULL) return(-1); - } buf->content = newbuf; } buf->size = size; @@ -7441,23 +7353,15 @@ xmlBufferDump(FILE *file, xmlBufferPtr buf) { size_t 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 > INT_MAX ? INT_MAX : (int)ret); + ret = fwrite(buf->content, 1, buf->use, file); + return(ret > INT_MAX ? INT_MAX : ret); } /** @@ -7515,16 +7419,12 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) 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; - if (size > UINT_MAX - 10) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if (size > UINT_MAX - 10) return 0; - } /* figure out new size */ switch (buf->alloc){ @@ -7532,19 +7432,17 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) case XML_BUFFER_ALLOC_DOUBLEIT: /*take care of empty case*/ if (buf->size == 0) - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; else newSize = buf->size; while (size > newSize) { - if (newSize > UINT_MAX / 2) { - xmlTreeErrMemory("growing buffer"); + if (newSize > UINT_MAX / 2) return 0; - } newSize *= 2; } break; case XML_BUFFER_ALLOC_EXACT: - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; break; case XML_BUFFER_ALLOC_HYBRID: if (buf->use < BASE_BUFFER_SIZE) @@ -7552,17 +7450,15 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) else { newSize = buf->size; while (size > newSize) { - if (newSize > UINT_MAX / 2) { - xmlTreeErrMemory("growing buffer"); + if (newSize > UINT_MAX / 2) return 0; - } newSize *= 2; } } break; default: - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; break; } @@ -7577,10 +7473,8 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) buf->size += start_buf; } else { rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); - if (rebuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (rebuf == NULL) return 0; - } buf->contentIO = rebuf; buf->content = rebuf + start_buf; } @@ -7604,10 +7498,8 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) rebuf[buf->use] = 0; } } - if (rebuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (rebuf == NULL) return 0; - } buf->content = rebuf; } buf->size = newSize; @@ -7634,12 +7526,7 @@ xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { 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; @@ -7652,18 +7539,14 @@ xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { /* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { - if ((unsigned) len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if ((unsigned) len >= UINT_MAX - buf->use) return XML_ERR_NO_MEMORY; - } needSize = buf->use + len + 1; - if (!xmlBufferResize(buf, needSize)){ - xmlTreeErrMemory("growing buffer"); + if (!xmlBufferResize(buf, needSize)) return XML_ERR_NO_MEMORY; - } } - memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); + memmove(&buf->content[buf->use], str, len); buf->use += len; buf->content[buf->use] = 0; return 0; @@ -7687,19 +7570,10 @@ xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { 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; @@ -7726,15 +7600,11 @@ xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { } /* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { - if ((unsigned) len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if ((unsigned) len >= UINT_MAX - buf->use) return(-1); - } needSize = buf->use + len + 1; - if (!xmlBufferResize(buf, needSize)){ - xmlTreeErrMemory("growing buffer"); - return XML_ERR_NO_MEMORY; - } + if (!xmlBufferResize(buf, needSize)) + return(-1); } memmove(&buf->content[len], &buf->content[0], buf->use); @@ -7758,7 +7628,6 @@ 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); } @@ -7790,7 +7659,6 @@ void xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { if (buf == NULL) return; - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; xmlBufferCat(buf, string); } @@ -7806,7 +7674,6 @@ void xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { if (buf == NULL) return; - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; xmlBufferCCat(buf, string); } @@ -7825,13 +7692,8 @@ 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){ @@ -7895,6 +7757,8 @@ xmlSetDocCompressMode (xmlDocPtr doc, int mode) { /** * xmlGetCompressMode: * + * DEPRECATED: Use xmlGetDocCompressMode + * * get the default compression mode used, ZLIB based. * Returns 0 (uncompressed) to 9 (max compression) */ @@ -7908,6 +7772,8 @@ xmlGetCompressMode(void) * xmlSetCompressMode: * @mode: the compression ratio * + * DEPRECATED: Use xmlSetDocCompressMode + * * set the default compression mode used, ZLIB based * Correct values: 0 (uncompressed) to 9 (max compression) */ @@ -8015,10 +7881,8 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, * Create the ns-map. */ map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); - if (map == NULL) { - xmlTreeErrMemory("allocating namespace map"); - return (NULL); - } + if (map == NULL) + return(NULL); memset(map, 0, sizeof(struct xmlNsMap)); *nsmap = map; } @@ -8035,10 +7899,8 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, * Create a new item. */ ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); - if (ret == NULL) { - xmlTreeErrMemory("allocating namespace map item"); - return (NULL); - } + if (ret == NULL) + return(NULL); memset(ret, 0, sizeof(struct xmlNsMapItem)); } @@ -8130,10 +7992,8 @@ xmlDOMWrapNewCtxt(void) xmlDOMWrapCtxtPtr ret; ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); - if (ret == NULL) { - xmlTreeErrMemory("allocating DOM-wrapper context"); + if (ret == NULL) return (NULL); - } memset(ret, 0, sizeof(xmlDOMWrapCtxt)); return (ret); } @@ -8249,39 +8109,6 @@ xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, return (0); } -/* -* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; -* otherwise copy it, when it was in the source-dict. -*/ -#define XML_TREE_ADOPT_STR(str) \ - if (adoptStr && (str != NULL)) { \ - if (destDoc->dict) { \ - const xmlChar *old = str; \ - str = xmlDictLookup(destDoc->dict, str, -1); \ - if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ - (!xmlDictOwns(sourceDoc->dict, old))) \ - xmlFree((char *)old); \ - } else if ((sourceDoc) && (sourceDoc->dict) && \ - xmlDictOwns(sourceDoc->dict, str)) { \ - str = BAD_CAST xmlStrdup(str); \ - } \ - } - -/* -* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then -* put it in dest-dict or copy it. -*/ -#define XML_TREE_ADOPT_STR_2(str) \ - if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ - (sourceDoc->dict != NULL) && \ - xmlDictOwns(sourceDoc->dict, cur->content)) { \ - if (destDoc->dict) \ - cur->content = (xmlChar *) \ - xmlDictLookup(destDoc->dict, cur->content, -1); \ - else \ - cur->content = xmlStrdup(BAD_CAST cur->content); \ - } - /* * xmlDOMWrapNSNormAddNsMapItem2: * @@ -8293,23 +8120,18 @@ static int xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, xmlNsPtr oldNs, xmlNsPtr newNs) { - if (*list == NULL) { - *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); - if (*list == NULL) { - xmlTreeErrMemory("alloc ns map item"); - return(-1); - } - *size = 3; - *number = 0; - } else if ((*number) >= (*size)) { - *size *= 2; - *list = (xmlNsPtr *) xmlRealloc(*list, - (*size) * 2 * sizeof(xmlNsPtr)); - if (*list == NULL) { - xmlTreeErrMemory("realloc ns map item"); - return(-1); - } + if (*number >= *size) { + xmlNsPtr *tmp; + size_t newSize; + + newSize = *size ? *size * 2 : 3; + tmp = xmlRealloc(*list, newSize * 2 * sizeof(tmp[0])); + if (tmp == NULL) + return(-1); + *list = tmp; + *size = newSize; } + (*list)[2 * (*number)] = oldNs; (*list)[2 * (*number) +1] = newNs; (*number)++; @@ -8338,7 +8160,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr node, int options ATTRIBUTE_UNUSED) { xmlNsPtr *list = NULL; - int sizeList, nbList, i, j; + int sizeList = 0, nbList = 0, ret = 0, i, j; xmlNsPtr ns; if ((node == NULL) || (doc == NULL) || (node->doc != doc)) @@ -8354,7 +8176,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node); return (0); case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -8362,7 +8184,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, default: return (1); } - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node); /* * Save out-of-scope ns-references in doc->oldNs. */ @@ -8374,7 +8196,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, do { if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, ns, ns) == -1) - goto internal_error; + ret = -1; ns = ns->next; } while (ns != NULL); } @@ -8404,7 +8226,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, ns = xmlDOMWrapStoreNs(doc, node->ns->href, node->ns->prefix); if (ns == NULL) - goto internal_error; + ret = -1; } if (ns != NULL) { /* @@ -8412,7 +8234,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, */ if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, node->ns, ns) == -1) - goto internal_error; + ret = -1; } node->ns = ns; } @@ -8437,19 +8259,22 @@ next_sibling: if (node->next != NULL) node = node->next; else { + int type = node->type; + node = node->parent; - goto next_sibling; + if ((type == XML_ATTRIBUTE_NODE) && + (node != NULL) && + (node->children != NULL)) { + node = node->children; + } else { + goto next_sibling; + } } } while (node != NULL); if (list != NULL) xmlFree(list); - return (0); - -internal_error: - if (list != NULL) - xmlFree(list); - return (-1); + return (ret); } /* @@ -8547,8 +8372,7 @@ xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, out = prev; prev = cur; } - } else if ((cur->type == XML_ENTITY_NODE) || - (cur->type == XML_ENTITY_DECL)) + } else if (cur->type == XML_ENTITY_DECL) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); @@ -8610,8 +8434,7 @@ xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, ns = ns->next; } while (ns != NULL); } - } else if ((cur->type == XML_ENTITY_NODE) || - (cur->type == XML_ENTITY_DECL)) + } else if (cur->type == XML_ENTITY_DECL) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); @@ -8795,7 +8618,6 @@ xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc, */ if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, XML_TREE_NSMAP_DOC) == NULL) { - xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; @@ -8825,7 +8647,6 @@ xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc, } } if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { - xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; @@ -8870,7 +8691,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, int optRemoveRedundantNS = ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; xmlNsPtr *listRedund = NULL; - int sizeRedund = 0, nbRedund = 0, ret, i, j; + int sizeRedund = 0, nbRedund = 0, ret = 0, i, j; if ((elem == NULL) || (elem->doc == NULL) || (elem->type != XML_ELEMENT_NODE)) @@ -8899,7 +8720,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) - goto internal_error; + ret = -1; } parnsdone = 1; } @@ -8921,16 +8742,18 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, * Add it to the list of redundant ns-decls. */ if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, - &sizeRedund, &nbRedund, ns, mi->newNs) == -1) - goto internal_error; - /* - * Remove the ns-decl from the element-node. - */ - if (prevns) - prevns->next = ns->next; - else - cur->nsDef = ns->next; - goto next_ns_decl; + &sizeRedund, &nbRedund, ns, mi->newNs) == -1) { + ret = -1; + } else { + /* + * Remove the ns-decl from the element-node. + */ + if (prevns) + prevns->next = ns->next; + else + cur->nsDef = ns->next; + goto next_ns_decl; + } } } } @@ -8960,7 +8783,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) - goto internal_error; + ret = -1; prevns = ns; next_ns_decl: @@ -8980,7 +8803,7 @@ next_ns_decl: ((xmlNodePtr) elem->parent->doc != elem->parent)) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) - goto internal_error; + ret = -1; } parnsdone = 1; } @@ -9019,7 +8842,7 @@ next_ns_decl: &nsMap, depth, ancestorsOnly, (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) - goto internal_error; + ret = -1; cur->ns = ns; ns_end: @@ -9079,11 +8902,6 @@ next_sibling: } } while (cur != NULL); - ret = 0; - goto exit; -internal_error: - ret = -1; -exit: if (listRedund) { for (i = 0, j = 0; i < nbRedund; i++, j += 2) { xmlFreeNs(listRedund[j]); @@ -9119,7 +8937,7 @@ exit: */ static int xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, - xmlDocPtr sourceDoc, + xmlDocPtr sourceDoc ATTRIBUTE_UNUSED, xmlNodePtr node, xmlDocPtr destDoc, xmlNodePtr destParent, @@ -9130,21 +8948,12 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns = NULL; - int depth = -1, adoptStr = 1; + int depth = -1; /* gather @parent's ns-decls. */ int parnsdone; /* @ancestorsOnly should be set per option. */ int ancestorsOnly = 0; - /* - * Optimize string adoption for equal or none dicts. - */ - if ((sourceDoc != NULL) && - (sourceDoc->dict == destDoc->dict)) - adoptStr = 0; - else - adoptStr = 1; - /* * Get the ns-map from the context if available. */ @@ -9164,40 +8973,21 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, parnsdone = 0; cur = node; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - goto internal_error; while (cur != NULL) { - /* - * Paranoid source-doc sanity check. - */ - if (cur->doc != sourceDoc) { - /* - * We'll assume XIncluded nodes if the doc differs. - * TODO: Do we need to reconciliate XIncluded nodes? - * This here skips XIncluded nodes and tries to handle - * broken sequences. - */ - if (cur->next == NULL) - goto leave_node; - do { - cur = cur->next; - if ((cur->type == XML_XINCLUDE_END) || - (cur->doc == node->doc)) - break; - } while (cur->next != NULL); + if (cur->doc != destDoc) { + if (xmlNodeSetDoc(cur, destDoc) < 0) + ret = -1; + } - if (cur->doc != node->doc) - goto leave_node; - } - cur->doc = destDoc; switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* * TODO */ - return (-1); + ret = -1; + goto leave_node; case XML_ELEMENT_NODE: curElem = cur; depth++; @@ -9218,14 +9008,12 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) - goto internal_error; + ret = -1; parnsdone = 1; } for (ns = cur->nsDef; ns != NULL; ns = ns->next) { /* * NOTE: ns->prefix and ns->href are never in the dict. - * XML_TREE_ADOPT_STR(ns->prefix) - * XML_TREE_ADOPT_STR(ns->href) */ /* * Does it shadow any ns-decl? @@ -9247,7 +9035,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) - goto internal_error; + ret = -1; } } /* Falls through. */ @@ -9259,7 +9047,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, if (! parnsdone) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) - goto internal_error; + ret = -1; parnsdone = 1; } /* @@ -9293,7 +9081,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) - goto internal_error; + ret = -1; cur->ns = ns; } else { /* @@ -9307,15 +9095,11 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, ancestorsOnly, /* ns-decls must be prefixed for attributes. */ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) - goto internal_error; + ret = -1; cur->ns = ns; } + ns_end: - /* - * Further node properties. - * TODO: Is this all? - */ - XML_TREE_ADOPT_STR(cur->name) if (cur->type == XML_ELEMENT_NODE) { cur->psvi = NULL; cur->line = 0; @@ -9330,55 +9114,16 @@ ns_end: cur = (xmlNodePtr) cur->properties; continue; } - } else { - /* - * Attributes. - */ - if ((sourceDoc != NULL) && - (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) - { - xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); - } - ((xmlAttrPtr) cur)->atype = 0; - ((xmlAttrPtr) cur)->psvi = NULL; } break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - /* - * This puts the content in the dest dict, only if - * it was previously in the source dict. - */ - XML_TREE_ADOPT_STR_2(cur->content) - goto leave_node; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - cur->content = NULL; - cur->children = NULL; - cur->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, cur->name); - if (ent != NULL) { - cur->content = ent->content; - cur->children = (xmlNodePtr) ent; - cur->last = (xmlNodePtr) ent; - } - } - goto leave_node; case XML_PI_NODE: - XML_TREE_ADOPT_STR(cur->name) - XML_TREE_ADOPT_STR_2(cur->content) - break; case XML_COMMENT_NODE: - break; + case XML_ENTITY_REF_NODE: + goto leave_node; default: - goto internal_error; + ret = -1; } /* * Walk the tree. @@ -9429,12 +9174,6 @@ leave_node: } } - goto exit; - -internal_error: - ret = -1; - -exit: /* * Cleanup. */ @@ -9496,7 +9235,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, int options ATTRIBUTE_UNUSED) { int ret = 0; - xmlNodePtr cur, curElem = NULL; + xmlNodePtr cur, cloneElem = NULL; xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns; @@ -9514,7 +9253,8 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; xmlDictPtr dict; /* The destination dict */ - if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) + if ((node == NULL) || (resNode == NULL) || (destDoc == NULL) || + ((destParent != NULL) && (destParent->doc != destDoc))) return(-1); /* * TODO: Initially we support only element-nodes. @@ -9546,9 +9286,6 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, *resNode = NULL; cur = node; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - return(-1); - while (cur != NULL) { if (cur->doc != sourceDoc) { /* @@ -9576,15 +9313,12 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, case XML_PI_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: /* * Nodes of xmlNode structure. */ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); + if (clone == NULL) goto internal_error; - } memset(clone, 0, sizeof(xmlNode)); /* * Set hierarchical links. @@ -9596,6 +9330,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, clone->prev = prevClone; } else parentClone->children = clone; + parentClone->last = clone; } else resultClone = clone; @@ -9604,11 +9339,10 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, /* * Attributes (xmlAttr). */ - clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); - if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); + /* Use xmlRealloc to avoid -Warray-bounds warning */ + clone = (xmlNodePtr) xmlRealloc(NULL, sizeof(xmlAttr)); + if (clone == NULL) goto internal_error; - } memset(clone, 0, sizeof(xmlAttr)); /* * Set hierarchical links. @@ -9649,7 +9383,12 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, else if (cur->name == xmlStringComment) clone->name = xmlStringComment; else if (cur->name != NULL) { - DICT_CONST_COPY(cur->name, clone->name); + if (dict != NULL) + clone->name = xmlDictLookup(dict, cur->name, -1); + else + clone->name = xmlStrdup(cur->name); + if (clone->name == NULL) + goto internal_error; } switch (cur->type) { @@ -9660,7 +9399,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ return (-1); case XML_ELEMENT_NODE: - curElem = cur; + cloneElem = clone; depth++; /* * Namespace declarations. @@ -9686,18 +9425,25 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, * Create a new xmlNs. */ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cloneNs == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): " - "allocating namespace"); - return(-1); - } + if (cloneNs == NULL) + goto internal_error; memset(cloneNs, 0, sizeof(xmlNs)); cloneNs->type = XML_LOCAL_NAMESPACE; - if (ns->href != NULL) + if (ns->href != NULL) { cloneNs->href = xmlStrdup(ns->href); - if (ns->prefix != NULL) + if (cloneNs->href == NULL) { + xmlFreeNs(cloneNs); + goto internal_error; + } + } + if (ns->prefix != NULL) { cloneNs->prefix = xmlStrdup(ns->prefix); + if (cloneNs->prefix == NULL) { + xmlFreeNs(cloneNs); + goto internal_error; + } + } *cloneNsDefSlot = cloneNs; cloneNsDefSlot = &(cloneNs->next); @@ -9743,15 +9489,18 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, /* IDs will be processed further down. */ /* cur->ns will be processed further down. */ break; + case XML_PI_NODE: + case XML_COMMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: /* * Note that this will also cover the values of attributes. */ - DICT_COPY(cur->content, clone->content); - goto leave_node; - case XML_ENTITY_NODE: - /* TODO: What to do here? */ + if (cur->content != NULL) { + clone->content = xmlStrdup(cur->content); + if (clone->content == NULL) + goto internal_error; + } goto leave_node; case XML_ENTITY_REF_NODE: if (sourceDoc != destDoc) { @@ -9777,12 +9526,6 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, clone->last = cur->last; } goto leave_node; - case XML_PI_NODE: - DICT_COPY(cur->content, clone->content); - goto leave_node; - case XML_COMMENT_NODE: - DICT_COPY(cur->content, clone->content); - goto leave_node; default: goto internal_error; } @@ -9842,8 +9585,8 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, * Acquire a normalized ns-decl and add it to the map. */ if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc, - /* ns-decls on curElem or on destDoc->oldNs */ - destParent ? curElem : NULL, + /* ns-decls on cloneElem or on destDoc->oldNs */ + destParent ? cloneElem : NULL, cur->ns, &ns, &nsMap, depth, /* if we need to search only in the ancestor-axis */ @@ -9864,19 +9607,22 @@ end_ns_reference: if ((clone->type == XML_ATTRIBUTE_NODE) && (clone->parent != NULL)) { - if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { + int res; + res = xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone); + if (res < 0) + goto internal_error; + if (res == 1) { xmlChar *idVal; - idVal = xmlNodeListGetString(cur->doc, cur->children, 1); - if (idVal != NULL) { - if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { - /* TODO: error message. */ - xmlFree(idVal); - goto internal_error; - } - xmlFree(idVal); - } + idVal = xmlNodeGetContent(cur); + if (idVal == NULL) + goto internal_error; + if (xmlAddIDSafe((xmlAttrPtr) cur, idVal) < 0) { + xmlFree(idVal); + goto internal_error; + } + xmlFree(idVal); } } /* @@ -9941,11 +9687,6 @@ leave_node: prevClone = clone; cur = cur->next; } else if (cur->type != XML_ATTRIBUTE_NODE) { - /* - * Set clone->last. - */ - if (clone->parent != NULL) - clone->parent->last = clone; clone = clone->parent; if (clone != NULL) parentClone = clone->parent; @@ -10014,19 +9755,22 @@ exit: */ static int xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, - xmlDocPtr sourceDoc, + xmlDocPtr sourceDoc ATTRIBUTE_UNUSED, xmlAttrPtr attr, xmlDocPtr destDoc, xmlNodePtr destParent, int options ATTRIBUTE_UNUSED) { - xmlNodePtr cur; - int adoptStr = 1; + int ret = 0; if ((attr == NULL) || (destDoc == NULL)) return (-1); - attr->doc = destDoc; + if (attr->doc != destDoc) { + if (xmlSetTreeDoc((xmlNodePtr) attr, destDoc) < 0) + ret = -1; + } + if (attr->ns != NULL) { xmlNsPtr ns = NULL; @@ -10047,75 +9791,18 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, */ if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, &ns, 1) == -1) - goto internal_error; + ret = -1; if (ns == NULL) { ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, attr->ns->href, attr->ns->prefix, 1); } } if (ns == NULL) - goto internal_error; + ret = -1; attr->ns = ns; } - XML_TREE_ADOPT_STR(attr->name); - attr->atype = 0; - attr->psvi = NULL; - /* - * Walk content. - */ - if (attr->children == NULL) - return (0); - cur = attr->children; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - goto internal_error; - while (cur != NULL) { - cur->doc = destDoc; - switch (cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - XML_TREE_ADOPT_STR_2(cur->content) - break; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - cur->content = NULL; - cur->children = NULL; - cur->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, cur->name); - if (ent != NULL) { - cur->content = ent->content; - cur->children = (xmlNodePtr) ent; - cur->last = (xmlNodePtr) ent; - } - } - break; - default: - break; - } - if (cur->children != NULL) { - cur = cur->children; - continue; - } -next_sibling: - if (cur == (xmlNodePtr) attr) - break; - if (cur->next != NULL) - cur = cur->next; - else { - cur = cur->parent; - goto next_sibling; - } - } - return (0); -internal_error: - return (-1); + return (ret); } /* @@ -10153,6 +9840,8 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, xmlNodePtr destParent, int options) { + int ret = 0; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (destDoc == NULL) || ((destParent != NULL) && (destParent->doc != destDoc))) @@ -10160,17 +9849,18 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, /* * Check node->doc sanity. */ - if ((node->doc != NULL) && (sourceDoc != NULL) && - (node->doc != sourceDoc)) { - /* - * Might be an XIncluded node. - */ + if (sourceDoc == NULL) { + sourceDoc = node->doc; + } else if (node->doc != sourceDoc) { return (-1); } - if (sourceDoc == NULL) - sourceDoc = node->doc; + + /* + * TODO: Shouldn't this be allowed? + */ if (sourceDoc == destDoc) return (-1); + switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -10190,7 +9880,7 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, * Unlink only if @node was not already added to @destParent. */ if ((node->parent != NULL) && (destParent != node->parent)) - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node); if (node->type == XML_ELEMENT_NODE) { return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, @@ -10199,51 +9889,102 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, (xmlAttrPtr) node, destDoc, destParent, options)); } else { - xmlNodePtr cur = node; - int adoptStr = 1; + if (node->doc != destDoc) { + if (xmlNodeSetDoc(node, destDoc) < 0) + ret = -1; + } + } + return (ret); +} - cur->doc = destDoc; - /* - * Optimize string adoption. - */ - if ((sourceDoc != NULL) && - (sourceDoc->dict == destDoc->dict)) - adoptStr = 0; - switch (node->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - XML_TREE_ADOPT_STR_2(node->content) - break; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - node->content = NULL; - node->children = NULL; - node->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, node->name); - if (ent != NULL) { - node->content = ent->content; - node->children = (xmlNodePtr) ent; - node->last = (xmlNodePtr) ent; - } - } - XML_TREE_ADOPT_STR(node->name) - break; - case XML_PI_NODE: { - XML_TREE_ADOPT_STR(node->name) - XML_TREE_ADOPT_STR_2(node->content) - break; - } - default: - break; - } +/************************************************************************ + * * + * 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" + +/** + * 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); } - return (0); + 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); +} + +/************************************************************************ + * * + * Node callbacks * + * * + ************************************************************************/ + +/** + * xmlRegisterNodeDefault: + * @func: function pointer to the new RegisterNodeFunc + * + * DEPRECATED: don't use + * + * Registers a callback for node creation + * + * Returns the old value of the registration function + */ +xmlRegisterNodeFunc +xmlRegisterNodeDefault(xmlRegisterNodeFunc func) +{ + xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue; + + __xmlRegisterCallbacks = 1; + xmlRegisterNodeDefaultValue = func; + return(old); +} + +/** + * xmlDeregisterNodeDefault: + * @func: function pointer to the new DeregisterNodeFunc + * + * DEPRECATED: don't use + * + * Registers a callback for node destruction + * + * Returns the previous value of the deregistration function + */ +xmlDeregisterNodeFunc +xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func) +{ + xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue; + + __xmlRegisterCallbacks = 1; + xmlDeregisterNodeDefaultValue = func; + return(old); } diff --git a/triodef.h b/triodef.h deleted file mode 100644 index e101f6df560..00000000000 --- a/triodef.h +++ /dev/null @@ -1,228 +0,0 @@ -/************************************************************************* - * - * $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 - * MERCHANTABILITY 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(__OS400__) -# define TRIO_PLATFORM_OS400 -#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 -#elif defined(TRIO_COMPILER_XLC) && defined(__EXTENDED__) -# define TRIO_COMPILER_SUPPORTS_C89 -# define TRIO_COMPILER_SUPPORTS_C90 -# define TRIO_COMPILER_SUPPORTS_C94 -#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/trionan.c b/trionan.c deleted file mode 100644 index 8767a9fe648..00000000000 --- a/trionan.c +++ /dev/null @@ -1,914 +0,0 @@ -/************************************************************************* - * - * $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 - * MERCHANTABILITY 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 (amongst 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 - * endianness by the compiler, which means that we can support any - * kind of endianness. 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/trionan.h b/trionan.h deleted file mode 100644 index eac0e6f1686..00000000000 --- a/trionan.h +++ /dev/null @@ -1,84 +0,0 @@ -/************************************************************************* - * - * $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 - * MERCHANTABILITY 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/uri.c b/uri.c index e5c790ebd91..3b986532aec 100644 --- a/uri.c +++ b/uri.c @@ -16,9 +16,10 @@ #include #include -#include #include +#include "private/error.h" + /** * MAX_URI_LENGTH: * @@ -33,22 +34,8 @@ */ #define MAX_URI_LENGTH 1024 * 1024 -static void -xmlURIErrMemory(const char *extra) -{ - if (extra) - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_URI, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_URI, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); -} +#define PORT_EMPTY 0 +#define PORT_EMPTY_SERVER -1 static void xmlCleanURI(xmlURIPtr uri); @@ -64,7 +51,6 @@ static void xmlCleanURI(xmlURIPtr uri); * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | * "u" | "v" | "w" | "x" | "y" | "z" */ - #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z')) /* @@ -85,7 +71,6 @@ static void xmlCleanURI(xmlURIPtr uri); /* * alphanum = alpha | digit */ - #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x)) /* @@ -99,16 +84,15 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unwise = "{" | "}" | "|" | "\" | "^" | "`" */ - #define IS_UNWISE(p) \ (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \ ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \ ((*(p) == ']')) || ((*(p) == '`'))) + /* * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," | * "[" | "]" */ - #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \ ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \ ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \ @@ -117,13 +101,11 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unreserved = alphanum | mark */ - #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x)) /* * Skip to next pointer char, handle escaped sequences */ - #define NEXT(p) ((*p == '%')? p += 3 : p++) /* @@ -135,7 +117,6 @@ static void xmlCleanURI(xmlURIPtr uri); * * path = [ abs_path | opaque_part ] */ - #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n)) /************************************************************************ @@ -177,7 +158,7 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" */ -#define ISA_UNRESERVED(p) \ +#define ISA_STRICTLY_UNRESERVED(p) \ ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \ ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~'))) @@ -190,10 +171,47 @@ static void xmlCleanURI(xmlURIPtr uri); /* * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ -#define ISA_PCHAR(p) \ - (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ +#define ISA_PCHAR(u, p) \ + (ISA_UNRESERVED(u, p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ ((*(p) == ':')) || ((*(p) == '@'))) +/* + * From https://www.w3.org/TR/leiri/ + * + * " " / "<" / ">" / '"' / "{" / "}" / "|" + * / "\" / "^" / "`" / %x0-1F / %x7F-D7FF + * / %xE000-FFFD / %x10000-10FFFF + */ +#define ISA_UCSCHAR(p) \ + ((*(p) <= 0x20) || (*(p) >= 0x7F) || (*(p) == '<') || (*(p) == '>') || \ + (*(p) == '"') || (*(p) == '{') || (*(p) == '}') || (*(p) == '|') || \ + (*(p) == '\\') || (*(p) == '^') || (*(p) == '`')) + +#define ISA_UNRESERVED(u, p) (xmlIsUnreserved(u, p)) + +#define XML_URI_ALLOW_UNWISE 1 +#define XML_URI_NO_UNESCAPE 2 +#define XML_URI_ALLOW_UCSCHAR 4 + +static int +xmlIsUnreserved(xmlURIPtr uri, const char *cur) { + if (uri == NULL) + return(0); + + if (ISA_STRICTLY_UNRESERVED(cur)) + return(1); + + if (uri->cleanup & XML_URI_ALLOW_UNWISE) { + if (IS_UNWISE(cur)) + return(1); + } else if (uri->cleanup & XML_URI_ALLOW_UCSCHAR) { + if (ISA_UCSCHAR(cur)) + return(1); + } + + return(0); +} + /** * xmlParse3986Scheme: * @uri: pointer to an URI structure @@ -209,18 +227,17 @@ static int xmlParse3986Scheme(xmlURIPtr uri, const char **str) { const char *cur; - if (str == NULL) - return(-1); - cur = *str; if (!ISA_ALPHA(cur)) - return(2); + return(1); cur++; while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++; if (uri != NULL) { if (uri->scheme != NULL) xmlFree(uri->scheme); uri->scheme = STRNDUP(*str, cur - *str); + if (uri->scheme == NULL) + return(-1); } *str = cur; return(0); @@ -246,22 +263,20 @@ xmlParse3986Fragment(xmlURIPtr uri, const char **str) { const char *cur; - if (str == NULL) - return (-1); - cur = *str; - while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || - (*cur == '[') || (*cur == ']') || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?') || + (*cur == '[') || (*cur == ']')) NEXT(cur); if (uri != NULL) { if (uri->fragment != NULL) xmlFree(uri->fragment); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->fragment = STRNDUP(*str, cur - *str); else uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->fragment == NULL) + return (-1); } *str = cur; return (0); @@ -283,21 +298,19 @@ xmlParse3986Query(xmlURIPtr uri, const char **str) { const char *cur; - if (str == NULL) - return (-1); - cur = *str; - while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?')) NEXT(cur); if (uri != NULL) { if (uri->query != NULL) xmlFree(uri->query); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->query = STRNDUP(*str, cur - *str); else uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->query == NULL) + return (-1); /* Save the raw bytes of the query as well. * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114 @@ -305,6 +318,8 @@ xmlParse3986Query(xmlURIPtr uri, const char **str) if (uri->query_raw != NULL) xmlFree (uri->query_raw); uri->query_raw = STRNDUP (*str, cur - *str); + if (uri->query_raw == NULL) + return (-1); } *str = cur; return (0); @@ -367,16 +382,18 @@ xmlParse3986Userinfo(xmlURIPtr uri, const char **str) const char *cur; cur = *str; - while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || + while (ISA_UNRESERVED(uri, cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) || (*cur == ':')) NEXT(cur); if (*cur == '@') { if (uri != NULL) { if (uri->user != NULL) xmlFree(uri->user); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->user = STRNDUP(*str, cur - *str); else uri->user = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->user == NULL) + return(-1); } *str = cur; return(0); @@ -481,7 +498,8 @@ not_ipv4: /* * then this should be a hostname which can be empty */ - while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) + while (ISA_UNRESERVED(uri, cur) || + ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) NEXT(cur); found: if (uri != NULL) { @@ -489,10 +507,12 @@ found: uri->authority = NULL; if (uri->server != NULL) xmlFree(uri->server); if (cur != host) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->server = STRNDUP(host, cur - host); else uri->server = xmlURIUnescapeString(host, cur - host, NULL); + if (uri->server == NULL) + return(-1); } else uri->server = NULL; } @@ -523,6 +543,8 @@ xmlParse3986Authority(xmlURIPtr uri, const char **str) * try to parse an userinfo and check for the trailing @ */ ret = xmlParse3986Userinfo(uri, &cur); + if (ret < 0) + return(ret); if ((ret != 0) || (*cur != '@')) cur = *str; else @@ -555,17 +577,17 @@ xmlParse3986Authority(xmlURIPtr uri, const char **str) * Returns 0 or the error code */ static int -xmlParse3986Segment(const char **str, char forbid, int empty) +xmlParse3986Segment(xmlURIPtr uri, const char **str, char forbid, int empty) { const char *cur; cur = *str; - if (!ISA_PCHAR(cur)) { + if (!ISA_PCHAR(uri, cur)) { if (empty) return(0); return(1); } - while (ISA_PCHAR(cur) && (*cur != forbid)) + while (ISA_PCHAR(uri, cur) && (*cur != forbid)) NEXT(cur); *str = cur; return (0); @@ -593,16 +615,18 @@ xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str) while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (*str != cur) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -634,21 +658,23 @@ xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str) if (*cur != '/') return(1); cur++; - ret = xmlParse3986Segment(&cur, 0, 0); + ret = xmlParse3986Segment(uri, &cur, 0, 0); if (ret == 0) { while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -677,20 +703,22 @@ xmlParse3986PathRootless(xmlURIPtr uri, const char **str) cur = *str; - ret = xmlParse3986Segment(&cur, 0, 0); + ret = xmlParse3986Segment(uri, &cur, 0, 0); if (ret != 0) return(ret); while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -719,20 +747,22 @@ xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str) cur = *str; - ret = xmlParse3986Segment(&cur, ':', 0); + ret = xmlParse3986Segment(uri, &cur, ':', 0); if (ret != 0) return(ret); while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -768,8 +798,11 @@ xmlParse3986HierPart(xmlURIPtr uri, const char **str) cur += 2; ret = xmlParse3986Authority(uri, &cur); if (ret != 0) return(ret); - if (uri->server == NULL) - uri->port = -1; + /* + * An empty server is marked with a special URI value. + */ + if ((uri->server == NULL) && (uri->port == PORT_EMPTY)) + uri->port = PORT_EMPTY_SERVER; ret = xmlParse3986PathAbEmpty(uri, &cur); if (ret != 0) return(ret); *str = cur; @@ -777,7 +810,7 @@ xmlParse3986HierPart(xmlURIPtr uri, const char **str) } else if (*cur == '/') { ret = xmlParse3986PathAbsolute(uri, &cur); if (ret != 0) return(ret); - } else if (ISA_PCHAR(cur)) { + } else if (ISA_PCHAR(uri, cur)) { ret = xmlParse3986PathRootless(uri, &cur); if (ret != 0) return(ret); } else { @@ -820,7 +853,7 @@ xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) { } else if (*str == '/') { ret = xmlParse3986PathAbsolute(uri, &str); if (ret != 0) return(ret); - } else if (ISA_PCHAR(str)) { + } else if (ISA_PCHAR(uri, str)) { ret = xmlParse3986PathNoScheme(uri, &str); if (ret != 0) return(ret); } else { @@ -915,6 +948,8 @@ xmlParse3986URIReference(xmlURIPtr uri, const char *str) { * it fails. */ ret = xmlParse3986URI(uri, str); + if (ret < 0) + return(ret); if (ret != 0) { xmlCleanURI(uri); ret = xmlParse3986RelativeRef(uri, str); @@ -927,30 +962,58 @@ xmlParse3986URIReference(xmlURIPtr uri, const char *str) { } /** - * xmlParseURI: + * xmlParseURISafe: * @str: the URI string to analyze + * @uriOut: optional pointer to parsed URI * * Parse an URI based on RFC 3986 * * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] * - * Returns a newly built xmlURIPtr or NULL in case of error + * Available since 2.13.0. + * + * Returns 0 on success, an error code (typically 1) if the URI is invalid + * or -1 if a memory allocation failed. */ -xmlURIPtr -xmlParseURI(const char *str) { +int +xmlParseURISafe(const char *str, xmlURIPtr *uriOut) { xmlURIPtr uri; int ret; + if (uriOut == NULL) + return(1); + *uriOut = NULL; if (str == NULL) - return(NULL); + return(1); + uri = xmlCreateURI(); - if (uri != NULL) { - ret = xmlParse3986URIReference(uri, str); - if (ret) { - xmlFreeURI(uri); - return(NULL); - } + if (uri == NULL) + return(-1); + + ret = xmlParse3986URIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(ret); } + + *uriOut = uri; + return(0); +} + +/** + * xmlParseURI: + * @str: the URI string to analyze + * + * Parse an URI based on RFC 3986 + * + * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] + * + * Returns a newly built xmlURIPtr or NULL in case of error + */ +xmlURIPtr +xmlParseURI(const char *str) { + xmlURIPtr uri; + xmlParseURISafe(str, &uri); return(uri); } @@ -992,7 +1055,7 @@ xmlParseURIRaw(const char *str, int raw) { uri = xmlCreateURI(); if (uri != NULL) { if (raw) { - uri->cleanup |= 2; + uri->cleanup |= XML_URI_NO_UNESCAPE; } ret = xmlParseURIReference(uri, str); if (ret) { @@ -1021,11 +1084,10 @@ xmlCreateURI(void) { xmlURIPtr ret; ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI)); - if (ret == NULL) { - xmlURIErrMemory("creating URI structure\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlURI)); + ret->port = PORT_EMPTY; return(ret); } @@ -1040,16 +1102,12 @@ xmlSaveUriRealloc(xmlChar *ret, int *max) { xmlChar *temp; int tmp; - if (*max > MAX_URI_LENGTH) { - xmlURIErrMemory("reaching arbitrary MAX_URI_LENGTH limit\n"); + if (*max > MAX_URI_LENGTH) return(NULL); - } tmp = *max * 2; temp = (xmlChar *) xmlRealloc(ret, (tmp + 1)); - if (temp == NULL) { - xmlURIErrMemory("saving URI\n"); + if (temp == NULL) return(NULL); - } *max = tmp; return(temp); } @@ -1074,11 +1132,9 @@ xmlSaveUri(xmlURIPtr uri) { max = 80; - ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar)); - if (ret == NULL) { - xmlURIErrMemory("saving URI\n"); + ret = (xmlChar *) xmlMallocAtomic(max + 1); + if (ret == NULL) return(NULL); - } len = 0; if (uri->scheme != NULL) { @@ -1117,7 +1173,7 @@ xmlSaveUri(xmlURIPtr uri) { } } } else { - if ((uri->server != NULL) || (uri->port == -1)) { + if ((uri->server != NULL) || (uri->port != PORT_EMPTY)) { if (len + 3 >= max) { temp = xmlSaveUriRealloc(ret, &max); if (temp == NULL) goto mem_error; @@ -1162,17 +1218,18 @@ xmlSaveUri(xmlURIPtr uri) { if (temp == NULL) goto mem_error; ret = temp; } - ret[len++] = *p++; - } - if (uri->port > 0) { - if (len + 10 >= max) { - temp = xmlSaveUriRealloc(ret, &max); - if (temp == NULL) goto mem_error; - ret = temp; - } - len += snprintf((char *) &ret[len], max - len, ":%d", uri->port); + /* TODO: escaping? */ + ret[len++] = (xmlChar) *p++; } } + if (uri->port > 0) { + if (len + 10 >= max) { + temp = xmlSaveUriRealloc(ret, &max); + if (temp == NULL) goto mem_error; + ret = temp; + } + len += snprintf((char *) &ret[len], max - len, ":%d", uri->port); + } } else if (uri->authority != NULL) { if (len + 3 >= max) { temp = xmlSaveUriRealloc(ret, &max); @@ -1405,195 +1462,136 @@ xmlFreeURI(xmlURIPtr uri) { * * ************************************************************************/ +static int +xmlIsPathSeparator(int c, int isFile) { + (void) isFile; + + if (c == '/') + return(1); + +#if defined(_WIN32) || defined(__CYGWIN__) + if (isFile && (c == '\\')) + return(1); +#endif + + return(0); +} + /** - * xmlNormalizeURIPath: + * xmlNormalizePath: * @path: pointer to the path string + * @isFile: true for filesystem paths, false for URIs * - * Applies the 5 normalization steps to a path string--that is, RFC 2396 - * Section 5.2, steps 6.c through 6.g. - * - * Normalization occurs directly on the string, no new allocation is done + * Normalize a filesystem path or URI. * * Returns 0 or an error code */ -int -xmlNormalizeURIPath(char *path) { +static int +xmlNormalizePath(char *path, int isFile) { char *cur, *out; + int numSeg = 0; if (path == NULL) return(-1); - /* Skip all initial "/" chars. We want to get to the beginning of the - * first non-empty segment. - */ cur = path; - while (cur[0] == '/') - ++cur; - if (cur[0] == '\0') - return(0); + out = path; - /* Keep everything we've seen so far. */ - out = cur; + if (*cur == 0) + return(0); - /* - * Analyze each segment in sequence for cases (c) and (d). - */ - while (cur[0] != '\0') { - /* - * c) All occurrences of "./", where "." is a complete path segment, - * are removed from the buffer string. - */ - if ((cur[0] == '.') && (cur[1] == '/')) { - cur += 2; - /* '//' normalization should be done at this point too */ - while (cur[0] == '/') - cur++; - continue; - } - - /* - * d) If the buffer string ends with "." as a complete path segment, - * that "." is removed. - */ - if ((cur[0] == '.') && (cur[1] == '\0')) - break; - - /* Otherwise keep the segment. */ - while (cur[0] != '/') { - if (cur[0] == '\0') - goto done_cd; - (out++)[0] = (cur++)[0]; - } - /* normalize // */ - while ((cur[0] == '/') && (cur[1] == '/')) - cur++; - - (out++)[0] = (cur++)[0]; + if (xmlIsPathSeparator(*cur, isFile)) { + cur++; + *out++ = '/'; } - done_cd: - out[0] = '\0'; - - /* Reset to the beginning of the first segment for the next sequence. */ - cur = path; - while (cur[0] == '/') - ++cur; - if (cur[0] == '\0') - return(0); - - /* - * Analyze each segment in sequence for cases (e) and (f). - * - * e) All occurrences of "/../", 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. + while (*cur != 0) { + /* + * At this point, out is either empty or ends with a separator. + * Collapse multiple separators first. */ - ++segp; - if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3)) - || ((segp[0] != '.') || (segp[1] != '.') - || ((segp[2] != '/') && (segp[2] != '\0')))) { - cur = segp; - continue; + while (xmlIsPathSeparator(*cur, isFile)) { +#if defined(_WIN32) || defined(__CYGWIN__) + /* Allow two separators at start of path */ + if ((isFile) && (out == path + 1)) + *out++ = '/'; +#endif + cur++; } - /* If we get here, remove this segment and the next one and back up - * to the previous segment (if there is one), to implement the - * "iteratively" clause. It's pretty much impossible to back up - * while maintaining two pointers into the buffer, so just compact - * the whole buffer now. - */ + if (*cur == '.') { + if (cur[1] == 0) { + /* Ignore "." at end of path */ + break; + } else if (xmlIsPathSeparator(cur[1], isFile)) { + /* Skip "./" */ + cur += 2; + continue; + } else if ((cur[1] == '.') && + ((cur[2] == 0) || xmlIsPathSeparator(cur[2], isFile))) { + if (numSeg > 0) { + /* Handle ".." by removing last segment */ + do { + out--; + } while ((out > path) && + !xmlIsPathSeparator(out[-1], isFile)); + numSeg--; + + if (cur[2] == 0) + break; + cur += 3; + continue; + } else if (out[0] == '/') { + /* Ignore extraneous ".." in absolute paths */ + if (cur[2] == 0) + break; + cur += 3; + continue; + } else { + /* Keep "../" at start of relative path */ + numSeg--; + } + } + } - /* If this is the end of the buffer, we're done. */ - if (segp[2] == '\0') { - cur[0] = '\0'; - break; + /* Copy segment */ + while ((*cur != 0) && !xmlIsPathSeparator(*cur, isFile)) { + *out++ = *cur++; } - /* Valgrind complained, strcpy(cur, segp + 3); */ - /* string will overlap, do not use strcpy */ - tmp = cur; - segp += 3; - while ((*tmp++ = *segp++) != 0) - ; - - /* If there are no previous segments, then keep going from here. */ - segp = cur; - while ((segp > path) && ((--segp)[0] == '/')) - ; - if (segp == path) - continue; - - /* "segp" is pointing to the end of a previous segment; find it's - * start. We need to back up to the previous segment and start - * over with that to handle things like "foo/bar/../..". If we - * don't do this, then on the first pass we'll remove the "bar/..", - * but be pointing at the second ".." so we won't realize we can also - * remove the "foo/..". - */ - cur = segp; - while ((cur > path) && (cur[-1] != '/')) - --cur; - } - out[0] = '\0'; - /* - * g) If the resulting buffer string still begins with one or more - * complete path segments of "..", then the reference is - * considered to be in error. Implementations may handle this - * error by retaining these components in the resolved path (i.e., - * treating them as part of the final URI), by removing them from - * the resolved path (i.e., discarding relative levels above the - * root), or by avoiding traversal of the reference. - * - * We discard them from the final path. - */ - if (path[0] == '/') { - cur = path; - while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') - && ((cur[3] == '/') || (cur[3] == '\0'))) - cur += 3; + /* Copy separator */ + if (*cur != 0) { + cur++; + *out++ = '/'; + } - if (cur != path) { - out = path; - while (cur[0] != '\0') - (out++)[0] = (cur++)[0]; - out[0] = 0; - } + numSeg++; } + /* Keep "." if output is empty and it's a file */ + if ((isFile) && (out <= path)) + *out++ = '.'; + *out = 0; + return(0); } +/** + * xmlNormalizeURIPath: + * @path: pointer to the path string + * + * Applies the 5 normalization steps to a path string--that is, RFC 2396 + * Section 5.2, steps 6.c through 6.g. + * + * Normalization occurs directly on the string, no new allocation is done + * + * Returns 0 or an error code + */ +int +xmlNormalizeURIPath(char *path) { + return(xmlNormalizePath(path, 0)); +} + static int is_hex(char c) { if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || @@ -1628,10 +1626,8 @@ xmlURIUnescapeString(const char *str, int len, char *target) { if (target == NULL) { ret = (char *) xmlMallocAtomic(len + 1); - if (ret == NULL) { - xmlURIErrMemory("unescaping URI value\n"); + if (ret == NULL) return(NULL); - } } else ret = target; in = str; @@ -1655,6 +1651,7 @@ xmlURIUnescapeString(const char *str, int len, char *target) { c = c * 16 + (*in - 'A') + 10; in++; len -= 3; + /* Explicit sign change */ *out++ = (char) c; } else { *out++ = *in++; @@ -1670,8 +1667,9 @@ xmlURIUnescapeString(const char *str, int len, char *target) { * @str: string to escape * @list: exception list string of chars not to escape * - * This routine escapes a string to hex, ignoring reserved characters (a-z) - * and the characters in the exception list. + * This routine escapes a string to hex, ignoring unreserved characters + * a-z, A-Z, 0-9, "-._~", a few sub-delims "!*'()", the gen-delim "@" + * (why?) and the characters in the exception list. * * Returns a new escaped string or NULL in case of error. */ @@ -1687,25 +1685,24 @@ xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) { if (str[0] == 0) return(xmlStrdup(str)); len = xmlStrlen(str); - if (!(len > 0)) return(NULL); len += 20; ret = (xmlChar *) xmlMallocAtomic(len); - if (ret == NULL) { - xmlURIErrMemory("escaping URI value\n"); + if (ret == NULL) return(NULL); - } in = (const xmlChar *) str; out = 0; while(*in != 0) { if (len - out <= 3) { - temp = xmlSaveUriRealloc(ret, &len); + if (len > INT_MAX / 2) + return(NULL); + temp = xmlRealloc(ret, len * 2); if (temp == NULL) { - xmlURIErrMemory("escaping URI value\n"); xmlFree(ret); return(NULL); } ret = temp; + len *= 2; } ch = *in; @@ -1763,7 +1760,7 @@ xmlURIEscape(const xmlChar * str) /* * Allow escaping errors in the unescaped form */ - uri->cleanup = 1; + uri->cleanup = XML_URI_ALLOW_UNWISE; ret2 = xmlParseURIReference(uri, (const char *)str); if (ret2) { xmlFreeURI(uri); @@ -1777,7 +1774,6 @@ xmlURIEscape(const xmlChar * str) ret = NULL; #define NULLCHK(p) if(!p) { \ - xmlURIErrMemory("escaping URI value\n"); \ xmlFreeURI(uri); \ xmlFree(ret); \ return NULL; } \ @@ -1817,10 +1813,10 @@ xmlURIEscape(const xmlChar * str) xmlFree(segment); } - if (uri->port) { - xmlChar port[10]; + if (uri->port > 0) { + xmlChar port[11]; - snprintf((char *) port, 10, "%d", uri->port); + snprintf((char *) port, 11, "%d", uri->port); ret = xmlStrcat(ret, BAD_CAST ":"); ret = xmlStrcat(ret, port); } @@ -1873,10 +1869,132 @@ xmlURIEscape(const xmlChar * str) * * ************************************************************************/ +static int +xmlIsAbsolutePath(const xmlChar *path) { + int c = path[0]; + + if (xmlIsPathSeparator(c, 1)) + return(1); + +#if defined(_WIN32) || defined(__CYGWIN__) + if ((((c >= 'A') && (c <= 'Z')) || + ((c >= 'a') && (c <= 'z'))) && + (path[1] == ':')) + return(1); +#endif + + return(0); +} + /** - * xmlBuildURI: + * xmlResolvePath: + * @ref: the filesystem path + * @base: the base value + * @out: pointer to result URI + * + * Resolves a filesystem path from a base path. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. + */ +static int +xmlResolvePath(const xmlChar *escRef, const xmlChar *base, xmlChar **out) { + const xmlChar *fragment; + xmlChar *tmp = NULL; + xmlChar *ref = NULL; + xmlChar *result = NULL; + int ret = -1; + int i; + + if (out == NULL) + return(1); + *out = NULL; + + if ((escRef == NULL) || (escRef[0] == 0)) { + if ((base == NULL) || (base[0] == 0)) + return(1); + ref = xmlStrdup(base); + if (ref == NULL) + goto err_memory; + *out = ref; + return(0); + } + + /* + * If a URI is resolved, we can assume it is a valid URI and not + * a filesystem path. This means we have to unescape the part + * before the fragment. + */ + fragment = xmlStrchr(escRef, '#'); + if (fragment != NULL) { + tmp = xmlStrndup(escRef, fragment - escRef); + if (tmp == NULL) + goto err_memory; + escRef = tmp; + } + + ref = (xmlChar *) xmlURIUnescapeString((char *) escRef, -1, NULL); + if (ref == NULL) + goto err_memory; + + if ((base == NULL) || (base[0] == 0)) + goto done; + + if (xmlIsAbsolutePath(ref)) + goto done; + + /* + * Remove last segment from base + */ + i = xmlStrlen(base); + while ((i > 0) && !xmlIsPathSeparator(base[i-1], 1)) + i--; + + /* + * Concatenate base and ref + */ + if (i > 0) { + int refLen = xmlStrlen(ref); + + result = xmlMalloc(i + refLen + 1); + if (result == NULL) + goto err_memory; + + memcpy(result, base, i); + memcpy(result + i, ref, refLen + 1); + } + + /* + * Normalize + */ + xmlNormalizePath((char *) result, 1); + +done: + if (result == NULL) { + result = ref; + ref = NULL; + } + + if (fragment != NULL) { + result = xmlStrcat(result, fragment); + if (result == NULL) + goto err_memory; + } + + *out = result; + ret = 0; + +err_memory: + xmlFree(tmp); + xmlFree(ref); + return(ret); +} + +/** + * xmlBuildURISafe: * @URI: the URI instance found in the document * @base: the base value + * @valPtr: pointer to result URI * * Computes he final URI of the reference done by checking that * the given URI is valid, and building the final URI using the @@ -1885,17 +2003,34 @@ xmlURIEscape(const xmlChar * str) * * 5.2. Resolving Relative References to Absolute Form * - * Returns a new URI string (to be freed by the caller) or NULL in case - * of error. + * Available since 2.13.0. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. */ -xmlChar * -xmlBuildURI(const xmlChar *URI, const xmlChar *base) { +int +xmlBuildURISafe(const xmlChar *URI, const xmlChar *base, xmlChar **valPtr) { xmlChar *val = NULL; int ret, len, indx, cur, out; xmlURIPtr ref = NULL; xmlURIPtr bas = NULL; xmlURIPtr res = NULL; + if (valPtr == NULL) + return(1); + *valPtr = NULL; + + if (URI == NULL) + return(1); + + if (base == NULL) { + val = xmlStrdup(URI); + if (val == NULL) + return(-1); + *valPtr = val; + return(0); + } + /* * 1) The URI reference is parsed into the potential four components and * fragment identifier, as described in Section 4.3. @@ -1904,18 +2039,10 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * as a reference to "." rather than as a synonym for the current * URI. Should we do that here? */ - if (URI == NULL) - ret = -1; - else { - if (*URI) { - ref = xmlCreateURI(); - if (ref == NULL) - goto done; - ret = xmlParseURIReference(ref, (const char *) URI); - } - else - ret = 0; - } + if (URI[0] != 0) + ret = xmlParseURISafe((const char *) URI, &ref); + else + ret = 0; if (ret != 0) goto done; if ((ref != NULL) && (ref->scheme != NULL)) { @@ -1923,19 +2050,30 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * The URI is absolute don't modify. */ val = xmlStrdup(URI); + if (val == NULL) + ret = -1; goto done; } - if (base == NULL) - ret = -1; - else { - bas = xmlCreateURI(); - if (bas == NULL) - goto done; - ret = xmlParseURIReference(bas, (const char *) base); + + /* + * If base has no scheme or authority, it is assumed to be a + * filesystem path. + */ + if (xmlStrstr(base, BAD_CAST "://") == NULL) { + xmlFreeURI(ref); + return(xmlResolvePath(URI, base, valPtr)); } + + ret = xmlParseURISafe((const char *) base, &bas); + if (ret < 0) + goto done; if (ret != 0) { - if (ref) + if (ref) { + ret = 0; val = xmlSaveUri(ref); + if (val == NULL) + ret = -1; + } goto done; } if (ref == NULL) { @@ -1947,6 +2085,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { bas->fragment = NULL; } val = xmlSaveUri(bas); + if (val == NULL) + ret = -1; goto done; } @@ -1962,34 +2102,62 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * defined while still treating this as a reference to the current * document. */ + ret = -1; res = xmlCreateURI(); if (res == NULL) goto done; if ((ref->scheme == NULL) && (ref->path == NULL) && - ((ref->authority == NULL) && (ref->server == NULL))) { - if (bas->scheme != NULL) + ((ref->authority == NULL) && (ref->server == NULL) && + (ref->port == PORT_EMPTY))) { + if (bas->scheme != NULL) { res->scheme = xmlMemStrdup(bas->scheme); - if (bas->authority != NULL) + if (res->scheme == NULL) + goto done; + } + if (bas->authority != NULL) { res->authority = xmlMemStrdup(bas->authority); - else if ((bas->server != NULL) || (bas->port == -1)) { - if (bas->server != NULL) + if (res->authority == NULL) + goto done; + } else { + if (bas->server != NULL) { res->server = xmlMemStrdup(bas->server); - if (bas->user != NULL) + if (res->server == NULL) + goto done; + } + if (bas->user != NULL) { res->user = xmlMemStrdup(bas->user); + if (res->user == NULL) + goto done; + } res->port = bas->port; } - if (bas->path != NULL) + if (bas->path != NULL) { res->path = xmlMemStrdup(bas->path); - if (ref->query_raw != NULL) + if (res->path == NULL) + goto done; + } + if (ref->query_raw != NULL) { res->query_raw = xmlMemStrdup (ref->query_raw); - else if (ref->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (ref->query != NULL) { res->query = xmlMemStrdup(ref->query); - else if (bas->query_raw != NULL) + if (res->query == NULL) + goto done; + } else if (bas->query_raw != NULL) { res->query_raw = xmlMemStrdup(bas->query_raw); - else if (bas->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (bas->query != NULL) { res->query = xmlMemStrdup(bas->query); - if (ref->fragment != NULL) + if (res->query == NULL) + goto done; + } + if (ref->fragment != NULL) { res->fragment = xmlMemStrdup(ref->fragment); + if (res->fragment == NULL) + goto done; + } goto step_7; } @@ -2001,17 +2169,30 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { */ if (ref->scheme != NULL) { val = xmlSaveUri(ref); + if (val != NULL) + ret = 0; goto done; } - if (bas->scheme != NULL) + if (bas->scheme != NULL) { res->scheme = xmlMemStrdup(bas->scheme); + if (res->scheme == NULL) + goto done; + } - if (ref->query_raw != NULL) + if (ref->query_raw != NULL) { res->query_raw = xmlMemStrdup(ref->query_raw); - else if (ref->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (ref->query != NULL) { res->query = xmlMemStrdup(ref->query); - if (ref->fragment != NULL) + if (res->query == NULL) + goto done; + } + if (ref->fragment != NULL) { res->fragment = xmlMemStrdup(ref->fragment); + if (res->fragment == NULL) + goto done; + } /* * 4) If the authority component is defined, then the reference is a @@ -2020,26 +2201,47 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * 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) + if ((ref->authority != NULL) || (ref->server != NULL) || + (ref->port != PORT_EMPTY)) { + if (ref->authority != NULL) { res->authority = xmlMemStrdup(ref->authority); - else { - res->server = xmlMemStrdup(ref->server); - if (ref->user != NULL) + if (res->authority == NULL) + goto done; + } else { + if (ref->server != NULL) { + res->server = xmlMemStrdup(ref->server); + if (res->server == NULL) + goto done; + } + if (ref->user != NULL) { res->user = xmlMemStrdup(ref->user); + if (res->user == NULL) + goto done; + } res->port = ref->port; } - if (ref->path != NULL) + if (ref->path != NULL) { res->path = xmlMemStrdup(ref->path); + if (res->path == NULL) + goto done; + } goto step_7; } - if (bas->authority != NULL) + if (bas->authority != NULL) { res->authority = xmlMemStrdup(bas->authority); - else if ((bas->server != NULL) || (bas->port == -1)) { - if (bas->server != NULL) + if (res->authority == NULL) + goto done; + } else if ((bas->server != NULL) || (bas->port != PORT_EMPTY)) { + if (bas->server != NULL) { res->server = xmlMemStrdup(bas->server); - if (bas->user != NULL) + if (res->server == NULL) + goto done; + } + if (bas->user != NULL) { res->user = xmlMemStrdup(bas->user); + if (res->user == NULL) + goto done; + } res->port = bas->port; } @@ -2049,6 +2251,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { */ if ((ref->path != NULL) && (ref->path[0] == '/')) { res->path = xmlMemStrdup(ref->path); + if (res->path == NULL) + goto done; goto step_7; } @@ -2067,10 +2271,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { if (bas->path != NULL) len += strlen(bas->path); res->path = (char *) xmlMallocAtomic(len); - if (res->path == NULL) { - xmlURIErrMemory("resolving URI against base\n"); + if (res->path == NULL) goto done; - } res->path[0] = 0; /* @@ -2105,7 +2307,7 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { /* * Ensure the path includes a '/' */ - if ((out == 0) && (bas->server != NULL)) + if ((out == 0) && ((bas->server != NULL) || bas->port != PORT_EMPTY)) res->path[out++] = '/'; while (ref->path[indx] != 0) { res->path[out++] = ref->path[indx++]; @@ -2126,6 +2328,8 @@ step_7: * reference. */ val = xmlSaveUri(res); + if (val != NULL) + ret = 0; done: if (ref != NULL) @@ -2134,13 +2338,161 @@ done: xmlFreeURI(bas); if (res != NULL) xmlFreeURI(res); - return(val); + *valPtr = val; + return(ret); } /** - * xmlBuildRelativeURI: + * xmlBuildURI: + * @URI: the URI instance found in the document + * @base: the base value + * + * Computes he final URI of the reference done by checking that + * the given URI is valid, and building the final URI using the + * base URI. This is processed according to section 5.2 of the + * RFC 2396 + * + * 5.2. Resolving Relative References to Absolute Form + * + * Returns a new URI string (to be freed by the caller) or NULL in case + * of error. + */ +xmlChar * +xmlBuildURI(const xmlChar *URI, const xmlChar *base) { + xmlChar *out; + + xmlBuildURISafe(URI, base, &out); + return(out); +} + +static int +xmlParseUriOrPath(const char *str, xmlURIPtr *out, int *drive) { + xmlURIPtr uri; + char *buf = NULL; + int ret; + + *out = NULL; + *drive = 0; + + uri = xmlCreateURI(); + if (uri == NULL) { + ret = -1; + goto done; + } + + if (xmlStrstr(BAD_CAST str, BAD_CAST "://") == NULL) { + const char *path; + size_t pathSize; + int prependSlash = 0; + + buf = xmlMemStrdup(str); + if (buf == NULL) { + ret = -1; + goto done; + } + xmlNormalizePath(buf, /* isFile */ 1); + + path = buf; + + if (xmlIsAbsolutePath(BAD_CAST buf)) { +#if defined(_WIN32) || defined(__CYGWIN__) + const char *server = NULL; + int isFileScheme = 0; +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) + if (strncmp(buf, "//?/UNC/", 8) == 0) { + server = buf + 8; + isFileScheme = 1; + } else if (strncmp(buf, "//?/", 4) == 0) { + path = buf + 3; + isFileScheme = 1; + } else if (strncmp(buf, "//", 2) == 0) { + server = buf + 2; + isFileScheme = 1; + } + + if (server != NULL) { + const char *end = strchr(server, '/'); + + if (end == NULL) { + uri->server = xmlMemStrdup(server); + path = "/"; + } else { + uri->server = (char *) xmlStrndup(BAD_CAST server, + end - server); + path = end; + } + if (uri->server == NULL) { + ret = -1; + goto done; + } + } + + if ((((path[0] >= 'A') && (path[0] <= 'Z')) || + ((path[0] >= 'a') && (path[0] <= 'z'))) && + (path[1] == ':')) { + prependSlash = 1; + isFileScheme = 1; + } + + if (isFileScheme) { + uri->scheme = xmlMemStrdup("file"); + if (uri->scheme == NULL) { + ret = -1; + goto done; + } + + if (uri->server == NULL) + uri->port = PORT_EMPTY_SERVER; + } +#endif + } + + pathSize = strlen(path); + uri->path = xmlMalloc(pathSize + prependSlash + 1); + if (uri->path == NULL) { + ret = -1; + goto done; + } + if (prependSlash) { + uri->path[0] = '/'; + memcpy(uri->path + 1, path, pathSize + 1); + } else { + memcpy(uri->path, path, pathSize + 1); + } + } else { + ret = xmlParseURIReference(uri, str); + if (ret != 0) + goto done; + + xmlNormalizePath(uri->path, /* isFile */ 0); + } + +#if defined(_WIN32) || defined(__CYGWIN__) + if ((uri->path[0] == '/') && + (((uri->path[1] >= 'A') && (uri->path[1] <= 'Z')) || + ((uri->path[1] >= 'a') && (uri->path[1] <= 'z'))) && + (uri->path[2] == ':')) + *drive = uri->path[1]; +#endif + + *out = uri; + uri = NULL; + ret = 0; + +done: + xmlFreeURI(uri); + xmlFree(buf); + + return(ret); +} + +/** + * xmlBuildRelativeURISafe: * @URI: the URI reference under consideration * @base: the base value + * @valPtr: pointer to result URI * * Expresses the URI of the reference in terms relative to the * base. Some examples of this operation include: @@ -2166,105 +2518,112 @@ done: * since this routine (for reasonable efficiency) assumes URI has * already been through some validation. * - * Returns a new URI string (to be freed by the caller) or NULL in case - * error. + * Available since 2.13.0. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. */ -xmlChar * -xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) +int +xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base, + xmlChar **valPtr) { xmlChar *val = NULL; - int ret; + int ret = 0; int ix; int nbslash = 0; int len; xmlURIPtr ref = NULL; xmlURIPtr bas = NULL; - xmlChar *bptr, *uptr, *vptr; + const xmlChar *bptr, *uptr, *rptr; + xmlChar *vptr; int remove_path = 0; + int refDrive, baseDrive; + if (valPtr == NULL) + return(1); + *valPtr = NULL; if ((URI == NULL) || (*URI == 0)) - return NULL; + return(1); - /* - * First parse URI into a standard form - */ - ref = xmlCreateURI (); - if (ref == NULL) - return NULL; - /* If URI not already in "relative" form */ - if (URI[0] != '.') { - ret = xmlParseURIReference (ref, (const char *) URI); - if (ret != 0) - goto done; /* Error in URI, return NULL */ - } else - ref->path = (char *)xmlStrdup(URI); + ret = xmlParseUriOrPath((char *) URI, &ref, &refDrive); + if (ret < 0) + goto done; + if (ret != 0) { + /* Return URI if URI is invalid */ + ret = 0; + val = xmlStrdup(URI); + if (val == NULL) + ret = -1; + goto done; + } - /* - * Next parse base into the same standard form - */ - if ((base == NULL) || (*base == 0)) { - val = xmlStrdup (URI); - goto done; + /* Return URI if base is empty */ + if ((base == NULL) || (*base == 0)) + goto done; + + ret = xmlParseUriOrPath((char *) base, &bas, &baseDrive); + if (ret < 0) + goto done; + if (ret != 0) { + /* Return URI if base is invalid */ + ret = 0; + goto done; } - bas = xmlCreateURI (); - if (bas == NULL) - goto done; - if (base[0] != '.') { - ret = xmlParseURIReference (bas, (const char *) base); - if (ret != 0) - goto done; /* Error in base, return NULL */ - } else - bas->path = (char *)xmlStrdup(base); /* * If the scheme / server on the URI differs from the base, * just return the URI */ - if ((ref->scheme != NULL) && - ((bas->scheme == NULL) || - (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) || - (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) { - val = xmlStrdup (URI); + if ((xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) || + (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) || + (bas->port != ref->port) || + (baseDrive != refDrive)) { goto done; } if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) { val = xmlStrdup(BAD_CAST ""); + if (val == NULL) + ret = -1; goto done; } if (bas->path == NULL) { val = xmlStrdup((xmlChar *)ref->path); - goto done; + if (val == NULL) { + ret = -1; + goto done; + } + goto escape; } if (ref->path == NULL) { ref->path = (char *) "/"; remove_path = 1; } + bptr = (xmlChar *) bas->path; + rptr = (xmlChar *) ref->path; + /* - * At this point (at last!) we can compare the two paths - * - * First we take care of the special case where either of the - * two path components may be missing (bug 316224) + * Return URI if URI and base aren't both absolute or relative. + */ + if ((bptr[0] == '/') != (rptr[0] == '/')) + goto done; + + /* + * At this point we can compare the two paths */ - bptr = (xmlChar *)bas->path; { - xmlChar *rptr = (xmlChar *) ref->path; int pos = 0; /* * Next we compare the two strings and find where they first differ */ - if ((*rptr == '.') && (rptr[1] == '/')) - rptr += 2; - if ((*bptr == '.') && (bptr[1] == '/')) - bptr += 2; - else if ((*bptr == '/') && (*rptr != '/')) - bptr++; while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0)) pos++; if (bptr[pos] == rptr[pos]) { val = xmlStrdup(BAD_CAST ""); + if (val == NULL) + ret = -1; goto done; /* (I can't imagine why anyone would do this) */ } @@ -2292,6 +2651,8 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) */ if (nbslash == 0 && !uptr[0]) { val = xmlStrdup(BAD_CAST "./"); + if (val == NULL) + ret = -1; goto done; } @@ -2299,9 +2660,12 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) } if (nbslash == 0) { - if (uptr != NULL) + if (uptr != NULL) { /* exception characters from xmlSaveUri */ val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,"); + if (val == NULL) + ret = -1; + } goto done; } @@ -2312,7 +2676,7 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) */ val = (xmlChar *) xmlMalloc (len + 3 * nbslash); if (val == NULL) { - xmlURIErrMemory("building relative URI\n"); + ret = -1; goto done; } vptr = val; @@ -2340,13 +2704,24 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) vptr[len - 1] = 0; } +escape: /* escape the freshly-built path */ vptr = val; - /* exception characters from xmlSaveUri */ + /* exception characters from xmlSaveUri */ val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,"); + if (val == NULL) + ret = -1; + else + ret = 0; xmlFree(vptr); done: + if ((ret == 0) && (val == NULL)) { + val = xmlSaveUri(ref); + if (val == NULL) + ret = -1; + } + /* * Free the working variables */ @@ -2356,153 +2731,75 @@ done: xmlFreeURI (ref); if (bas != NULL) xmlFreeURI (bas); + if (ret != 0) { + xmlFree(val); + val = NULL; + } + + *valPtr = val; + return(ret); +} + +/* + * xmlBuildRelativeURI: + * @URI: the URI reference under consideration + * @base: the base value + * + * See xmlBuildRelativeURISafe. + * + * Returns a new URI string (to be freed by the caller) or NULL in case + * error. + */ +xmlChar * +xmlBuildRelativeURI(const xmlChar * URI, const xmlChar * base) +{ + xmlChar *val; - return val; + xmlBuildRelativeURISafe(URI, base, &val); + return(val); } /** * xmlCanonicPath: * @path: the resource locator in a filesystem notation * - * Constructs a canonic path from the specified path. + * Prepares a path. + * + * If the path contains the substring "://", it is considered a + * Legacy Extended IRI. Characters which aren't allowed in URIs are + * escaped. * - * 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 + * Otherwise, the path is considered a filesystem path which is + * copied without modification. + * + * The caller is responsible for freeing the memory occupied * by the returned string. If there is insufficient memory available, or the * argument is NULL, the function returns NULL. + * + * Returns the escaped path. */ -#define IS_WINDOWS_PATH(p) \ - ((p != NULL) && \ - (((p[0] >= 'a') && (p[0] <= 'z')) || \ - ((p[0] >= 'A') && (p[0] <= 'Z'))) && \ - (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\'))) xmlChar * xmlCanonicPath(const xmlChar *path) { -/* - * For Windows implementations, additional work needs to be done to - * replace backslashes in pathnames with "forward slashes" - */ -#if defined(_WIN32) - int len = 0; - char *p = NULL; -#endif - xmlURIPtr uri; xmlChar *ret; - const xmlChar *absuri; if (path == NULL) return(NULL); -#if defined(_WIN32) - /* - * We must not change the backslashes to slashes if the the path - * starts with \\?\ - * Those paths can be up to 32k characters long. - * Was added specifically for OpenOffice, those paths can't be converted - * to URIs anyway. - */ - if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') && - (path[3] == '\\') ) - return xmlStrdup((const xmlChar *) path); -#endif - - /* sanitize filename starting with // so it can be used as URI */ - if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/')) - path++; - - if ((uri = xmlParseURI((const char *) path)) != NULL) { - xmlFreeURI(uri); - return xmlStrdup(path); - } - /* Check if this is an "absolute uri" */ - absuri = xmlStrstr(path, BAD_CAST "://"); - if (absuri != NULL) { - int l, j; - unsigned char c; - xmlChar *escURI; - - /* - * this looks like an URI where some parts have not been - * escaped leading to a parsing problem. Check that the first - * part matches a protocol. - */ - l = absuri - path; - /* Bypass if first part (part before the '://') is > 20 chars */ - if ((l <= 0) || (l > 20)) - goto path_processing; - /* Bypass if any non-alpha characters are present in first part */ - for (j = 0;j < l;j++) { - c = path[j]; - if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))) - goto path_processing; - } - - /* Escape all except the characters specified in the supplied path */ - escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;="); - if (escURI != NULL) { - /* Try parsing the escaped path */ - uri = xmlParseURI((const char *) escURI); - /* If successful, return the escaped string */ - if (uri != NULL) { - xmlFreeURI(uri); - return escURI; - } - xmlFree(escURI); - } - } - -path_processing: -/* For Windows implementations, replace backslashes with 'forward slashes' */ -#if defined(_WIN32) - /* - * Create a URI structure - */ - uri = xmlCreateURI(); - if (uri == NULL) { /* Guard against 'out of memory' */ - return(NULL); - } - - len = xmlStrlen(path); - if ((len > 2) && IS_WINDOWS_PATH(path)) { - /* make the scheme 'file' */ - uri->scheme = (char *) xmlStrdup(BAD_CAST "file"); - /* allocate space for leading '/' + path + string terminator */ - uri->path = xmlMallocAtomic(len + 2); - if (uri->path == NULL) { - xmlFreeURI(uri); /* Guard against 'out of memory' */ - return(NULL); - } - /* Put in leading '/' plus path */ - uri->path[0] = '/'; - p = uri->path + 1; - strncpy(p, (char *) path, len + 1); - } else { - uri->path = (char *) xmlStrdup(path); - if (uri->path == NULL) { - xmlFreeURI(uri); - return(NULL); - } - p = uri->path; - } - /* Now change all occurrences of '\' to '/' */ - while (*p != '\0') { - if (*p == '\\') - *p = '/'; - p++; - } - - if (uri->scheme == NULL) { - ret = xmlStrdup((const xmlChar *) uri->path); + if (xmlStrstr(path, BAD_CAST "://") != NULL) { + /* + * Escape all characters except reserved, unreserved and the + * percent sign. + * + * xmlURIEscapeStr already keeps unreserved characters, so we + * pass gen-delims, sub-delims and "%" to ignore. + */ + ret = xmlURIEscapeStr(path, BAD_CAST ":/?#[]@!$&()*+,;='%"); } else { - ret = xmlSaveUri(uri); + ret = xmlStrdup((const xmlChar *) path); } - xmlFreeURI(uri); -#else - ret = xmlStrdup((const xmlChar *) path); -#endif return(ret); } @@ -2520,41 +2817,5 @@ path_processing: xmlChar * xmlPathToURI(const xmlChar *path) { - xmlURIPtr uri; - xmlURI temp; - xmlChar *ret, *cal; - - if (path == NULL) - return(NULL); - - if ((uri = xmlParseURI((const char *) path)) != NULL) { - xmlFreeURI(uri); - return xmlStrdup(path); - } - cal = xmlCanonicPath(path); - if (cal == NULL) - return(NULL); -#if defined(_WIN32) - /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?) - If 'cal' is a valid URI already then we are done here, as continuing would make - it invalid. */ - if ((uri = xmlParseURI((const char *) cal)) != NULL) { - xmlFreeURI(uri); - return cal; - } - /* 'cal' can contain a relative path with backslashes. If that is processed - by xmlSaveURI, they will be escaped and the external entity loader machinery - will fail. So convert them to slashes. Misuse 'ret' for walking. */ - ret = cal; - while (*ret != '\0') { - if (*ret == '\\') - *ret = '/'; - ret++; - } -#endif - memset(&temp, 0, sizeof(temp)); - temp.path = (char *) cal; - ret = xmlSaveUri(&temp); - xmlFree(cal); - return(ret); + return(xmlCanonicPath(path)); } diff --git a/valid.c b/valid.c index 1da812ea8c3..0e4a9c29947 100644 --- a/valid.c +++ b/valid.c @@ -21,17 +21,16 @@ #include #include #include -#include +#include -static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, - int create); -/* #define DEBUG_VALID_ALGO */ -/* #define DEBUG_REGEXP_ALGO */ +#include "private/error.h" +#include "private/parser.h" +#include "private/regexp.h" +#include "private/save.h" +#include "private/tree.h" -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +static xmlElementPtr +xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name); #ifdef LIBXML_VALID_ENABLED static int @@ -52,33 +51,56 @@ xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, * Handle an out of memory error */ static void -xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra) +xmlVErrMemory(xmlValidCtxtPtr ctxt) { - xmlGenericErrorFunc channel = NULL; + if (ctxt != NULL) { + if (ctxt->flags & XML_VCTXT_USE_PCTXT) { + xmlCtxtErrMemory(ctxt->userData); + } else { + xmlRaiseMemoryError(NULL, ctxt->error, ctxt->userData, + XML_FROM_VALID, NULL); + } + } else { + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_VALID, NULL); + } +} + +static void +xmlDoErrValid(xmlValidCtxtPtr ctxt, xmlNodePtr node, + xmlParserErrors code, int level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, + const char *msg, ...) { xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; + va_list ap; - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - long delta = (char *) ctxt - (char *) ctxt->userData; - if ((delta > 0) && (delta < 250)) - pctxt = ctxt->userData; - } + if (ctxt == NULL) + return; + if (ctxt->flags & XML_VCTXT_USE_PCTXT) + pctxt = ctxt->userData; + + va_start(ap, msg); + if (pctxt != NULL) { + xmlCtxtVErr(pctxt, node, XML_FROM_VALID, code, level, + str1, str2, str3, int1, msg, ap); + } else { + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + int res; + + if (ctxt != NULL) { + channel = ctxt->error; + data = ctxt->userData; + } + res = xmlVRaiseError(NULL, channel, data, NULL, node, + XML_FROM_VALID, code, level, NULL, 0, + (const char *) str1, (const char *) str2, + (const char *) str2, int1, 0, + msg, ap); + if (res < 0) + xmlVErrMemory(ctxt); } - if (extra) - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, - XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, - XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); + va_end(ap); } /** @@ -93,31 +115,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, const char *msg, const char *extra) { - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - 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); + xmlDoErrValid(ctxt, NULL, error, XML_ERR_ERROR, (const xmlChar *) extra, + NULL, NULL, 0, msg, extra); } #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) @@ -138,27 +137,8 @@ xmlErrValidNode(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - 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 *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3); + xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str2, str3, 0, + msg, str1, str2, str3); } #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ @@ -180,27 +160,8 @@ xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, int int2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - 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); + xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str3, NULL, int2, + msg, str1, int2, str3); } /** @@ -220,27 +181,8 @@ xmlErrValidWarning(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->warning; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - 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 *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3); + xmlDoErrValid(ctxt, node, error, XML_ERR_WARNING, str1, str2, str3, 0, + msg, str1, str2, str3); } @@ -269,7 +211,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } } @@ -280,7 +222,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "realloc failed"); + xmlVErrMemory(ctxt); return(-1); } ctxt->vstateMax *= 2; @@ -295,6 +237,10 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { if (elemDecl->contModel != NULL) { ctxt->vstateTab[ctxt->vstateNr].exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); + if (ctxt->vstateTab[ctxt->vstateNr].exec == NULL) { + xmlVErrMemory(ctxt); + return(-1); + } } else { ctxt->vstateTab[ctxt->vstateNr].exec = NULL; xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, @@ -376,7 +322,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } } @@ -386,7 +332,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } ctxt->vstateMax *= 2; @@ -434,7 +380,7 @@ nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); if (ctxt->nodeTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); ctxt->nodeMax = 0; return (0); } @@ -444,7 +390,7 @@ nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "realloc failed"); + xmlVErrMemory(ctxt); return (0); } ctxt->nodeMax *= 2; @@ -471,151 +417,6 @@ nodeVPop(xmlValidCtxtPtr ctxt) 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; - 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 */ @@ -666,7 +467,7 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, fullname = xmlBuildQName(content->name, content->prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, "Building content model"); + xmlVErrMemory(ctxt); return(0); } @@ -711,11 +512,13 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, oldstate = ctxt->state; } do { - xmlValidBuildAContentModel(content->c1, ctxt, name); + if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0) + return(0); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); - xmlValidBuildAContentModel(content, ctxt, name); + if (xmlValidBuildAContentModel(content, ctxt, name) == 0) + return(0); oldend = ctxt->state; ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { @@ -753,13 +556,15 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, */ do { ctxt->state = oldstate; - xmlValidBuildAContentModel(content->c1, ctxt, name); + if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0) + return(0); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_OR) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); ctxt->state = oldstate; - xmlValidBuildAContentModel(content, ctxt, name); + if (xmlValidBuildAContentModel(content, ctxt, name) == 0) + return(0); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { @@ -791,6 +596,8 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, * @ctxt: a validation context * @elem: an element declaration node * + * DEPRECATED: Internal function, don't use. + * * (Re)Build the automata associated to the content model of this * element * @@ -798,6 +605,7 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, */ int xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { + int ret = 0; if ((ctxt == NULL) || (elem == NULL)) return(0); @@ -816,37 +624,37 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { ctxt->am = xmlNewAutomata(); if (ctxt->am == NULL) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, - XML_ERR_INTERNAL_ERROR, - "Cannot create automata for element %s\n", - elem->name, NULL, NULL); + xmlVErrMemory(ctxt); return(0); } ctxt->state = xmlAutomataGetInitState(ctxt->am); - xmlValidBuildAContentModel(elem->content, ctxt, elem->name); + if (xmlValidBuildAContentModel(elem->content, ctxt, elem->name) == 0) + goto done; xmlAutomataSetFinalState(ctxt->am, ctxt->state); elem->contModel = xmlAutomataCompile(ctxt->am); + if (elem->contModel == NULL) { + xmlVErrMemory(ctxt); + goto done; + } if (xmlRegexpIsDeterminist(elem->contModel) != 1) { char expr[5000]; expr[0] = 0; xmlSnprintfElementContent(expr, 5000, elem->content, 1); xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_NOT_DETERMINIST, - "Content model of %s is not determinist: %s\n", + "Content model of %s is not deterministic: %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); + goto done; } + + ret = 1; + +done: ctxt->state = NULL; xmlFreeAutomata(ctxt->am); ctxt->am = NULL; - return(1); + return(ret); } #endif /* LIBXML_REGEXP_ENABLED */ @@ -867,10 +675,8 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { xmlValidCtxtPtr xmlNewValidCtxt(void) { xmlValidCtxtPtr ret; - if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) return (NULL); - } (void) memset(ret, 0, sizeof (xmlValidCtxt)); @@ -885,6 +691,8 @@ xmlValidCtxtPtr xmlNewValidCtxt(void) { */ void xmlFreeValidCtxt(xmlValidCtxtPtr cur) { + if (cur == NULL) + return; if (cur->vstateTab != NULL) xmlFree(cur->vstateTab); if (cur->nodeTab != NULL) @@ -937,10 +745,8 @@ xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, return(NULL); } ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlElementContent)); ret->type = type; ret->ocur = XML_ELEMENT_CONTENT_ONCE; @@ -962,9 +768,17 @@ xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, ret->prefix = xmlDictLookup(dict, name, l); ret->name = xmlDictLookup(dict, tmp, -1); } + if (ret->prefix == NULL) + goto error; } + if (ret->name == NULL) + goto error; } return(ret); + +error: + xmlFreeDocElementContent(doc, ret); + return(NULL); } /** @@ -1002,10 +816,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { dict = doc->dict; ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlElementContent)); ret->type = cur->type; ret->ocur = cur->ocur; @@ -1014,6 +826,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { ret->name = xmlDictLookup(dict, cur->name, -1); else ret->name = xmlStrdup(cur->name); + if (ret->name == NULL) + goto error; } if (cur->prefix != NULL) { @@ -1021,20 +835,22 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { ret->prefix = xmlDictLookup(dict, cur->prefix, -1); else ret->prefix = xmlStrdup(cur->prefix); + if (ret->prefix == NULL) + goto error; } - if (cur->c1 != NULL) + if (cur->c1 != NULL) { ret->c1 = xmlCopyDocElementContent(doc, cur->c1); - if (ret->c1 != NULL) + if (ret->c1 == NULL) + goto error; ret->c1->parent = ret; + } if (cur->c2 != NULL) { prev = ret; cur = cur->c2; while (cur != NULL) { tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (tmp == NULL) { - xmlVErrMemory(NULL, "malloc failed"); - return(ret); - } + if (tmp == NULL) + goto error; memset(tmp, 0, sizeof(xmlElementContent)); tmp->type = cur->type; tmp->ocur = cur->ocur; @@ -1045,6 +861,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { tmp->name = xmlDictLookup(dict, cur->name, -1); else tmp->name = xmlStrdup(cur->name); + if (tmp->name == NULL) + goto error; } if (cur->prefix != NULL) { @@ -1052,16 +870,24 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); else tmp->prefix = xmlStrdup(cur->prefix); + if (tmp->prefix == NULL) + goto error; } - if (cur->c1 != NULL) + if (cur->c1 != NULL) { tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); - if (tmp->c1 != NULL) - tmp->c1->parent = ret; + if (tmp->c1 == NULL) + goto error; + tmp->c1->parent = tmp; + } prev = tmp; cur = cur->c2; } } return(ret); + +error: + xmlFreeElementContent(ret); + return(NULL); } /** @@ -1157,105 +983,6 @@ xmlFreeElementContent(xmlElementContentPtr cur) { } #ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlDumpElementOccur: - * @buf: An XML buffer - * @cur: An element table - * - * Dump the occurrence operator of an element. - */ -static void -xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) { - switch (cur->ocur) { - case XML_ELEMENT_CONTENT_ONCE: - break; - case XML_ELEMENT_CONTENT_OPT: - xmlBufferWriteChar(buf, "?"); - break; - case XML_ELEMENT_CONTENT_MULT: - xmlBufferWriteChar(buf, "*"); - break; - case XML_ELEMENT_CONTENT_PLUS: - xmlBufferWriteChar(buf, "+"); - break; - } -} - -/** - * xmlDumpElementContent: - * @buf: An XML buffer - * @content: An element table - * - * This will dump the content of the element table as an XML DTD definition - */ -static void -xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) { - xmlElementContentPtr cur; - - if (content == NULL) return; - - xmlBufferWriteChar(buf, "("); - cur = content; - - do { - if (cur == NULL) return; - - switch (cur->type) { - case XML_ELEMENT_CONTENT_PCDATA: - xmlBufferWriteChar(buf, "#PCDATA"); - break; - case XML_ELEMENT_CONTENT_ELEMENT: - if (cur->prefix != NULL) { - xmlBufferWriteCHAR(buf, cur->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, cur->name); - break; - case XML_ELEMENT_CONTENT_SEQ: - case XML_ELEMENT_CONTENT_OR: - if ((cur != content) && - (cur->parent != NULL) && - ((cur->type != cur->parent->type) || - (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) - xmlBufferWriteChar(buf, "("); - cur = cur->c1; - continue; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT cur corrupted invalid type\n", - NULL); - } - - while (cur != content) { - xmlElementContentPtr parent = cur->parent; - - if (parent == NULL) return; - - if (((cur->type == XML_ELEMENT_CONTENT_OR) || - (cur->type == XML_ELEMENT_CONTENT_SEQ)) && - ((cur->type != parent->type) || - (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) - xmlBufferWriteChar(buf, ")"); - xmlDumpElementOccur(buf, cur); - - if (cur == parent->c1) { - if (parent->type == XML_ELEMENT_CONTENT_SEQ) - xmlBufferWriteChar(buf, " , "); - else if (parent->type == XML_ELEMENT_CONTENT_OR) - xmlBufferWriteChar(buf, " | "); - - cur = parent->c2; - break; - } - - cur = parent; - } - } while (cur != content); - - xmlBufferWriteChar(buf, ")"); - xmlDumpElementOccur(buf, content); -} - /** * xmlSprintfElementContent: * @buf: an output buffer @@ -1422,7 +1149,8 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlElementPtr ret; xmlElementTablePtr table; xmlAttributePtr oldAttributes = NULL; - xmlChar *ns, *uqname; + const xmlChar *localName; + xmlChar *prefix = NULL; if (dtd == NULL) { return(NULL); @@ -1434,7 +1162,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, switch (type) { case XML_ELEMENT_TYPE_EMPTY: if (content != NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content != NULL for EMPTY\n", NULL); return(NULL); @@ -1442,7 +1170,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_ANY: if (content != NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content != NULL for ANY\n", NULL); return(NULL); @@ -1450,7 +1178,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_MIXED: if (content == NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content == NULL for MIXED\n", NULL); return(NULL); @@ -1458,25 +1186,24 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_ELEMENT: if (content == NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content == NULL for ELEMENT\n", NULL); return(NULL); } break; default: - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT decl corrupted invalid type\n", - NULL); + xmlErrValid(ctxt, XML_ERR_ARGUMENT, + "xmlAddElementDecl: invalid type\n", NULL); return(NULL); } /* * check if name is a QName */ - uqname = xmlSplitQName2(name, &ns); - if (uqname != NULL) - name = uqname; + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error; /* * Create the Element table if needed. @@ -1488,28 +1215,22 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, if (dtd->doc != NULL) dict = dtd->doc->dict; table = xmlHashCreateDict(0, dict); + if (table == NULL) + goto mem_error; dtd->elements = (void *) table; } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddElementDecl: Table creation failed!\n"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); - return(NULL); - } /* * lookup old attributes inserted on an undefined element in the * internal subset. */ if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) { - ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns); + ret = xmlHashLookup2(dtd->doc->intSubset->elements, localName, prefix); if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { oldAttributes = ret->attributes; ret->attributes = NULL; - xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); + xmlHashRemoveEntry2(dtd->doc->intSubset->elements, localName, prefix, + NULL); xmlFreeElement(ret); } } @@ -1518,7 +1239,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, * The element may already be present if one of its attribute * was registered first */ - ret = xmlHashLookup2(table, name, ns); + ret = xmlHashLookup2(table, localName, prefix); if (ret != NULL) { if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) { #ifdef LIBXML_VALID_ENABLED @@ -1529,61 +1250,42 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, "Redefinition of element %s\n", name, NULL, NULL); #endif /* LIBXML_VALID_ENABLED */ - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); + if (prefix != NULL) + xmlFree(prefix); return(NULL); } - if (ns != NULL) { - xmlFree(ns); - ns = NULL; + if (prefix != NULL) { + xmlFree(prefix); + prefix = NULL; } } else { + int res; + ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlElement)); ret->type = XML_ELEMENT_DECL; /* * fill the structure. */ - ret->name = xmlStrdup(name); + ret->name = xmlStrdup(localName); if (ret->name == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); xmlFree(ret); - return(NULL); + goto mem_error; } - ret->prefix = ns; + ret->prefix = prefix; + prefix = NULL; /* * Validity Check: * Insertion must not fail */ - if (xmlHashAddEntry2(table, name, ns, ret)) { -#ifdef LIBXML_VALID_ENABLED - /* - * The element is already defined in this DTD. - */ - xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - name, NULL, NULL); -#endif /* LIBXML_VALID_ENABLED */ + res = xmlHashAdd2(table, localName, ret->prefix, ret); + if (res <= 0) { xmlFreeElement(ret); - if (uqname != NULL) - xmlFree(uqname); - return(NULL); + goto mem_error; } /* * For new element, may have attributes from earlier @@ -1601,12 +1303,15 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, * and flag it by setting a special parent value * so the parser doesn't unallocate it. */ - if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { - ret->content = content; - if (content != NULL) - content->parent = (xmlElementContentPtr) 1; - } else { - ret->content = xmlCopyDocElementContent(dtd->doc, content); + if (content != NULL) { + if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { + ret->content = content; + content->parent = (xmlElementContentPtr) 1; + } else if (content != NULL){ + ret->content = xmlCopyDocElementContent(dtd->doc, content); + if (ret->content == NULL) + goto mem_error; + } } /* @@ -1621,9 +1326,15 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, ret->prev = dtd->last; dtd->last = (xmlNodePtr) ret; } - if (uqname != NULL) - xmlFree(uqname); + if (prefix != NULL) + xmlFree(prefix); return(ret); + +mem_error: + xmlVErrMemory(ctxt); + if (prefix != NULL) + xmlFree(prefix); + return(NULL); } static void @@ -1657,25 +1368,33 @@ xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlElementPtr cur; cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL; cur->etype = elem->etype; - if (elem->name != NULL) + if (elem->name != NULL) { cur->name = xmlStrdup(elem->name); - else - cur->name = NULL; - if (elem->prefix != NULL) + if (cur->name == NULL) + goto error; + } + if (elem->prefix != NULL) { cur->prefix = xmlStrdup(elem->prefix); - else - cur->prefix = NULL; - cur->content = xmlCopyElementContent(elem->content); + if (cur->prefix == NULL) + goto error; + } + if (elem->content != NULL) { + cur->content = xmlCopyElementContent(elem->content); + if (cur->content == NULL) + goto error; + } /* TODO : rebuild the attribute list on the copy */ cur->attributes = NULL; return(cur); + +error: + xmlFreeElement(cur); + return(NULL); } /** @@ -1688,7 +1407,7 @@ xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlElementTablePtr xmlCopyElementTable(xmlElementTablePtr table) { - return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement)); + return(xmlHashCopySafe(table, xmlCopyElement, xmlFreeElementTableEntry)); } #endif /* LIBXML_TREE_ENABLED */ @@ -1698,59 +1417,22 @@ xmlCopyElementTable(xmlElementTablePtr table) { * @buf: the XML buffer output * @elem: An element table * + * DEPRECATED: Use xmlSaveTree. + * * This will dump the content of the element declaration as an XML * DTD definition */ void xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (elem == NULL)) return; - switch (elem->etype) { - case XML_ELEMENT_TYPE_EMPTY: - xmlBufferWriteChar(buf, "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); - 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); - xmlBufferWriteChar(buf, ">\n"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT struct corrupted invalid type\n", - NULL); - } + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) elem); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -1762,9 +1444,9 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { * the arguments. */ static void -xmlDumpElementDeclScan(void *elem, void *buf, +xmlDumpElementDeclScan(void *elem, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem); + xmlSaveTree(save, elem); } /** @@ -1772,13 +1454,21 @@ xmlDumpElementDeclScan(void *elem, void *buf, * @buf: the XML buffer output * @table: An element table * + * DEPRECATED: Don't use. + * * This will dump the content of the element table as an XML DTD definition */ void xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpElementDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpElementDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -1796,14 +1486,18 @@ xmlCreateEnumeration(const xmlChar *name) { xmlEnumerationPtr ret; ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlEnumeration)); - if (name != NULL) + if (name != NULL) { ret->name = xmlStrdup(name); + if (ret->name == NULL) { + xmlFree(ret); + return(NULL); + } + } + return(ret); } @@ -1815,12 +1509,14 @@ xmlCreateEnumeration(const xmlChar *name) { */ void xmlFreeEnumeration(xmlEnumerationPtr cur) { - if (cur == NULL) return; + while (cur != NULL) { + xmlEnumerationPtr next = cur->next; - if (cur->next != NULL) xmlFreeEnumeration(cur->next); + xmlFree((xmlChar *) cur->name); + xmlFree(cur); - if (cur->name != NULL) xmlFree((xmlChar *) cur->name); - xmlFree(cur); + cur = next; + } } #ifdef LIBXML_TREE_ENABLED @@ -1835,41 +1531,30 @@ xmlFreeEnumeration(xmlEnumerationPtr cur) { */ xmlEnumerationPtr xmlCopyEnumeration(xmlEnumerationPtr cur) { - xmlEnumerationPtr ret; - - if (cur == NULL) return(NULL); - ret = xmlCreateEnumeration((xmlChar *) cur->name); - if (ret == NULL) return(NULL); + xmlEnumerationPtr ret = NULL; + xmlEnumerationPtr last = NULL; - if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); - else ret->next = NULL; + while (cur != NULL) { + xmlEnumerationPtr copy = xmlCreateEnumeration(cur->name); - return(ret); -} -#endif /* LIBXML_TREE_ENABLED */ + if (copy == NULL) { + xmlFreeEnumeration(ret); + return(NULL); + } -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlDumpEnumeration: - * @buf: the XML buffer output - * @enum: An enumeration - * - * This will dump the content of the enumeration - */ -static void -xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) { - if ((buf == NULL) || (cur == NULL)) - return; + if (ret == NULL) { + ret = last = copy; + } else { + last->next = copy; + last = copy; + } - xmlBufferWriteCHAR(buf, cur->name); - if (cur->next == NULL) - xmlBufferWriteChar(buf, ")"); - else { - xmlBufferWriteChar(buf, " | "); - xmlDumpEnumeration(buf, cur->next); + cur = cur->next; } + + return(ret); } -#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* LIBXML_TREE_ENABLED */ #ifdef LIBXML_VALID_ENABLED /** @@ -1969,10 +1654,11 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, const xmlChar *name, const xmlChar *ns, xmlAttributeType type, xmlAttributeDefault def, const xmlChar *defaultValue, xmlEnumerationPtr tree) { - xmlAttributePtr ret; + xmlAttributePtr ret = NULL; xmlAttributeTablePtr table; xmlElementPtr elemDef; xmlDictPtr dict = NULL; + int res; if (dtd == NULL) { xmlFreeEnumeration(tree); @@ -2015,9 +1701,8 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, case XML_ATTRIBUTE_NOTATION: break; default: - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid type\n", - NULL); + xmlErrValid(ctxt, XML_ERR_ARGUMENT, + "xmlAddAttributeDecl: invalid type\n", NULL); xmlFreeEnumeration(tree); return(NULL); } @@ -2054,20 +1739,12 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, table = xmlHashCreateDict(0, dict); dtd->attributes = (void *) table; } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddAttributeDecl: Table creation failed!\n"); - xmlFreeEnumeration(tree); - return(NULL); - } - + if (table == NULL) + goto mem_error; ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - xmlFreeEnumeration(tree); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlAttribute)); ret->type = XML_ATTRIBUTE_DECL; @@ -2083,34 +1760,53 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, ret->doc = dtd->doc; if (dict) { ret->name = xmlDictLookup(dict, name, -1); - ret->prefix = xmlDictLookup(dict, ns, -1); ret->elem = xmlDictLookup(dict, elem, -1); } else { ret->name = xmlStrdup(name); - ret->prefix = xmlStrdup(ns); ret->elem = xmlStrdup(elem); } + if ((ret->name == NULL) || (ret->elem == NULL)) + goto mem_error; + if (ns != NULL) { + if (dict) + ret->prefix = xmlDictLookup(dict, ns, -1); + else + ret->prefix = xmlStrdup(ns); + if (ret->prefix == NULL) + goto mem_error; + } ret->def = def; ret->tree = tree; + tree = NULL; if (defaultValue != NULL) { if (dict) ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); else ret->defaultValue = xmlStrdup(defaultValue); + if (ret->defaultValue == NULL) + goto mem_error; } + elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem); + if (elemDef == NULL) + goto mem_error; + /* * Validity Check: * Search the DTD for previous declarations of the ATTLIST */ - if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) { + res = xmlHashAdd3(table, ret->name, ret->prefix, ret->elem, ret); + if (res <= 0) { + if (res < 0) + goto mem_error; #ifdef LIBXML_VALID_ENABLED - /* - * The attribute is already defined in this DTD. - */ - xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED, - "Attribute %s of element %s: already defined\n", - name, elem, NULL); + /* + * The attribute is already defined in this DTD. + */ + xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, + XML_DTD_ATTRIBUTE_REDEFINED, + "Attribute %s of element %s: already defined\n", + name, elem, NULL); #endif /* LIBXML_VALID_ENABLED */ xmlFreeAttribute(ret); return(NULL); @@ -2120,48 +1816,44 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, * 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; - } + if ((type == XML_ATTRIBUTE_ID) && + (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) { + xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, + "Element %s has too may ID attributes defined : %s\n", + elem, name, NULL); + if (ctxt != NULL) + ctxt->valid = 0; + } #endif /* LIBXML_VALID_ENABLED */ - /* - * Insert namespace default def first they need to be - * processed first. - */ - if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || - ((ret->prefix != NULL && - (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { - ret->nexth = elemDef->attributes; - elemDef->attributes = ret; - } else { - xmlAttributePtr tmp = elemDef->attributes; + /* + * Insert namespace default def first they need to be + * processed first. + */ + if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || + ((ret->prefix != NULL && + (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { + ret->nexth = elemDef->attributes; + elemDef->attributes = ret; + } else { + xmlAttributePtr tmp = elemDef->attributes; - while ((tmp != NULL) && - ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || - ((ret->prefix != NULL && - (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { - if (tmp->nexth == NULL) - break; - tmp = tmp->nexth; - } - if (tmp != NULL) { - ret->nexth = tmp->nexth; - tmp->nexth = ret; - } else { - ret->nexth = elemDef->attributes; - elemDef->attributes = ret; - } - } + while ((tmp != NULL) && + ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || + ((ret->prefix != NULL && + (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { + if (tmp->nexth == NULL) + break; + tmp = tmp->nexth; + } + if (tmp != NULL) { + ret->nexth = tmp->nexth; + tmp->nexth = ret; + } else { + ret->nexth = elemDef->attributes; + elemDef->attributes = ret; + } } /* @@ -2176,6 +1868,12 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, dtd->last = (xmlNodePtr) ret; } return(ret); + +mem_error: + xmlVErrMemory(ctxt); + xmlFreeEnumeration(tree); + xmlFreeAttribute(ret); + return(NULL); } static void @@ -2209,24 +1907,42 @@ xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlAttributePtr cur; cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlAttribute)); cur->type = XML_ATTRIBUTE_DECL; cur->atype = attr->atype; cur->def = attr->def; - cur->tree = xmlCopyEnumeration(attr->tree); - if (attr->elem != NULL) + if (attr->tree != NULL) { + cur->tree = xmlCopyEnumeration(attr->tree); + if (cur->tree == NULL) + goto error; + } + if (attr->elem != NULL) { cur->elem = xmlStrdup(attr->elem); - if (attr->name != NULL) + if (cur->elem == NULL) + goto error; + } + if (attr->name != NULL) { cur->name = xmlStrdup(attr->name); - if (attr->prefix != NULL) + if (cur->name == NULL) + goto error; + } + if (attr->prefix != NULL) { cur->prefix = xmlStrdup(attr->prefix); - if (attr->defaultValue != NULL) + if (cur->prefix == NULL) + goto error; + } + if (attr->defaultValue != NULL) { cur->defaultValue = xmlStrdup(attr->defaultValue); + if (cur->defaultValue == NULL) + goto error; + } return(cur); + +error: + xmlFreeAttribute(cur); + return(NULL); } /** @@ -2239,7 +1955,8 @@ xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlAttributeTablePtr xmlCopyAttributeTable(xmlAttributeTablePtr table) { - return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute)); + return(xmlHashCopySafe(table, xmlCopyAttribute, + xmlFreeAttributeTableEntry)); } #endif /* LIBXML_TREE_ENABLED */ @@ -2249,81 +1966,22 @@ xmlCopyAttributeTable(xmlAttributeTablePtr table) { * @buf: the XML buffer output * @attr: An attribute declaration * + * DEPRECATED: Use xmlSaveTree. + * * This will dump the content of the attribute declaration as an XML * DTD definition */ void xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (attr == NULL)) return; - xmlBufferWriteChar(buf, "elem); - xmlBufferWriteChar(buf, " "); - if (attr->prefix != NULL) { - xmlBufferWriteCHAR(buf, attr->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, attr->name); - switch (attr->atype) { - case XML_ATTRIBUTE_CDATA: - xmlBufferWriteChar(buf, " CDATA"); - break; - case XML_ATTRIBUTE_ID: - xmlBufferWriteChar(buf, " ID"); - break; - case XML_ATTRIBUTE_IDREF: - xmlBufferWriteChar(buf, " IDREF"); - break; - case XML_ATTRIBUTE_IDREFS: - xmlBufferWriteChar(buf, " IDREFS"); - break; - case XML_ATTRIBUTE_ENTITY: - xmlBufferWriteChar(buf, " ENTITY"); - break; - case XML_ATTRIBUTE_ENTITIES: - xmlBufferWriteChar(buf, " ENTITIES"); - break; - case XML_ATTRIBUTE_NMTOKEN: - xmlBufferWriteChar(buf, " NMTOKEN"); - break; - case XML_ATTRIBUTE_NMTOKENS: - xmlBufferWriteChar(buf, " NMTOKENS"); - break; - case XML_ATTRIBUTE_ENUMERATION: - xmlBufferWriteChar(buf, " ("); - xmlDumpEnumeration(buf, attr->tree); - break; - case XML_ATTRIBUTE_NOTATION: - xmlBufferWriteChar(buf, " NOTATION ("); - xmlDumpEnumeration(buf, attr->tree); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid type\n", - NULL); - } - switch (attr->def) { - case XML_ATTRIBUTE_NONE: - break; - case XML_ATTRIBUTE_REQUIRED: - xmlBufferWriteChar(buf, " #REQUIRED"); - break; - case XML_ATTRIBUTE_IMPLIED: - xmlBufferWriteChar(buf, " #IMPLIED"); - break; - case XML_ATTRIBUTE_FIXED: - xmlBufferWriteChar(buf, " #FIXED"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid def\n", - NULL); - } - if (attr->defaultValue != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, attr->defaultValue); - } - xmlBufferWriteChar(buf, ">\n"); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) attr); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -2334,9 +1992,9 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { * This is used with the hash scan function - just reverses arguments */ static void -xmlDumpAttributeDeclScan(void *attr, void *buf, +xmlDumpAttributeDeclScan(void *attr, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr); + xmlSaveTree(save, attr); } /** @@ -2344,13 +2002,21 @@ xmlDumpAttributeDeclScan(void *attr, void *buf, * @buf: the XML buffer output * @table: An attribute table * + * DEPRECATED: Don't use. + * * This will dump the content of the attribute table as an XML DTD definition */ void xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpAttributeDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpAttributeDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -2394,8 +2060,9 @@ xmlNotationPtr xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, const xmlChar *PublicID, const xmlChar *SystemID) { - xmlNotationPtr ret; + xmlNotationPtr ret = NULL; xmlNotationTablePtr table; + int res; if (dtd == NULL) { return(NULL); @@ -2417,43 +2084,54 @@ xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, dict = dtd->doc->dict; dtd->notations = table = xmlHashCreateDict(0, dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddNotationDecl: Table creation failed!\n"); - return(NULL); + if (table == NULL) + goto mem_error; } ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlNotation)); /* * fill the structure. */ ret->name = xmlStrdup(name); - if (SystemID != NULL) + if (ret->name == NULL) + goto mem_error; + if (SystemID != NULL) { ret->SystemID = xmlStrdup(SystemID); - if (PublicID != NULL) + if (ret->SystemID == NULL) + goto mem_error; + } + if (PublicID != NULL) { ret->PublicID = xmlStrdup(PublicID); + if (ret->PublicID == NULL) + goto mem_error; + } /* * Validity Check: * Check the DTD for previous declarations of the ATTLIST */ - if (xmlHashAddEntry(table, name, ret)) { + res = xmlHashAdd(table, name, ret); + if (res <= 0) { + if (res < 0) + goto mem_error; #ifdef LIBXML_VALID_ENABLED - xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, - "xmlAddNotationDecl: %s already defined\n", - (const char *) name); + xmlErrValid(ctxt, XML_DTD_NOTATION_REDEFINED, + "xmlAddNotationDecl: %s already defined\n", + (const char *) name); #endif /* LIBXML_VALID_ENABLED */ xmlFreeNotation(ret); return(NULL); } return(ret); + +mem_error: + xmlVErrMemory(ctxt); + xmlFreeNotation(ret); + return(NULL); } static void @@ -2487,23 +2165,29 @@ xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlNotationPtr cur; cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } - if (nota->name != NULL) + memset(cur, 0, sizeof(*cur)); + if (nota->name != NULL) { cur->name = xmlStrdup(nota->name); - else - cur->name = NULL; - if (nota->PublicID != NULL) + if (cur->name == NULL) + goto error; + } + if (nota->PublicID != NULL) { cur->PublicID = xmlStrdup(nota->PublicID); - else - cur->PublicID = NULL; - if (nota->SystemID != NULL) + if (cur->PublicID == NULL) + goto error; + } + if (nota->SystemID != NULL) { cur->SystemID = xmlStrdup(nota->SystemID); - else - cur->SystemID = NULL; + if (cur->SystemID == NULL) + goto error; + } return(cur); + +error: + xmlFreeNotation(cur); + return(NULL); } /** @@ -2516,7 +2200,7 @@ xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlNotationTablePtr xmlCopyNotationTable(xmlNotationTablePtr table) { - return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation)); + return(xmlHashCopySafe(table, xmlCopyNotation, xmlFreeNotationTableEntry)); } #endif /* LIBXML_TREE_ENABLED */ @@ -2526,39 +2210,21 @@ xmlCopyNotationTable(xmlNotationTablePtr table) { * @buf: the XML buffer output * @nota: A notation declaration * + * DEPRECATED: Don't use. + * * This will dump the content the notation declaration as an XML DTD definition */ void xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (nota == NULL)) return; - xmlBufferWriteChar(buf, "name); - if (nota->PublicID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, nota->PublicID); - if (nota->SystemID != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - xmlBufferWriteChar(buf, " >\n"); -} -/** - * xmlDumpNotationDeclScan: - * @nota: A notation declaration - * @buf: the XML buffer output - * - * This is called with the hash scan function, and just reverses args - */ -static void -xmlDumpNotationDeclScan(void *nota, void *buf, - const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota); + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveNotationDecl(save, nota); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -2566,13 +2232,21 @@ xmlDumpNotationDeclScan(void *nota, void *buf, * @buf: the XML buffer output * @table: A notation table * + * DEPRECATED: Don't use. + * * This will dump the content of the notation table as an XML DTD definition */ void xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpNotationDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveNotationTable(save, table); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -2593,35 +2267,6 @@ xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str)); -/** - * xmlValidNormalizeString: - * @str: a string - * - * Normalize a string in-place. - */ -static void -xmlValidNormalizeString(xmlChar *str) { - xmlChar *dst; - const xmlChar *src; - - if (str == NULL) - return; - src = str; - dst = str; - - while (*src == 0x20) src++; - while (*src != 0) { - if (*src == 0x20) { - while (*src == 0x20) src++; - if (*src != 0) - *dst++ = 0x20; - } else { - *dst++ = *src++; - } - } - *dst = 0; -} - static int xmlIsStreaming(xmlValidCtxtPtr ctxt) { xmlParserCtxtPtr pctxt; @@ -2653,36 +2298,43 @@ xmlFreeID(xmlIDPtr id) { DICT_FREE(id->value) if (id->name != NULL) DICT_FREE(id->name) + if (id->attr != NULL) { + id->attr->id = NULL; + id->attr->atype = 0; + } + xmlFree(id); } /** - * xmlAddID: - * @ctxt: the validation context - * @doc: pointer to the document - * @value: the value name + * xmlAddIDInternal: * @attr: the attribute holding the ID + * @value: the attribute (ID) value + * @idPtr: pointer to resulting ID * * Register a new id declaration * - * Returns NULL if not, otherwise the new xmlIDPtr + * Returns 1 on success, 0 if the ID already exists, -1 if a memory + * allocation fails. */ -xmlIDPtr -xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, - xmlAttrPtr attr) { - xmlIDPtr ret; +static int +xmlAddIDInternal(xmlAttrPtr attr, const xmlChar *value, xmlIDPtr *idPtr) { + xmlDocPtr doc; + xmlIDPtr id; xmlIDTablePtr table; + int ret; - if (doc == NULL) { - return(NULL); - } - if ((value == NULL) || (value[0] == 0)) { - return(NULL); - } - if (attr == NULL) { - return(NULL); - } + if (idPtr != NULL) + *idPtr = NULL; + if ((value == NULL) || (value[0] == 0)) + return(0); + if (attr == NULL) + return(0); + + doc = attr->doc; + if (doc == NULL) + return(0); /* * Create the ID table if needed. @@ -2690,57 +2342,105 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, table = (xmlIDTablePtr) doc->ids; if (table == NULL) { doc->ids = table = xmlHashCreateDict(0, doc->dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddID: Table creation failed!\n"); - return(NULL); + if (table == NULL) + return(-1); + } else { + id = xmlHashLookup(table, value); + if (id != NULL) + return(0); } - ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + id = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); + if (id == NULL) + return(-1); + memset(id, 0, sizeof(*id)); /* * fill the structure. */ - ret->value = xmlStrdup(value); - ret->doc = doc; - if (xmlIsStreaming(ctxt)) { - /* - * Operating in streaming mode, attr is gonna disappear - */ - if (doc->dict != NULL) - ret->name = xmlDictLookup(doc->dict, attr->name, -1); - else - ret->name = xmlStrdup(attr->name); - ret->attr = NULL; - } else { - ret->attr = attr; - ret->name = NULL; + id->doc = doc; + id->value = xmlStrdup(value); + if (id->value == NULL) { + xmlFreeID(id); + return(-1); } - ret->lineno = xmlGetLineNo(attr->parent); - if (xmlHashAddEntry(table, value, ret) < 0) { -#ifdef LIBXML_VALID_ENABLED - /* - * The id is already defined in this DTD. - */ - if (ctxt != NULL) { - xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, - "ID %s already defined\n", value, NULL, NULL); - } -#endif /* LIBXML_VALID_ENABLED */ - xmlFreeID(ret); - return(NULL); + if (attr->id != NULL) + xmlRemoveID(doc, attr); + + if (xmlHashAddEntry(table, value, id) < 0) { + xmlFreeID(id); + return(-1); } - if (attr != NULL) - attr->atype = XML_ATTRIBUTE_ID; + + ret = 1; + if (idPtr != NULL) + *idPtr = id; + + id->attr = attr; + id->lineno = xmlGetLineNo(attr->parent); + attr->atype = XML_ATTRIBUTE_ID; + attr->id = id; + return(ret); } +/** + * xmlAddIDSafe: + * @attr: the attribute holding the ID + * @value: the attribute (ID) value + * + * Register a new id declaration + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if the ID already exists, -1 if a memory + * allocation fails. + */ +int +xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) { + return(xmlAddIDInternal(attr, value, NULL)); +} + +/** + * xmlAddID: + * @ctxt: the validation context + * @doc: pointer to the document + * @value: the value name + * @attr: the attribute holding the ID + * + * Register a new id declaration + * + * Returns NULL if not, otherwise the new xmlIDPtr + */ +xmlIDPtr +xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, + xmlAttrPtr attr) { + xmlIDPtr id; + int res; + + if ((attr == NULL) || (doc != attr->doc)) + return(NULL); + + res = xmlAddIDInternal(attr, value, &id); + if (res < 0) { + xmlVErrMemory(ctxt); + } +#ifdef LIBXML_VALID_ENABLED + else if (res == 0) { + if (ctxt != NULL) { + /* + * The id is already defined in this DTD. + */ + xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, + "ID %s already defined\n", value, NULL, NULL); + } + } +#endif /* LIBXML_VALID_ENABLED */ + + return(id); +} + static void xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeID((xmlIDPtr) id); @@ -2768,57 +2468,67 @@ xmlFreeIDTable(xmlIDTablePtr table) { * of HTML documents parsed with the HTML parser, then ID detection is * done systematically. * - * Returns 0 or 1 depending on the lookup result + * Returns 0 or 1 depending on the lookup result or -1 if a memory allocation + * failed. */ int xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { - if ((attr == NULL) || (attr->name == NULL)) return(0); - if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && - (!strcmp((char *) attr->name, "id")) && - (!strcmp((char *) attr->ns->prefix, "xml"))) - return(1); - if (doc == NULL) return(0); - if ((doc->intSubset == NULL) && (doc->extSubset == NULL) && - (doc->type != XML_HTML_DOCUMENT_NODE)) { - return(0); - } else if (doc->type == XML_HTML_DOCUMENT_NODE) { - if ((xmlStrEqual(BAD_CAST "id", attr->name)) || - ((xmlStrEqual(BAD_CAST "name", attr->name)) && - ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a"))))) + if ((attr == NULL) || (attr->name == NULL)) + return(0); + + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { + if (xmlStrEqual(BAD_CAST "id", attr->name)) + return(1); + + if ((elem == NULL) || (elem->type != XML_ELEMENT_NODE)) + return(0); + + if ((xmlStrEqual(BAD_CAST "name", attr->name)) && + (xmlStrEqual(elem->name, BAD_CAST "a"))) return(1); - return(0); - } else if (elem == NULL) { - return(0); } else { xmlAttributePtr attrDecl = NULL; + xmlChar felem[50]; + xmlChar *fullelemname; + const xmlChar *aprefix; + + if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && + (!strcmp((char *) attr->name, "id")) && + (!strcmp((char *) attr->ns->prefix, "xml"))) + return(1); + + if ((doc == NULL) || + ((doc->intSubset == NULL) && (doc->extSubset == NULL))) + return(0); - xmlChar felem[50], fattr[50]; - xmlChar *fullelemname, *fullattrname; + if ((elem == NULL) || + (elem->type != XML_ELEMENT_NODE) || + (elem->name == NULL)) + return(0); fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : (xmlChar *)elem->name; + if (fullelemname == NULL) + return(-1); - fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? - xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : - (xmlChar *)attr->name; + aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL; - if (fullelemname != NULL && fullattrname != NULL) { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, - fullattrname); + if (fullelemname != NULL) { + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullelemname, + attr->name, aprefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, - fullattrname); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullelemname, + attr->name, aprefix); } - if ((fullattrname != fattr) && (fullattrname != attr->name)) - xmlFree(fullattrname); if ((fullelemname != felem) && (fullelemname != elem->name)) xmlFree(fullelemname); if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) return(1); } + return(0); } @@ -2834,30 +2544,17 @@ xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { int xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { xmlIDTablePtr table; - xmlIDPtr id; - xmlChar *ID; if (doc == NULL) return(-1); - if (attr == NULL) return(-1); + if ((attr == NULL) || (attr->id == NULL)) return(-1); table = (xmlIDTablePtr) doc->ids; if (table == NULL) return(-1); - ID = xmlNodeListGetString(doc, attr->children, 1); - if (ID == NULL) + if (xmlHashRemoveEntry(table, attr->id->value, xmlFreeIDTableEntry) < 0) return(-1); - xmlValidNormalizeString(ID); - id = xmlHashLookup(table, ID); - if (id == NULL || id->attr != attr) { - xmlFree(ID); - return(-1); - } - - xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry); - xmlFree(ID); - attr->atype = 0; return(0); } @@ -3002,7 +2699,7 @@ xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, xmlRefPtr xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr) { - xmlRefPtr ret; + xmlRefPtr ret = NULL; xmlRefTablePtr table; xmlListPtr ref_list; @@ -3022,28 +2719,28 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, table = (xmlRefTablePtr) doc->refs; if (table == NULL) { doc->refs = table = xmlHashCreateDict(0, doc->dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddRef: Table creation failed!\n"); - return(NULL); + if (table == NULL) + goto failed; } ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + if (ret == NULL) + goto failed; + memset(ret, 0, sizeof(*ret)); /* * fill the structure. */ ret->value = xmlStrdup(value); + if (ret->value == NULL) + goto failed; if (xmlIsStreaming(ctxt)) { /* * Operating in streaming mode, attr is gonna disappear */ ret->name = xmlStrdup(attr->name); + if (ret->name == NULL) + goto failed; ret->attr = NULL; } else { ret->name = NULL; @@ -3059,28 +2756,22 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, */ if (NULL == (ref_list = xmlHashLookup(table, value))) { - if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) { - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list creation failed!\n", - NULL); + int res; + + if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) goto failed; - } - if (xmlHashAddEntry(table, value, ref_list) < 0) { + res = xmlHashAdd(table, value, ref_list); + if (res <= 0) { xmlListDelete(ref_list); - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list insertion failed!\n", - NULL); goto failed; } } - if (xmlListAppend(ref_list, ret) != 0) { - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list insertion failed!\n", - NULL); + if (xmlListAppend(ref_list, ret) != 0) goto failed; - } return(ret); + failed: + xmlVErrMemory(ctxt); if (ret != NULL) { if (ret->value != NULL) xmlFree((char *)ret->value); @@ -3134,12 +2825,15 @@ xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { return(0); } else { xmlAttributePtr attrDecl; + const xmlChar *aprefix; if (elem == NULL) return(0); - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); + aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL; + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name, + aprefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, attr->name); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name, + aprefix); if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF || @@ -3202,7 +2896,7 @@ xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) { /*If the list is empty then remove the list entry in the hash */ if (xmlListEmpty(ref_list)) - xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry); + xmlHashRemoveEntry(table, ID, xmlFreeRefTableEntry); xmlFree(ID); return(0); } @@ -3250,6 +2944,8 @@ xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { * * Search the DTD for the description of this element * + * NOTE: A NULL return value can also mean that a memory allocation failed. + * * returns the xmlElementPtr if found or NULL */ @@ -3257,21 +2953,26 @@ xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { xmlElementTablePtr table; xmlElementPtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + const xmlChar *localname; + xmlChar *prefix; + + if ((dtd == NULL) || (dtd->elements == NULL) || + (name == NULL)) + return(NULL); - if ((dtd == NULL) || (name == NULL)) return(NULL); - if (dtd->elements == NULL) - return(NULL); table = (xmlElementTablePtr) dtd->elements; + if (table == NULL) + return(NULL); - uqname = xmlSplitQName2(name, &prefix); - if (uqname != NULL) - name = uqname; - cur = xmlHashLookup2(table, name, prefix); - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + cur = xmlHashLookup2(table, localname, prefix); + if (prefix != NULL) + xmlFree(prefix); return(cur); } + /** * xmlGetDtdElementDesc2: * @dtd: a pointer to the DtD to search @@ -3284,60 +2985,64 @@ xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { */ static xmlElementPtr -xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) { +xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name) { xmlElementTablePtr table; - xmlElementPtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + xmlElementPtr cur = NULL; + const xmlChar *localName; + xmlChar *prefix = NULL; if (dtd == NULL) return(NULL); + + /* + * Create the Element table if needed. + */ if (dtd->elements == NULL) { xmlDictPtr dict = NULL; if (dtd->doc != NULL) dict = dtd->doc->dict; - if (!create) - return(NULL); - /* - * Create the Element table if needed. - */ - table = (xmlElementTablePtr) dtd->elements; - if (table == NULL) { - table = xmlHashCreateDict(0, dict); - dtd->elements = (void *) table; - } - if (table == NULL) { - xmlVErrMemory(NULL, "element table allocation failed"); - return(NULL); - } + dtd->elements = xmlHashCreateDict(0, dict); + if (dtd->elements == NULL) + goto mem_error; } table = (xmlElementTablePtr) dtd->elements; - uqname = xmlSplitQName2(name, &prefix); - if (uqname != NULL) - name = uqname; - cur = xmlHashLookup2(table, name, prefix); - if ((cur == NULL) && (create)) { + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error; + cur = xmlHashLookup2(table, localName, prefix); + if (cur == NULL) { cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); - return(NULL); - } + if (cur == NULL) + goto mem_error; memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL; + cur->doc = dtd->doc; /* * fill the structure. */ - cur->name = xmlStrdup(name); - cur->prefix = xmlStrdup(prefix); + cur->name = xmlStrdup(localName); + if (cur->name == NULL) + goto mem_error; + cur->prefix = prefix; + prefix = NULL; cur->etype = XML_ELEMENT_TYPE_UNDEFINED; - xmlHashAddEntry2(table, name, prefix, cur); + if (xmlHashAdd2(table, localName, cur->prefix, cur) <= 0) + goto mem_error; } - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); + + if (prefix != NULL) + xmlFree(prefix); return(cur); + +mem_error: + xmlVErrMemory(ctxt); + xmlFree(prefix); + xmlFreeElement(cur); + return(NULL); } /** @@ -3379,23 +3084,23 @@ xmlAttributePtr xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { xmlAttributeTablePtr table; xmlAttributePtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + const xmlChar *localname; + xmlChar *prefix = NULL; - if (dtd == NULL) return(NULL); - if (dtd->attributes == NULL) return(NULL); + if ((dtd == NULL) || (dtd->attributes == NULL) || + (elem == NULL) || (name == NULL)) + return(NULL); table = (xmlAttributeTablePtr) dtd->attributes; if (table == NULL) return(NULL); - uqname = xmlSplitQName2(name, &prefix); - - if (uqname != NULL) { - cur = xmlHashLookup3(table, uqname, prefix, elem); - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); - } else - cur = xmlHashLookup3(table, name, NULL, elem); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + cur = xmlHashLookup3(table, localname, prefix, elem); + if (prefix != NULL) + xmlFree(prefix); return(cur); } @@ -3452,6 +3157,8 @@ xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { * @doc: the document * @notationName: the notation name to check * + * DEPRECATED: Internal function, don't use. + * * Validate that the given name match a notation declaration. * - [ VC: Notation Declared ] * @@ -3519,6 +3226,35 @@ xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { #ifdef LIBXML_VALID_ENABLED +/** + * xmlValidNormalizeString: + * @str: a string + * + * Normalize a string in-place. + */ +static void +xmlValidNormalizeString(xmlChar *str) { + xmlChar *dst; + const xmlChar *src; + + if (str == NULL) + return; + src = str; + dst = str; + + while (*src == 0x20) src++; + while (*src != 0) { + if (*src == 0x20) { + while (*src == 0x20) src++; + if (*src != 0) + *dst++ = 0x20; + } else { + *dst++ = *src++; + } + } + *dst = 0; +} + static int xmlIsDocNameStartChar(xmlDocPtr doc, int c) { if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { @@ -3838,6 +3574,8 @@ xmlValidateNmtokensValue(const xmlChar *value) { * @doc: a document instance * @nota: a notation definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single notation definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -3894,6 +3632,8 @@ xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, * @type: an attribute type * @value: an attribute value * + * DEPRECATED: Internal function, don't use. + * * Validate that the given attribute value match the proper production * * [ VC: ID ] @@ -3989,8 +3729,10 @@ xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlEntityPtr ent; dup = xmlStrdup(value); - if (dup == NULL) + if (dup == NULL) { + xmlVErrMemory(ctxt); return(0); + } cur = dup; while (*cur != 0) { nam = cur; @@ -4048,6 +3790,8 @@ xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @value: the attribute value * @ctxt: the validation context or NULL * + * DEPRECATED: Internal function, don't use. + * * Does the validation related extra step of the normalization of attribute * values: * @@ -4068,6 +3812,8 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { xmlChar *ret; xmlAttributePtr attrDecl = NULL; + const xmlChar *localName; + xmlChar *prefix = NULL; int extsubset = 0; if (doc == NULL) return(NULL); @@ -4075,38 +3821,47 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, if (name == NULL) return(NULL); if (value == NULL) return(NULL); - if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { - xmlChar fn[50]; - xmlChar *fullname; + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error; - fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); - if (fullname == NULL) - return(NULL); - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); + if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { + xmlChar buf[50]; + xmlChar *elemname; + + elemname = xmlBuildQName(elem->name, elem->ns->prefix, buf, 50); + if (elemname == NULL) + goto mem_error; + if (doc->intSubset != NULL) + attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName, + prefix, elemname); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); + attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName, + prefix, elemname); if (attrDecl != NULL) extsubset = 1; } - if ((fullname != fn) && (fullname != elem->name)) - xmlFree(fullname); + if ((elemname != buf) && (elemname != elem->name)) + xmlFree(elemname); } if ((attrDecl == NULL) && (doc->intSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); + attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName, + prefix, elem->name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); + attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName, + prefix, elem->name); if (attrDecl != NULL) extsubset = 1; } if (attrDecl == NULL) - return(NULL); + goto done; if (attrDecl->atype == XML_ATTRIBUTE_CDATA) - return(NULL); + goto done; ret = xmlStrdup(value); if (ret == NULL) - return(NULL); + goto mem_error; xmlValidNormalizeString(ret); if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE, @@ -4114,7 +3869,16 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, name, elem->name, NULL); ctxt->valid = 0; } + + xmlFree(prefix); return(ret); + +mem_error: + xmlVErrMemory(ctxt); + +done: + xmlFree(prefix); + return(NULL); } /** @@ -4124,6 +3888,8 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @name: the attribute name * @value: the attribute value * + * DEPRECATED: Internal function, don't use. + * * Does the validation related extra step of the normalization of attribute * values: * @@ -4187,6 +3953,8 @@ xmlValidateAttributeIdCallback(void *payload, void *data, * @doc: a document instance * @attr: an attribute definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single attribute definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4232,13 +4000,23 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, /* One ID per Element Type */ if (attr->atype == XML_ATTRIBUTE_ID) { + xmlElementPtr elem = NULL; + const xmlChar *elemLocalName; + xmlChar *elemPrefix; int nbId; + elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix); + if (elemLocalName == NULL) { + xmlVErrMemory(ctxt); + return(0); + } + /* the trick is that we parse DtD as their own internal subset */ - xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, - attr->elem); + if (doc->intSubset != NULL) + elem = xmlHashLookup2(doc->intSubset->elements, + elemLocalName, elemPrefix); if (elem != NULL) { - nbId = xmlScanIDAttributeDecl(NULL, elem, 0); + nbId = xmlScanIDAttributeDecl(ctxt, elem, 0); } else { xmlAttributeTablePtr table; @@ -4258,22 +4036,28 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the internal subset : %s\n", attr->elem, nbId, attr->name); + ret = 0; } else if (doc->extSubset != NULL) { int extId = 0; - elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); + elem = xmlHashLookup2(doc->extSubset->elements, + elemLocalName, elemPrefix); if (elem != NULL) { - extId = xmlScanIDAttributeDecl(NULL, elem, 0); + extId = xmlScanIDAttributeDecl(ctxt, elem, 0); } if (extId > 1) { xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the external subset : %s\n", attr->elem, extId, attr->name); + ret = 0; } else if (extId + nbId > 1) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has ID attributes defined in the internal and external subset : %s\n", attr->elem, attr->name, NULL); + ret = 0; } } + + xmlFree(elemPrefix); } /* Validity Constraint: Enumeration */ @@ -4300,6 +4084,8 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @doc: a document instance * @elem: an element definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single element definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4315,6 +4101,8 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlElementPtr elem) { int ret = 1; xmlElementPtr tst; + const xmlChar *localName; + xmlChar *prefix; CHECK_DTD; @@ -4378,32 +4166,47 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, } } + localName = xmlSplitQName4(elem->name, &prefix); + if (localName == NULL) { + xmlVErrMemory(ctxt); + return(0); + } + /* VC: Unique Element Type Declaration */ - tst = xmlGetDtdElementDesc(doc->intSubset, elem->name); - if ((tst != NULL ) && (tst != elem) && - ((tst->prefix == elem->prefix) || - (xmlStrEqual(tst->prefix, elem->prefix))) && - (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - elem->name, NULL, NULL); - ret = 0; + if (doc->intSubset != NULL) { + tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix); + + if ((tst != NULL ) && (tst != elem) && + ((tst->prefix == elem->prefix) || + (xmlStrEqual(tst->prefix, elem->prefix))) && + (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, + "Redefinition of element %s\n", + elem->name, NULL, NULL); + ret = 0; + } } - tst = xmlGetDtdElementDesc(doc->extSubset, elem->name); - if ((tst != NULL ) && (tst != elem) && - ((tst->prefix == elem->prefix) || - (xmlStrEqual(tst->prefix, elem->prefix))) && - (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - elem->name, NULL, NULL); - ret = 0; + if (doc->extSubset != NULL) { + tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix); + + if ((tst != NULL ) && (tst != elem) && + ((tst->prefix == elem->prefix) || + (xmlStrEqual(tst->prefix, elem->prefix))) && + (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, + "Redefinition of element %s\n", + elem->name, NULL, NULL); + ret = 0; + } } + /* One ID per Element Type * already done when registering the attribute if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { ret = 0; } */ + + xmlFree(prefix); return(ret); } @@ -4415,6 +4218,8 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @attr: an attribute instance * @value: the attribute value (without entities processing) * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single attribute for an element * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4437,6 +4242,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) { xmlAttributePtr attrDecl = NULL; + const xmlChar *aprefix; int val; int ret = 1; @@ -4444,42 +4250,31 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, if ((elem == NULL) || (elem->name == NULL)) return(0); if ((attr == NULL) || (attr->name == NULL)) return(0); + aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL; + if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname; fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); - if (fullname == NULL) + if (fullname == NULL) { + xmlVErrMemory(ctxt); return(0); - if (attr->ns != NULL) { - attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, - attr->name, attr->ns->prefix); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, - attr->name, attr->ns->prefix); - } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - fullname, attr->name); - } + } + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, + attr->name, aprefix); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, + attr->name, aprefix); if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } if (attrDecl == NULL) { - if (attr->ns != NULL) { - attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, - attr->name, attr->ns->prefix); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, - attr->name, attr->ns->prefix); - } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, - elem->name, attr->name); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, attr->name); - } + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, + attr->name, aprefix); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, + attr->name, aprefix); } @@ -4490,6 +4285,8 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, attr->name, elem->name, NULL); return(0); } + if (attr->atype == XML_ATTRIBUTE_ID) + xmlRemoveID(doc, attr); attr->atype = attrDecl->atype; val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); @@ -4592,6 +4389,8 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @ns: an namespace declaration instance * @value: the attribute value (without entities processing) * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single namespace declaration for an element * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4627,7 +4426,7 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { fullname = xmlBuildQName(elem->name, prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, "Validating namespace"); + xmlVErrMemory(ctxt); return(0); } if (ns->prefix != NULL) { @@ -4637,11 +4436,11 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, ns->prefix, BAD_CAST "xmlns"); } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, - BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, + BAD_CAST "xmlns", NULL); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, - BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, + BAD_CAST "xmlns", NULL); } if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); @@ -4654,11 +4453,11 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, ns->prefix, BAD_CAST "xmlns"); } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, - elem->name, BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, + BAD_CAST "xmlns", NULL); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, + BAD_CAST "xmlns", NULL); } } @@ -4890,24 +4689,21 @@ cont: * 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 == (xmlElementContentPtr) 1) || (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); } @@ -4919,12 +4715,10 @@ cont: 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 @@ -4942,14 +4736,12 @@ cont: 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; } @@ -4965,7 +4757,6 @@ cont: } } if (ret == 1) { - DEBUG_VALID_MSG("element found, skip to next"); /* * go to next element in the content model * skipping ignorable elems @@ -4981,7 +4772,6 @@ cont: (NODE->type != XML_TEXT_NODE) && (NODE->type != XML_CDATA_SECTION_NODE))); } else { - DEBUG_VALID_MSG("element failed"); ret = 0; break; } @@ -5014,8 +4804,7 @@ cont: /* * save the second branch 'or' branch */ - DEBUG_VALID_MSG("saving 'or' branch"); - if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1), + if (vstateVPush(ctxt, CONT->c2, NODE, DEPTH + 1, OCCURS, ROLLBACK_OR) < 0) return(-1); DEPTH++; @@ -5056,7 +4845,6 @@ cont: * At this point handle going up in the tree */ if (ret == -1) { - DEBUG_VALID_MSG("error found returning"); return(ret); } analyze: @@ -5071,9 +4859,7 @@ analyze: 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) @@ -5082,69 +4868,50 @@ analyze: 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; } @@ -5155,38 +4922,32 @@ analyze: * Then act accordingly at the parent level */ RESET_OCCURRENCE; - if (CONT->parent == NULL) + if ((CONT->parent == NULL) || + (CONT->parent == (xmlElementContentPtr) 1)) 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--; } @@ -5196,9 +4957,7 @@ analyze: 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) @@ -5209,9 +4968,7 @@ analyze: 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) @@ -5263,7 +5020,8 @@ xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) { strcat(buf, " ..."); return; } - strcat(buf, (char *) cur->name); + if (cur->name != NULL) + strcat(buf, (char *) cur->name); if (cur->next != NULL) strcat(buf, " "); break; @@ -5349,67 +5107,74 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, ctxt->nodeNr = 0; ctxt->nodeTab = NULL; exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); - if (exec != NULL) { - cur = child; - while (cur != NULL) { - switch (cur->type) { - case XML_ENTITY_REF_NODE: - /* - * Push the current node to be able to roll back - * and process within the entity - */ - if ((cur->children != NULL) && - (cur->children->children != NULL)) { - nodeVPush(ctxt, cur); - cur = cur->children->children; - continue; - } - break; - case XML_TEXT_NODE: - if (xmlIsBlankNode(cur)) - break; - ret = 0; - goto fail; - case XML_CDATA_SECTION_NODE: - /* TODO */ - ret = 0; - goto fail; - case XML_ELEMENT_NODE: - if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { - xmlChar fn[50]; - xmlChar *fullname; - - fullname = xmlBuildQName(cur->name, - cur->ns->prefix, fn, 50); - if (fullname == NULL) { - ret = -1; - goto fail; - } - ret = xmlRegExecPushString(exec, fullname, NULL); - if ((fullname != fn) && (fullname != cur->name)) - xmlFree(fullname); - } else { - ret = xmlRegExecPushString(exec, cur->name, NULL); - } - break; - default: - break; - } - /* - * Switch to next element - */ - cur = cur->next; - while (cur == NULL) { - cur = nodeVPop(ctxt); - if (cur == NULL) - break; - cur = cur->next; - } - } - ret = xmlRegExecPushString(exec, NULL, NULL); + if (exec == NULL) { + xmlVErrMemory(ctxt); + return(-1); + } + cur = child; + while (cur != NULL) { + switch (cur->type) { + case XML_ENTITY_REF_NODE: + /* + * Push the current node to be able to roll back + * and process within the entity + */ + if ((cur->children != NULL) && + (cur->children->children != NULL)) { + nodeVPush(ctxt, cur); + cur = cur->children->children; + continue; + } + break; + case XML_TEXT_NODE: + if (xmlIsBlankNode(cur)) + break; + ret = 0; + goto fail; + case XML_CDATA_SECTION_NODE: + /* TODO */ + ret = 0; + goto fail; + case XML_ELEMENT_NODE: + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(cur->name, + cur->ns->prefix, fn, 50); + if (fullname == NULL) { + xmlVErrMemory(ctxt); + ret = -1; + goto fail; + } + ret = xmlRegExecPushString(exec, fullname, NULL); + if ((fullname != fn) && (fullname != cur->name)) + xmlFree(fullname); + } else { + ret = xmlRegExecPushString(exec, cur->name, NULL); + } + break; + default: + break; + } + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); + /* + * Switch to next element + */ + cur = cur->next; + while (cur == NULL) { + cur = nodeVPop(ctxt); + if (cur == NULL) + break; + cur = cur->next; + } + } + ret = xmlRegExecPushString(exec, NULL, NULL); + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); fail: - xmlRegFreeExecCtxt(exec); - } + xmlRegFreeExecCtxt(exec); } #else /* LIBXML_REGEXP_ENABLED */ /* @@ -5419,7 +5184,7 @@ fail: ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } /* @@ -5437,16 +5202,19 @@ fail: 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); + char expr[5000]; + expr[0] = 0; + xmlSnprintfElementContent(expr, 5000, elemDecl->content, 1); + xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, + XML_DTD_CONTENT_NOT_DETERMINIST, + "Content model of %s is not deterministic: %s\n", + name, BAD_CAST expr, NULL); } else if (ret == -2) { /* * An entities reference appeared at this level. * Build 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) { @@ -5475,7 +5243,7 @@ fail: */ tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (tmp == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); xmlFreeNodeList(repl); ret = -1; goto done; @@ -5660,6 +5428,7 @@ done: return(ret); } +#ifdef LIBXML_REGEXP_ENABLED /** * xmlValidateCheckMixed: * @ctxt: the validation context @@ -5725,6 +5494,7 @@ xmlValidateCheckMixed(xmlValidCtxtPtr ctxt, } return(0); } +#endif /* LIBXML_REGEXP_ENABLED */ /** * xmlValidGetElemDecl: @@ -5773,9 +5543,9 @@ xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * full QName but in that case being flexible makes sense. */ if (elemDecl == NULL) { - elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); + elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, NULL); if ((elemDecl == NULL) && (doc->extSubset != NULL)) { - elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); + elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, NULL); if ((elemDecl != NULL) && (extsubset != NULL)) *extsubset = 1; } @@ -5797,6 +5567,8 @@ xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @elem: an element instance * @qname: the qualified name as appearing in the serialization * + * DEPRECATED: Internal function, don't use. + * * Push a new element start on the validation stack. * * returns 1 if no validation problem was found or 0 otherwise @@ -5865,6 +5637,10 @@ xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, */ if (state->exec != NULL) { ret = xmlRegExecPushString(state->exec, qname, NULL); + if (ret == XML_REGEXP_OUT_OF_MEMORY) { + xmlVErrMemory(ctxt); + return(0); + } if (ret < 0) { xmlErrValidNode(ctxt, state->node, XML_DTD_CONTENT_MODEL, @@ -5890,6 +5666,8 @@ xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @data: some character data read * @len: the length of the data * + * DEPRECATED: Internal function, don't use. + * * check the CData parsed for validation in the current stack * * returns 1 if no validation problem was found or 0 otherwise @@ -5963,6 +5741,8 @@ done: * @elem: an element instance * @qname: the qualified name as appearing in the serialization * + * DEPRECATED: Internal function, don't use. + * * Pop the element end from the validation stack. * * returns 1 if no validation problem was found or 0 otherwise @@ -5989,11 +5769,15 @@ xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, 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", + if (ret <= 0) { + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); + else + xmlErrValidNode(ctxt, state->node, + XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD, Expecting more children\n", state->node->name, NULL,NULL); + ret = 0; } else { /* * previous validation errors should not generate @@ -6016,6 +5800,8 @@ xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, * @doc: a document instance * @elem: an element instance * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single element and it's attributes, * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -6043,61 +5829,19 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, if (elem == NULL) return(0); switch (elem->type) { - case XML_ATTRIBUTE_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Attribute element not expected\n", NULL, NULL ,NULL); - return(0); case XML_TEXT_NODE: - if (elem->children != NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has children !\n", - NULL,NULL,NULL); - return(0); - } - if (elem->ns != NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has namespace !\n", - NULL,NULL,NULL); - return(0); - } - if (elem->content == NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has no content !\n", - NULL,NULL,NULL); - return(0); - } - return(1); - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return(1); case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: return(1); - case XML_ENTITY_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Entity element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_NOTATION_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Notation element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Document element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_HTML_DOCUMENT_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "HTML Document not expected\n", NULL, NULL ,NULL); - return(0); case XML_ELEMENT_NODE: break; default: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "unknown element type\n", NULL, NULL ,NULL); + "unexpected element type\n", NULL, NULL ,NULL); return(0); } @@ -6155,8 +5899,10 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, fullname = xmlBuildQName(child->name, child->ns->prefix, fn, 50); - if (fullname == NULL) + if (fullname == NULL) { + xmlVErrMemory(ctxt); return(0); + } cont = elemDecl->content; while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { @@ -6220,7 +5966,8 @@ child_ok: */ child = elem->children; while (child != NULL) { - if (child->type == XML_TEXT_NODE) { + if ((child->type == XML_TEXT_NODE) && + (child->content != NULL)) { const xmlChar *content = child->content; while (IS_BLANK_CH(*content)) @@ -6241,7 +5988,7 @@ child_ok: cont = elemDecl->content; tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); if (tmp <= 0) - ret = tmp; + ret = 0; break; } } /* not continuous */ @@ -6383,6 +6130,8 @@ found: * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Try to validate a the root element * basically it does the following check as described by the * XML-1.0 recommendation: @@ -6422,7 +6171,7 @@ xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, NULL); + xmlVErrMemory(ctxt); return(0); } ret = xmlStrEqual(doc->intSubset->name, fullname); @@ -6449,7 +6198,7 @@ name_ok: * xmlValidateElement: * @ctxt: the validation context * @doc: a document instance - * @elem: an element instance + * @root: an element instance * * Try to validate the subtree under an element * @@ -6457,60 +6206,67 @@ name_ok: */ int -xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { - xmlNodePtr child; +xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) { + xmlNodePtr elem; 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) || - (elem->type == XML_NAMESPACE_DECL)) - return(1); + if (root == NULL) return(0); CHECK_DTD; - /* - * Entities references have to be handled separately - */ - if (elem->type == XML_ENTITY_REF_NODE) { - return(1); - } + elem = root; + while (1) { + ret &= xmlValidateOneElement(ctxt, doc, elem); + + if (elem->type == XML_ELEMENT_NODE) { + attr = elem->properties; + while (attr != NULL) { + if (attr->children == NULL) + value = xmlStrdup(BAD_CAST ""); + else + value = xmlNodeListGetString(doc, attr->children, 0); + if (value == NULL) { + xmlVErrMemory(ctxt); + ret = 0; + } else { + ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); + xmlFree((char *)value); + } + attr= attr->next; + } - 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; + 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; + } + + if (elem->children != NULL) { + elem = elem->children; + continue; + } + } + + while (1) { + if (elem == root) + goto done; + if (elem->next != NULL) + break; + elem = elem->parent; + } + elem = elem->next; } +done: return(ret); } @@ -6537,7 +6293,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, dup = xmlStrdup(name); if (dup == NULL) { - ctxt->valid = 0; + xmlVErrMemory(ctxt); return; } cur = dup; @@ -6572,7 +6328,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, dup = xmlStrdup(name); if (dup == NULL) { - xmlVErrMemory(ctxt, "IDREFS split"); + xmlVErrMemory(ctxt); ctxt->valid = 0; return; } @@ -6640,6 +6396,8 @@ xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Does the final step for the document validation once all the * incremental validation steps have been completed * @@ -6653,7 +6411,8 @@ xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { xmlRefTablePtr table; - unsigned int save; + xmlParserCtxtPtr pctxt = NULL; + xmlParserInputPtr oldInput = NULL; if (ctxt == NULL) return(0); @@ -6663,10 +6422,6 @@ xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { return(0); } - /* trick to get correct line id report */ - save = ctxt->flags; - ctxt->flags &= ~XML_VCTXT_USE_PCTXT; - /* * Check all the NOTATION/NOTATIONS attributes */ @@ -6676,12 +6431,24 @@ xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { /* * Check all the IDREF/IDREFS attributes definition for validity */ + + /* + * Don't print line numbers. + */ + if (ctxt->flags & XML_VCTXT_USE_PCTXT) { + pctxt = ctxt->userData; + oldInput = pctxt->input; + pctxt->input = NULL; + } + table = (xmlRefTablePtr) doc->refs; ctxt->doc = doc; ctxt->valid = 1; xmlHashScan(table, xmlValidateCheckRefCallback, ctxt); - ctxt->flags = save; + if (ctxt->flags & XML_VCTXT_USE_PCTXT) + pctxt->input = oldInput; + return(ctxt->valid); } @@ -6707,31 +6474,42 @@ xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { xmlDtdPtr oldExt, oldInt; xmlNodePtr root; - if (dtd == NULL) return(0); - if (doc == NULL) return(0); + if (dtd == NULL) + return(0); + if (doc == NULL) + return(0); + oldExt = doc->extSubset; oldInt = doc->intSubset; doc->extSubset = dtd; doc->intSubset = NULL; - ret = xmlValidateRoot(ctxt, doc); - if (ret == 0) { - doc->extSubset = oldExt; - doc->intSubset = oldInt; - return(ret); - } if (doc->ids != NULL) { - xmlFreeIDTable(doc->ids); - doc->ids = NULL; + xmlFreeIDTable(doc->ids); + doc->ids = NULL; } if (doc->refs != NULL) { - xmlFreeRefTable(doc->refs); - doc->refs = NULL; + xmlFreeRefTable(doc->refs); + doc->refs = NULL; } - root = xmlDocGetRootElement(doc); - ret = xmlValidateElement(ctxt, doc, root); - ret &= xmlValidateDocumentFinal(ctxt, doc); + + ret = xmlValidateRoot(ctxt, doc); + if (ret != 0) { + root = xmlDocGetRootElement(doc); + ret = xmlValidateElement(ctxt, doc, root); + ret &= xmlValidateDocumentFinal(ctxt, doc); + } + doc->extSubset = oldExt; doc->intSubset = oldInt; + if (doc->ids != NULL) { + xmlFreeIDTable(doc->ids); + doc->ids = NULL; + } + if (doc->refs != NULL) { + xmlFreeRefTable(doc->refs); + doc->refs = NULL; + } + return(ret); } @@ -6798,6 +6576,9 @@ xmlValidateAttributeCallback(void *payload, void *data, } } if (cur->atype == XML_ATTRIBUTE_NOTATION) { + const xmlChar *elemLocalName; + xmlChar *elemPrefix; + doc = cur->doc; if (cur->elem == NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, @@ -6806,13 +6587,25 @@ xmlValidateAttributeCallback(void *payload, void *data, return; } - if (doc != NULL) - elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); - if ((elem == NULL) && (doc != NULL)) - elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); + elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix); + if (elemLocalName == NULL) { + xmlVErrMemory(ctxt); + return; + } + + if ((doc != NULL) && (doc->intSubset != NULL)) + elem = xmlHashLookup2(doc->intSubset->elements, + elemLocalName, elemPrefix); + if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL)) + elem = xmlHashLookup2(doc->extSubset->elements, + elemLocalName, elemPrefix); if ((elem == NULL) && (cur->parent != NULL) && (cur->parent->type == XML_DTD_NODE)) - elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); + elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements, + elemLocalName, elemPrefix); + + xmlFree(elemPrefix); + if (elem == NULL) { xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, "attribute %s: could not find decl for element %s\n", @@ -6833,6 +6626,8 @@ xmlValidateAttributeCallback(void *payload, void *data, * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Does the final step for the dtds validation once all the * subsets have been parsed * @@ -7007,7 +6802,7 @@ xmlValidGetPotentialChildren(xmlElementContent *ctree, /* * Dummy function to suppress messages while we try out valid elements */ -static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, +static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED, ...) { return; } diff --git a/xinclude.c b/xinclude.c index 0c6b3f296bf..6c1e3ace64f 100644 --- a/xinclude.c +++ b/xinclude.c @@ -22,22 +22,17 @@ #include #include #include -#include #ifdef LIBXML_XINCLUDE_ENABLED #include -#include "buf.h" +#include "private/buf.h" +#include "private/error.h" +#include "private/tree.h" +#include "private/xinclude.h" #define XINCLUDE_MAX_DEPTH 40 -/* #define DEBUG_XINCLUDE */ -#ifdef DEBUG_XINCLUDE -#ifdef LIBXML_DEBUG_ENABLED -#include -#endif -#endif - /************************************************************************ * * * XInclude context handling * @@ -54,45 +49,72 @@ 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 */ + xmlChar *base; /* base URI of xi:include element */ + xmlNodePtr elem; /* the xi:include element */ xmlNodePtr inc; /* the included copy */ int xml; /* xml or txt */ - int count; /* how many refs use that specific doc */ int fallback; /* fallback was loaded */ - int emptyFb; /* flag to show fallback empty */ + int expanding; /* flag to detect inclusion loops */ + int replace; /* should the node be replaced? */ +}; + +typedef struct _xmlXIncludeDoc xmlXIncludeDoc; +typedef xmlXIncludeDoc *xmlXIncludeDocPtr; +struct _xmlXIncludeDoc { + xmlDocPtr doc; /* the parsed document */ + xmlChar *url; /* the URL */ + int expanding; /* flag to detect inclusion loops */ +}; + +typedef struct _xmlXIncludeTxt xmlXIncludeTxt; +typedef xmlXIncludeTxt *xmlXIncludeTxtPtr; +struct _xmlXIncludeTxt { + xmlChar *text; /* text string */ + xmlChar *url; /* the URL */ }; 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 */ - xmlChar * *txtTab; /* array of unparsed text strings */ - xmlURL *txturlTab; /* array of unparsed text URLs */ + xmlXIncludeTxt *txtTab; /* array of unparsed documents */ - xmlChar * url; /* the current URL processed */ - int urlNr; /* number of URLs stacked */ - int urlMax; /* size of URL stack */ - xmlChar * *urlTab; /* URL stack */ + int urlNr; /* number of documents stacked */ + int urlMax; /* size of document stack */ + xmlXIncludeDoc *urlTab; /* document stack */ int nbErrors; /* the number of errors detected */ + int fatalErr; /* abort processing */ + int errNo; /* error code */ int legacy; /* using XINCLUDE_OLD_NS */ int parseFlags; /* the flags used for parsing XML documents */ - xmlChar * base; /* the current xml:base */ void *_private; /* application data */ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION unsigned long incTotal; /* total number of processed inclusions */ +#endif + int depth; /* recursion depth */ + int isStream; /* streaming mode */ + + xmlXPathContextPtr xpctxt; + + xmlStructuredErrorFunc errorHandler; + void *errorCtxt; }; +static xmlXIncludeRefPtr +xmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node); + +static int +xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref); + static int -xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, - int skipRoot); +xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree); /************************************************************************ @@ -108,15 +130,14 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, * Handle an out of memory condition */ static void -xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, - const char *extra) +xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt) { - if (ctxt != NULL) - ctxt->nbErrors++; - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->fatalErr = 1; + ctxt->nbErrors++; + + xmlRaiseMemoryError(ctxt->errorHandler, NULL, ctxt->errorCtxt, + XML_FROM_XINCLUDE, NULL); } /** @@ -132,34 +153,34 @@ static void LIBXML_ATTR_FORMAT(4,0) xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra) { - if (ctxt != NULL) - ctxt->nbErrors++; - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - error, XML_ERR_ERROR, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, (const char *) extra); -} + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + int res; -#if 0 -/** - * xmlXIncludeWarn: - * @ctxt: the XInclude context - * @node: the context node - * @msg: the error message - * @extra: extra information - * - * Emit an XInclude warning. - */ -static void LIBXML_ATTR_FORMAT(4,0) -xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, - const char *msg, const xmlChar *extra) -{ - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - error, XML_ERR_WARNING, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, (const char *) extra); + if (ctxt->fatalErr != 0) + return; + ctxt->nbErrors++; + + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + + if (schannel == NULL) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_XINCLUDE, error, XML_ERR_ERROR, + NULL, 0, (const char *) extra, NULL, NULL, 0, 0, + msg, (const char *) extra); + if (res < 0) { + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->fatalErr = 1; + } else { + ctxt->errNo = error; + } } -#endif /** * xmlXIncludeGetProp: @@ -176,15 +197,20 @@ xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *name) { xmlChar *ret; - ret = xmlGetNsProp(cur, XINCLUDE_NS, name); + if (xmlNodeGetAttrValue(cur, name, XINCLUDE_NS, &ret) < 0) + xmlXIncludeErrMemory(ctxt); if (ret != NULL) return(ret); + if (ctxt->legacy != 0) { - ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); - if (ret != NULL) - return(ret); + if (xmlNodeGetAttrValue(cur, name, XINCLUDE_OLD_NS, &ret) < 0) + xmlXIncludeErrMemory(ctxt); + if (ret != NULL) + return(ret); } - ret = xmlGetProp(cur, name); + + if (xmlNodeGetAttrValue(cur, name, NULL, &ret) < 0) + xmlXIncludeErrMemory(ctxt); return(ret); } /** @@ -197,79 +223,15 @@ 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->base != NULL) + xmlFree(ref->base); 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 @@ -282,94 +244,20 @@ 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"); + if (ret == NULL) 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 @@ -380,15 +268,15 @@ 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) + if (ctxt->urlTab != NULL) { + for (i = 0; i < ctxt->urlNr; i++) { + xmlFreeDoc(ctxt->urlTab[i].doc); + xmlFree(ctxt->urlTab[i].url); + } xmlFree(ctxt->urlTab); + } for (i = 0;i < ctxt->incNr;i++) { if (ctxt->incTab[i] != NULL) xmlXIncludeFreeRef(ctxt->incTab[i]); @@ -397,21 +285,13 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { xmlFree(ctxt->incTab); if (ctxt->txtTab != NULL) { for (i = 0;i < ctxt->txtNr;i++) { - if (ctxt->txtTab[i] != NULL) - xmlFree(ctxt->txtTab[i]); + xmlFree(ctxt->txtTab[i].text); + xmlFree(ctxt->txtTab[i].url); } xmlFree(ctxt->txtTab); } - if (ctxt->txturlTab != NULL) { - for (i = 0;i < ctxt->txtNr;i++) { - if (ctxt->txturlTab[i] != NULL) - xmlFree(ctxt->txturlTab[i]); - } - xmlFree(ctxt->txturlTab); - } - if (ctxt->base != NULL) { - xmlFree(ctxt->base); - } + if (ctxt->xpctxt != NULL) + xmlXPathFreeContext(ctxt->xpctxt); xmlFree(ctxt); } @@ -424,7 +304,7 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { */ static xmlDocPtr xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { - xmlDocPtr ret; + xmlDocPtr ret = NULL; xmlParserCtxtPtr pctxt; xmlParserInputPtr inputStream; @@ -432,9 +312,11 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { pctxt = xmlNewParserCtxt(); if (pctxt == NULL) { - xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); + xmlXIncludeErrMemory(ctxt); return(NULL); } + if (ctxt->errorHandler != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->errorHandler, ctxt->errorCtxt); /* * pass in the application data to the parser context. @@ -452,25 +334,18 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlDictReference(pctxt->dict); } + /* + * We set DTDLOAD to make sure that ID attributes declared in + * external DTDs are detected. + */ xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD); - /* Don't read from stdin. */ - if ((URL != NULL) && (strcmp(URL, "-") == 0)) - URL = "./-"; - inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(pctxt); - return(NULL); - } + if (inputStream == NULL) + goto error; inputPush(pctxt, inputStream); - if (pctxt->directory == NULL) - pctxt->directory = xmlParserGetDirectory(URL); - - pctxt->loadsubset |= XML_DETECT_IDS; - xmlParseDocument(pctxt); if (pctxt->wellFormed) { @@ -482,6 +357,10 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlFreeDoc(pctxt->myDoc); pctxt->myDoc = NULL; } + +error: + if (pctxt->errNo == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); xmlFreeParserCtxt(pctxt); return(ret); @@ -494,37 +373,46 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { * * Add a new node to process to an XInclude context */ -static int +static xmlXIncludeRefPtr xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { - xmlXIncludeRefPtr ref; - xmlURIPtr uri; - xmlChar *URL; + xmlXIncludeRefPtr ref = NULL; + xmlXIncludeRefPtr ret = NULL; + xmlURIPtr uri = NULL; + xmlChar *href = NULL; + xmlChar *parse = NULL; xmlChar *fragment = NULL; - xmlChar *href; - xmlChar *parse; - xmlChar *base; - xmlChar *URI; - int xml = 1, i; /* default Issue 64 */ + xmlChar *base = NULL; + xmlChar *tmp; + int xml = 1; int local = 0; - + int res; if (ctxt == NULL) - return(-1); + return(NULL); if (cur == NULL) - return(-1); + return(NULL); -#ifdef DEBUG_XINCLUDE - xmlGenericError(xmlGenericErrorContext, "Add node\n"); -#endif /* * read the attributes */ + + fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); + href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); if (href == NULL) { + if (fragment == NULL) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_HREF, + "href or xpointer must be present\n", parse); + goto error; + } + href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ - if (href == NULL) - return(-1); + if (href == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } } + parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); if (parse != NULL) { if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) @@ -534,61 +422,21 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, "invalid value %s for 'parse'\n", parse); - if (href != NULL) - xmlFree(href); - if (parse != NULL) - xmlFree(parse); - return(-1); + goto error; } } - /* - * compute the URI - */ - base = xmlNodeGetBase(ctxt->doc, cur); - if (base == NULL) { - URI = xmlBuildURI(href, ctxt->doc->URL); - } else { - URI = xmlBuildURI(href, base); - } - if (URI == NULL) { - xmlChar *escbase; - xmlChar *eschref; - /* - * Some escaping may be needed - */ - escbase = xmlURIEscape(base); - eschref = xmlURIEscape(href); - URI = xmlBuildURI(eschref, escbase); - if (escbase != NULL) - xmlFree(escbase); - if (eschref != NULL) - xmlFree(eschref); - } - if (parse != NULL) - xmlFree(parse); - if (href != NULL) - xmlFree(href); - if (base != NULL) - xmlFree(base); - if (URI == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "failed build URL\n", NULL); - return(-1); - } - fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); - /* * Check the URL and remove any fragment identifier */ - uri = xmlParseURI((const char *)URI); + res = xmlParseURISafe((const char *)href, &uri); if (uri == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", URI); - if (fragment != NULL) - xmlFree(fragment); - xmlFree(URI); - return(-1); + if (res < 0) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, + "invalid value href %s\n", href); + goto error; } if (uri->fragment != NULL) { @@ -601,28 +449,46 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { } else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, "Invalid fragment identifier in URI %s use the xpointer attribute\n", - URI); - if (fragment != NULL) - xmlFree(fragment); - xmlFreeURI(uri); - xmlFree(URI); - return(-1); + href); + goto error; } 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); + tmp = xmlSaveUri(uri); + if (tmp == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; } + xmlFree(href); + href = tmp; + + /* + * Resolve URI + */ + + if (xmlNodeGetBaseSafe(ctxt->doc, cur, &base) < 0) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (href[0] != 0) { + if (xmlBuildURISafe(href, base, &tmp) < 0) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + if (tmp == NULL) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, + "failed build URL\n", NULL); + goto error; + } + xmlFree(href); + href = tmp; - if (xmlStrEqual(URL, ctxt->doc->URL)) - local = 1; + if (xmlStrEqual(href, ctxt->doc->URL)) + local = 1; + } else { + local = 1; + } /* * If local and xml then we need a fragment @@ -631,182 +497,113 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { ((fragment == NULL) || (fragment[0] == 0))) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, "detected a local recursion with no xpointer in %s\n", - URL); - xmlFree(URL); - xmlFree(fragment); - return(-1); + href); + goto error; } - /* - * 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); - xmlFree(URL); - xmlFree(fragment); - return(-1); - } - } - } - - ref = xmlXIncludeNewRef(ctxt, URL, cur); - xmlFree(URL); + ref = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); if (ref == NULL) { - return(-1); + xmlXIncludeErrMemory(ctxt); + goto error; } - ref->fragment = fragment; - ref->doc = NULL; - ref->xml = xml; - ref->count = 1; - return(0); -} + memset(ref, 0, sizeof(xmlXIncludeRef)); -/** - * 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; + ref->elem = cur; + ref->xml = xml; + ref->URI = href; + href = NULL; + ref->fragment = fragment; + fragment = NULL; /* - * Avoid recursion in already substituted resources - for (i = 0;i < ctxt->urlNr;i++) { - if (xmlStrEqual(doc->URL, ctxt->urlTab[i])) - return; - } + * xml:base fixup */ + if (((ctxt->parseFlags & XML_PARSE_NOBASEFIX) == 0) && + (cur->doc != NULL) && + ((cur->doc->parseFlags & XML_PARSE_NOBASEFIX) == 0)) { + if (base != NULL) { + ref->base = base; + base = NULL; + } else { + ref->base = xmlStrdup(BAD_CAST ""); + if (ref->base == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + } + } -#ifdef DEBUG_XINCLUDE - xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL); + if (ctxt->incNr >= ctxt->incMax) { + xmlXIncludeRefPtr *table; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 1; +#else + size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 4; #endif - /* - * 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 */ + table = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, + newSize * sizeof(ctxt->incTab[0])); + if (table == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; } - /* - * The new context should also inherit the Parse Flags - * (bug 132597) - */ - newctxt->parseFlags = ctxt->parseFlags; - newctxt->incTotal = ctxt->incTotal; - xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0); - ctxt->incTotal = newctxt->incTotal; - 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; + ctxt->incTab = table; + ctxt->incMax = newSize; + } + ctxt->incTab[ctxt->incNr++] = ref; - newctxt->urlMax = 0; - newctxt->urlNr = 0; - newctxt->urlTab = NULL; + ret = ref; + ref = NULL; - xmlXIncludeFreeContext(newctxt); - } -#ifdef DEBUG_XINCLUDE - xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url); -#endif +error: + xmlXIncludeFreeRef(ref); + xmlFreeURI(uri); + xmlFree(href); + xmlFree(parse); + xmlFree(fragment); + xmlFree(base); + return(ret); } /** - * xmlXIncludeAddTxt: + * xmlXIncludeRecurseDoc: * @ctxt: the XInclude context - * @txt: the new text node + * @doc: the new document * @url: the associated URL * - * Add a new text node to the list + * The XInclude recursive nature is handled at this point. */ static void -xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt, - const xmlURL url) { -#ifdef DEBUG_XINCLUDE - xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url); -#endif - if (ctxt->txtMax == 0) { - ctxt->txtMax = 4; - ctxt->txtTab = (xmlChar **) 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 = (xmlChar **) 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] = xmlStrdup(txt); - ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); - ctxt->txtNr++; +xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) { + xmlDocPtr oldDoc; + xmlXIncludeRefPtr *oldIncTab; + int oldIncMax, oldIncNr, oldIsStream; + int i; + + oldDoc = ctxt->doc; + oldIncMax = ctxt->incMax; + oldIncNr = ctxt->incNr; + oldIncTab = ctxt->incTab; + oldIsStream = ctxt->isStream; + ctxt->doc = doc; + ctxt->incMax = 0; + ctxt->incNr = 0; + ctxt->incTab = NULL; + ctxt->isStream = 0; + + xmlXIncludeDoProcess(ctxt, xmlDocGetRootElement(doc)); + + if (ctxt->incTab != NULL) { + for (i = 0; i < ctxt->incNr; i++) + xmlXIncludeFreeRef(ctxt->incTab[i]); + xmlFree(ctxt->incTab); + } + + ctxt->doc = oldDoc; + ctxt->incMax = oldIncMax; + ctxt->incNr = oldIncNr; + ctxt->incTab = oldIncTab; + ctxt->isStream = oldIsStream; } /************************************************************************ @@ -815,70 +612,175 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt, * * ************************************************************************/ -static xmlNodePtr -xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, - xmlDocPtr source, xmlNodePtr elem); +static void +xmlXIncludeBaseFixup(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, xmlNodePtr copy, + const xmlChar *targetBase) { + xmlChar *base = NULL; + xmlChar *relBase = NULL; + xmlNs ns; + int res; + + if (cur->type != XML_ELEMENT_NODE) + return; + + if (xmlNodeGetBaseSafe(cur->doc, cur, &base) < 0) + xmlXIncludeErrMemory(ctxt); + + if ((base != NULL) && !xmlStrEqual(base, targetBase)) { + if (xmlBuildRelativeURISafe(base, targetBase, &relBase) < 0) { + xmlXIncludeErrMemory(ctxt); + goto done; + } + if (relBase == NULL) { + xmlXIncludeErr(ctxt, cur, + XML_XINCLUDE_HREF_URI, + "Building relative URI failed: %s\n", + base); + goto done; + } + + /* + * If the new base doesn't contain a slash, it can be omitted. + */ + if (xmlStrchr(relBase, '/') != NULL) { + res = xmlNodeSetBase(copy, relBase); + if (res < 0) + xmlXIncludeErrMemory(ctxt); + goto done; + } + } + + /* + * Delete existing xml:base if bases are equal + */ + memset(&ns, 0, sizeof(ns)); + ns.href = XML_XML_NAMESPACE; + xmlUnsetNsProp(copy, &ns, BAD_CAST "base"); + +done: + xmlFree(base); + xmlFree(relBase); +} /** * xmlXIncludeCopyNode: * @ctxt: the XInclude context - * @target: the document target - * @source: the document source * @elem: the element + * @copyChildren: copy children instead of node if true + * + * Make a copy of the node while expanding nested XIncludes. * - * Make a copy of the node while preserving the XInclude semantic - * of the Infoset copy + * Returns a node list, not a single node. */ static xmlNodePtr -xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, - xmlDocPtr source, xmlNodePtr elem) { +xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, + int copyChildren, const xmlChar *targetBase) { xmlNodePtr result = NULL; + xmlNodePtr insertParent = NULL; + xmlNodePtr insertLast = NULL; + xmlNodePtr cur; + xmlNodePtr item; + int depth = 0; - 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); -} + if (copyChildren) { + cur = elem->children; + if (cur == NULL) + return(NULL); + } else { + cur = elem; + } -/** - * 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; + while (1) { + xmlNodePtr copy = NULL; + int recurse = 0; - 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; + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_DTD_NODE)) { + ; + } else if ((cur->type == XML_ELEMENT_NODE) && + (cur->ns != NULL) && + (xmlStrEqual(cur->name, XINCLUDE_NODE)) && + ((xmlStrEqual(cur->ns->href, XINCLUDE_NS)) || + (xmlStrEqual(cur->ns->href, XINCLUDE_OLD_NS)))) { + xmlXIncludeRefPtr ref = xmlXIncludeExpandNode(ctxt, cur); + + if (ref == NULL) + goto error; + /* + * TODO: Insert XML_XINCLUDE_START and XML_XINCLUDE_END nodes + */ + for (item = ref->inc; item != NULL; item = item->next) { + copy = xmlStaticCopyNode(item, ctxt->doc, insertParent, 1); + if (copy == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (result == NULL) + result = copy; + if (insertLast != NULL) { + insertLast->next = copy; + copy->prev = insertLast; + } else if (insertParent != NULL) { + insertParent->children = copy; + } + insertLast = copy; + + if ((depth == 0) && (targetBase != NULL)) + xmlXIncludeBaseFixup(ctxt, item, copy, targetBase); + } + } else { + copy = xmlStaticCopyNode(cur, ctxt->doc, insertParent, 2); + if (copy == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (result == NULL) + result = copy; + if (insertLast != NULL) { + insertLast->next = copy; + copy->prev = insertLast; + } else if (insertParent != NULL) { + insertParent->children = copy; + } + insertLast = copy; + + if ((depth == 0) && (targetBase != NULL)) + xmlXIncludeBaseFixup(ctxt, cur, copy, targetBase); + + recurse = (cur->type != XML_ENTITY_REF_NODE) && + (cur->children != NULL); + } + + if (recurse) { + cur = cur->children; + insertParent = insertLast; + insertLast = NULL; + depth += 1; + continue; + } + + if (cur == elem) + return(result); + + while (cur->next == NULL) { + if (insertParent != NULL) + insertParent->last = insertLast; + cur = cur->parent; + if (cur == elem) + return(result); + insertLast = insertParent; + insertParent = insertParent->parent; + depth -= 1; + } + + cur = cur->next; } - return(result); + +error: + xmlFreeNodeList(result); + return(NULL); } #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -913,8 +815,6 @@ 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. @@ -923,8 +823,7 @@ xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */ * The caller has to free the node tree. */ static xmlNodePtr -xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, - xmlDocPtr source, xmlXPathObjectPtr range) { +xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr range) { /* pointers to generated nodes */ xmlNodePtr list = NULL, last = NULL, listParent = NULL; xmlNodePtr tmp, tmp2; @@ -933,8 +832,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, int index1, index2; int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0; - if ((ctxt == NULL) || (target == NULL) || (source == NULL) || - (range == NULL)) + if ((ctxt == NULL) || (range == NULL)) return(NULL); if (range->type != XPATH_RANGE) return(NULL); @@ -944,7 +842,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, return(NULL); end = range->user2; if (end == NULL) - return(xmlDocCopyNode(start, target, 1)); + return(xmlDocCopyNode(start, ctxt->doc, 1)); if (end->type == XML_NAMESPACE_DECL) return(NULL); @@ -966,7 +864,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, if (level < 0) { while (level < 0) { /* copy must include namespaces and properties */ - tmp2 = xmlDocCopyNode(listParent, target, 2); + tmp2 = xmlDocCopyNode(listParent, ctxt->doc, 2); xmlAddChild(tmp2, list); list = tmp2; listParent = listParent->parent; @@ -988,7 +886,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, int len; if (content == NULL) { - tmp = xmlNewDocTextLen(target, NULL, 0); + tmp = xmlNewDocTextLen(ctxt->doc, NULL, 0); } else { len = index2; if ((cur == start) && (index1 > 1)) { @@ -997,7 +895,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, } else { len = index2; } - tmp = xmlNewDocTextLen(target, content, len); + tmp = xmlNewDocTextLen(ctxt->doc, content, len); } /* single sub text node selection */ if (list == NULL) @@ -1012,7 +910,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 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); + tmp = xmlDocCopyNode(cur, ctxt->doc, 2); if (list == NULL) { list = tmp; listParent = cur->parent; @@ -1048,13 +946,13 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, const xmlChar *content = cur->content; if (content == NULL) { - tmp = xmlNewDocTextLen(target, NULL, 0); + tmp = xmlNewDocTextLen(ctxt->doc, NULL, 0); } else { if (index1 > 1) { content += (index1 - 1); index1 = 0; } - tmp = xmlNewDocText(target, content); + tmp = xmlNewDocText(ctxt->doc, content); } last = list = tmp; listParent = cur->parent; @@ -1063,7 +961,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, * start of the range - need to take care of * properties and namespaces */ - tmp = xmlDocCopyNode(cur, target, 2); + tmp = xmlDocCopyNode(cur, ctxt->doc, 2); list = last = tmp; listParent = cur->parent; if (index1 > 1) { /* Do we need to position? */ @@ -1100,7 +998,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, * Middle of the range - need to take care of * properties and namespaces */ - tmp = xmlDocCopyNode(cur, target, 2); + tmp = xmlDocCopyNode(cur, ctxt->doc, 2); break; } if (tmp != NULL) { @@ -1123,11 +1021,10 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, } #endif /* LIBXML_XPTR_LOCS_ENABLED */ +#ifdef LIBXML_XPTR_ENABLED /** - * xmlXIncludeBuildNodeList: + * xmlXIncludeCopyXPointer: * @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. @@ -1137,86 +1034,69 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, * the caller has to free the node tree. */ static xmlNodePtr -xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, - xmlDocPtr source, xmlXPathObjectPtr obj) { - xmlNodePtr list = NULL, last = NULL; +xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj, + const xmlChar *targetBase) { + xmlNodePtr list = NULL, last = NULL, copy; int i; - if (source == NULL) - source = ctxt->doc; - if ((ctxt == NULL) || (target == NULL) || (source == NULL) || - (obj == NULL)) + if ((ctxt == NULL) || (obj == NULL)) return(NULL); switch (obj->type) { case XPATH_NODESET: { xmlNodeSetPtr set = obj->nodesetval; if (set == NULL) - return(NULL); + break; for (i = 0;i < set->nodeNr;i++) { + xmlNodePtr node; + if (set->nodeTab[i] == NULL) continue; switch (set->nodeTab[i]->type) { - case XML_TEXT_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + node = xmlDocGetRootElement( + (xmlDocPtr) set->nodeTab[i]); + if (node == NULL) { + xmlXIncludeErr(ctxt, set->nodeTab[i], + XML_ERR_INTERNAL_ERROR, + "document without root\n", NULL); + continue; + } + break; + 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: - case XML_XINCLUDE_END: + node = set->nodeTab[i]; 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 { - last = xmlAddNextSibling(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: + default: + xmlXIncludeErr(ctxt, set->nodeTab[i], + XML_XINCLUDE_XPTR_RESULT, + "invalid node type in XPtr result\n", + NULL); 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; + /* + * OPTIMIZE TODO: External documents should already be + * expanded, so xmlDocCopyNode should work as well. + * xmlXIncludeCopyNode is only required for the initial + * document. + */ + copy = xmlXIncludeCopyNode(ctxt, node, 0, targetBase); + if (copy == NULL) { + xmlFreeNodeList(list); + return(NULL); + } + if (last == NULL) { + list = copy; + } else { + while (last->next != NULL) + last = last->next; + copy->prev = last; + last->next = copy; } + last = copy; } break; } @@ -1227,12 +1107,13 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, return(NULL); for (i = 0;i < set->locNr;i++) { if (last == NULL) - list = last = xmlXIncludeCopyXPointer(ctxt, target, source, - set->locTab[i]); + list = last = xmlXIncludeCopyXPointer(ctxt, + set->locTab[i], + targetBase); else xmlAddNextSibling(last, - xmlXIncludeCopyXPointer(ctxt, target, source, - set->locTab[i])); + xmlXIncludeCopyXPointer(ctxt, set->locTab[i], + targetBase)); if (last != NULL) { while (last->next != NULL) last = last->next; @@ -1241,7 +1122,7 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, break; } case XPATH_RANGE: - return(xmlXIncludeCopyRange(ctxt, target, source, obj)); + return(xmlXIncludeCopyRange(ctxt, obj)); case XPATH_POINT: /* points are ignored in XInclude */ break; @@ -1251,6 +1132,8 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, } return(list); } +#endif + /************************************************************************ * * * XInclude I/O handling * @@ -1268,7 +1151,7 @@ struct _xmlXIncludeMergeData { * xmlXIncludeMergeOneEntity: * @ent: the entity * @doc: the including doc - * @nr: the entity name + * @name: the entity name * * Implements the merge of one entity */ @@ -1297,32 +1180,36 @@ xmlXIncludeMergeEntity(void *payload, void *vdata, case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } - ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, - ent->SystemID, ent->content); - if (ret != NULL) { - if (ent->URI != NULL) + prev = xmlGetDocEntity(doc, ent->name); + if (prev == NULL) { + ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, + ent->SystemID, ent->content); + if (ret == NULL) { + xmlXIncludeErrMemory(ctxt); + return; + } + if (ent->URI != NULL) { ret->URI = xmlStrdup(ent->URI); + if (ret->URI == 0) + xmlXIncludeErrMemory(ctxt); + } } else { - prev = xmlGetDocEntity(doc, ent->name); - if (prev != NULL) { - if (ent->etype != prev->etype) - goto error; - - if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { - if (!xmlStrEqual(ent->SystemID, prev->SystemID)) - goto error; - } else if ((ent->ExternalID != NULL) && - (prev->ExternalID != NULL)) { - if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) - goto error; - } else if ((ent->content != NULL) && (prev->content != NULL)) { - if (!xmlStrEqual(ent->content, prev->content)) - goto error; - } else { - goto error; - } - - } + if (ent->etype != prev->etype) + goto error; + + if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { + if (!xmlStrEqual(ent->SystemID, prev->SystemID)) + goto error; + } else if ((ent->ExternalID != NULL) && + (prev->ExternalID != NULL)) { + if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) + goto error; + } else if ((ent->content != NULL) && (prev->content != NULL)) { + if (!xmlStrEqual(ent->content, prev->content)) + goto error; + } else { + goto error; + } } return; error: @@ -1369,8 +1256,10 @@ xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, if (cur == NULL) return(-1); target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); - if (target == NULL) + if (target == NULL) { + xmlXIncludeErrMemory(ctxt); return(-1); + } } source = from->intSubset; @@ -1406,81 +1295,48 @@ xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, * xmlXIncludeLoadDoc: * @ctxt: the XInclude context * @url: the associated URL - * @nr: the xinclude node number + * @ref: an XMLXincludeRefPtr * * 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) { +xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { + xmlXIncludeDocPtr cache; xmlDocPtr doc; - xmlURIPtr uri; - xmlChar *URL; - xmlChar *fragment = NULL; + const xmlChar *url = ref->URI; + const xmlChar *fragment = ref->fragment; int i = 0; + int ret = -1; + int cacheNr; #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)))) { + if ((url[0] == 0) || (url[0] == '#') || + ((ctxt->doc != NULL) && (xmlStrEqual(url, ctxt->doc->URL)))) { doc = ctxt->doc; goto loaded; } /* - * Prevent reloading twice the document. + * Prevent reloading the document twice. */ - 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 + for (i = 0; i < ctxt->urlNr; i++) { + if (xmlStrEqual(url, ctxt->urlTab[i].url)) { + if (ctxt->urlTab[i].expanding) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_RECURSION, + "inclusion loop detected\n", NULL); + goto error; + } + doc = ctxt->urlTab[i].doc; + if (doc == NULL) + goto error; goto loaded; } } @@ -1488,9 +1344,6 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { /* * 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 @@ -1503,36 +1356,50 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { } #endif - doc = xmlXIncludeParseFile(ctxt, (const char *)URL); + 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); + + /* Also cache NULL docs */ + if (ctxt->urlNr >= ctxt->urlMax) { + xmlXIncludeDoc *tmp; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + size_t newSize = ctxt->urlMax ? ctxt->urlMax * 2 : 1; +#else + size_t newSize = ctxt->urlMax ? ctxt->urlMax * 2 : 8; +#endif + + tmp = xmlRealloc(ctxt->urlTab, sizeof(xmlXIncludeDoc) * newSize); + if (tmp == NULL) { + xmlXIncludeErrMemory(ctxt); + xmlFreeDoc(doc); + goto error; + } + ctxt->urlMax = newSize; + ctxt->urlTab = tmp; } - ctxt->incTab[nr]->doc = doc; + cache = &ctxt->urlTab[ctxt->urlNr]; + cache->doc = doc; + cache->url = xmlStrdup(url); + if (cache->url == NULL) { + xmlXIncludeErrMemory(ctxt); + xmlFreeDoc(doc); + goto error; + } + cache->expanding = 0; + cacheNr = ctxt->urlNr++; + + if (doc == NULL) + goto error; /* * 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; - } - } + */ + if ((doc->URL != NULL) && (!xmlStrEqual(url, doc->URL))) + url = doc->URL; /* * Make sure we have all entities fixed up @@ -1552,15 +1419,31 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { doc->extSubset = NULL; } */ - xmlXIncludeRecurseDoc(ctxt, doc, URL); + cache->expanding = 1; + xmlXIncludeRecurseDoc(ctxt, doc); + /* urlTab might be reallocated. */ + cache = &ctxt->urlTab[cacheNr]; + cache->expanding = 0; loaded: if (fragment == NULL) { - /* - * Add the top children list as the replacement copy. - */ - ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc, - doc, doc->children); + xmlNodePtr root; + + root = xmlDocGetRootElement(doc); + if (root == NULL) { + xmlXIncludeErr(ctxt, ref->elem, XML_ERR_INTERNAL_ERROR, + "document without root\n", NULL); + goto error; + } + + ref->inc = xmlDocCopyNode(root, ctxt->doc, 1); + if (ref->inc == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (ref->base != NULL) + xmlXIncludeBaseFixup(ctxt, root, ref->inc, ref->base); } #ifdef LIBXML_XPTR_ENABLED else { @@ -1569,29 +1452,42 @@ loaded: * as the replacement copy. */ xmlXPathObjectPtr xptr; - xmlXPathContextPtr xptrctxt; xmlNodeSetPtr set; - 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); + if (ctxt->isStream && doc == ctxt->doc) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, + "XPointer expressions not allowed in streaming" + " mode\n", NULL); + goto error; + } + + if (ctxt->xpctxt == NULL) { + ctxt->xpctxt = xmlXPtrNewContext(doc, NULL, NULL); + if (ctxt->xpctxt == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + if (ctxt->errorHandler != NULL) + xmlXPathSetErrorHandler(ctxt->xpctxt, ctxt->errorHandler, + ctxt->errorCtxt); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ctxt->xpctxt->opLimit = 100000; +#endif + } else { + ctxt->xpctxt->doc = doc; + } + xptr = xmlXPtrEval(fragment, ctxt->xpctxt); + if (ctxt->xpctxt->lastError.code != XML_ERR_OK) { + if (ctxt->xpctxt->lastError.code == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, + "XPointer evaluation failed: #%s\n", + fragment); + goto error; } + if (xptr == NULL) + goto done; switch (xptr->type) { case XPATH_UNDEFINED: case XPATH_BOOLEAN: @@ -1602,24 +1498,13 @@ loaded: #endif case XPATH_USERS: case XPATH_XSLT_TREE: - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, - XML_XINCLUDE_XPTR_RESULT, + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer is not a range: #%s\n", fragment); xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); - xmlFree(URL); - xmlFree(fragment); - return(-1); + goto error; case XPATH_NODESET: - if ((xptr->nodesetval == NULL) || - (xptr->nodesetval->nodeNr <= 0)) { - xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); - xmlFree(URL); - xmlFree(fragment); - return(-1); - } + break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_RANGE: @@ -1645,14 +1530,14 @@ loaded: continue; case XML_ATTRIBUTE_NODE: - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + xmlXIncludeErr(ctxt, ref->elem, 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, + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer selects a namespace: #%s\n", fragment); @@ -1667,7 +1552,7 @@ loaded: case XML_ENTITY_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer selects unexpected nodes: #%s\n", fragment); @@ -1677,285 +1562,212 @@ loaded: } } } - ctxt->incTab[nr]->inc = - xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); + ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr, ref->base); xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); - xmlFree(fragment); } #endif - /* - * Do the xml:base fixup if needed - */ - if ((doc != NULL) && (URL != NULL) && - (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) && - (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) { - xmlNodePtr node; - xmlChar *base; - xmlChar *curBase; +done: + ret = 0; - /* - * 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); +error: + return(ret); } /** * xmlXIncludeLoadTxt: * @ctxt: the XInclude context - * @url: the associated URL - * @nr: the xinclude node number + * @ref: an XMLXincludeRefPtr * * 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) { +xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlParserInputBufferPtr buf; - xmlNodePtr node; - xmlURIPtr uri; - xmlChar *URL; + xmlNodePtr node = NULL; + const xmlChar *url = ref->URI; int i; + int ret = -1; xmlChar *encoding = NULL; - xmlCharEncoding enc = (xmlCharEncoding) 0; - xmlParserCtxtPtr pctxt; - xmlParserInputPtr inputStream; - int xinclude_multibyte_fallback_used = 0; - - /* Don't read from stdin. */ - if (xmlStrcmp(url, BAD_CAST "-") == 0) - url = BAD_CAST "./-"; - - /* - * Check the URL and remove any fragment identifier - */ - uri = xmlParseURI((const char *)url); - if (uri == NULL) { - xmlXIncludeErr(ctxt, 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); - } + xmlCharEncodingHandlerPtr handler = NULL; + xmlParserCtxtPtr pctxt = NULL; + xmlParserInputPtr inputStream = NULL; + int len; + int res; + const xmlChar *content; /* * 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, + if (url[0] == 0) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_TEXT_DOCUMENT, "text serialization of document not available\n", NULL); - xmlFree(URL); - return(-1); + goto error; } /* - * Prevent reloading twice the document. + * Prevent reloading the document twice. */ for (i = 0; i < ctxt->txtNr; i++) { - if (xmlStrEqual(URL, ctxt->txturlTab[i])) { - node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i]); + if (xmlStrEqual(url, ctxt->txtTab[i].url)) { + node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i].text); + if (node == NULL) + xmlXIncludeErrMemory(ctxt); 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 (ref->elem != NULL) { + encoding = xmlXIncludeGetProp(ctxt, ref->elem, XINCLUDE_PARSE_ENCODING); } if (encoding != NULL) { - /* - * TODO: we should not have to remap to the xmlCharEncoding - * predefined set, a better interface than - * xmlParserInputBufferCreateFilename should allow any - * encoding supported by iconv - */ - enc = xmlParseCharEncoding((const char *) encoding); - if (enc == XML_CHAR_ENCODING_ERROR) { - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, - XML_XINCLUDE_UNKNOWN_ENCODING, - "encoding %s not supported\n", encoding); - xmlFree(encoding); - xmlFree(URL); - return(-1); - } - xmlFree(encoding); + res = xmlOpenCharEncodingHandler((const char *) encoding, + /* output */ 0, &handler); + + if (res != 0) { + if (res == XML_ERR_NO_MEMORY) { + xmlXIncludeErrMemory(ctxt); + } else if (res == XML_ERR_UNSUPPORTED_ENCODING) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING, + "encoding %s not supported\n", encoding); + goto error; + } else { + xmlXIncludeErr(ctxt, ref->elem, res, + "unexpected error from iconv or ICU\n", NULL); + goto error; + } + } } /* * Load it. */ pctxt = xmlNewParserCtxt(); - inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt); - if(inputStream == NULL) { - xmlFreeParserCtxt(pctxt); - xmlFree(URL); - return(-1); + if (pctxt == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; } - buf = inputStream->buf; - if (buf == NULL) { - xmlFreeInputStream (inputStream); - xmlFreeParserCtxt(pctxt); - xmlFree(URL); - return(-1); + if (ctxt->errorHandler != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->errorHandler, ctxt->errorCtxt); + inputStream = xmlLoadExternalEntity((const char*)url, NULL, pctxt); + if (inputStream == NULL) { + /* + * ENOENT only produces a warning which isn't reflected in errNo. + */ + if (pctxt->errNo == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else if ((pctxt->errNo != XML_ERR_OK) && + (pctxt->errNo != XML_IO_ENOENT) && + (pctxt->errNo != XML_IO_UNKNOWN)) + xmlXIncludeErr(ctxt, NULL, pctxt->errNo, "load error", NULL); + goto error; } + buf = inputStream->buf; + if (buf == NULL) + goto error; if (buf->encoder) xmlCharEncCloseFunc(buf->encoder); - buf->encoder = xmlGetCharEncodingHandler(enc); + buf->encoder = handler; + handler = NULL; + node = xmlNewDocText(ctxt->doc, NULL); + if (node == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } /* * Scan all chars from the resource and add the to the node */ -xinclude_multibyte_fallback: - while (xmlParserInputBufferRead(buf, 128) > 0) { - int len; - const xmlChar *content; - - content = xmlBufContent(buf->buffer); - len = xmlBufLength(buf->buffer); - for (i = 0;i < len;) { - int cur; - int l; - - cur = xmlStringCurrentChar(NULL, &content[i], &l); - if (!IS_CHAR(cur)) { - /* Handle split multibyte char at buffer boundary */ - if (((len - i) < 4) && (!xinclude_multibyte_fallback_used)) { - xinclude_multibyte_fallback_used = 1; - xmlBufShrink(buf->buffer, i); - goto xinclude_multibyte_fallback; - } else { - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, - XML_XINCLUDE_INVALID_CHAR, - "%s contains invalid char\n", URL); - xmlFreeParserCtxt(pctxt); - xmlFreeParserInputBuffer(buf); - xmlFree(URL); - return(-1); - } - } else { - xinclude_multibyte_fallback_used = 0; - xmlNodeAddContentLen(node, &content[i], l); - } - i += l; - } - xmlBufShrink(buf->buffer, len); + do { + res = xmlParserInputBufferRead(buf, 4096); + } while (res > 0); + if (res < 0) { + if (buf->error == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, NULL, buf->error, "read error", NULL); + goto error; + } + + content = xmlBufContent(buf->buffer); + len = xmlBufLength(buf->buffer); + for (i = 0; i < len;) { + int cur; + int l; + + l = len - i; + cur = xmlGetUTF8Char(&content[i], &l); + if ((cur < 0) || (!IS_CHAR(cur))) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_INVALID_CHAR, + "%s contains invalid char\n", url); + goto error; + } + + i += l; } - xmlFreeParserCtxt(pctxt); - xmlXIncludeAddTxt(ctxt, node->content, URL); - xmlFreeInputStream(inputStream); + + if (xmlNodeAddContentLen(node, content, len) < 0) + xmlXIncludeErrMemory(ctxt); + + if (ctxt->txtNr >= ctxt->txtMax) { + xmlXIncludeTxt *tmp; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + size_t newSize = ctxt->txtMax ? ctxt->txtMax * 2 : 1; +#else + size_t newSize = ctxt->txtMax ? ctxt->txtMax * 2 : 8; +#endif + + tmp = xmlRealloc(ctxt->txtTab, sizeof(xmlXIncludeTxt) * newSize); + if (tmp == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + ctxt->txtMax = newSize; + ctxt->txtTab = tmp; + } + ctxt->txtTab[ctxt->txtNr].text = xmlStrdup(node->content); + if ((node->content != NULL) && + (ctxt->txtTab[ctxt->txtNr].text == NULL)) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(url); + if (ctxt->txtTab[ctxt->txtNr].url == NULL) { + xmlXIncludeErrMemory(ctxt); + xmlFree(ctxt->txtTab[ctxt->txtNr].text); + goto error; + } + ctxt->txtNr++; loaded: /* * Add the element as the replacement copy. */ - ctxt->incTab[nr]->inc = node; - xmlFree(URL); - return(0); + ref->inc = node; + node = NULL; + ret = 0; + +error: + xmlFreeNode(node); + xmlFreeInputStream(inputStream); + xmlFreeParserCtxt(pctxt); + xmlCharEncCloseFunc(handler); + xmlFree(encoding); + return(ret); } /** * xmlXIncludeLoadFallback: * @ctxt: the XInclude context * @fallback: the fallback node - * @nr: the xinclude node number + * @ref: an XMLXincludeRefPtr * * Load the content of the fallback node, and store the result * in the XInclude context @@ -1963,10 +1775,10 @@ loaded: * Returns 0 in case of success, -1 in case of failure */ static int -xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { - xmlXIncludeCtxtPtr newctxt; +xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, + xmlXIncludeRefPtr ref) { int ret = 0; - int oldNbErrors = ctxt->nbErrors; + int oldNbErrors; if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) || (ctxt == NULL)) @@ -1976,29 +1788,14 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { * 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); - newctxt->incTotal = ctxt->incTotal; - if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0) - ret = -1; - ctxt->incTotal = newctxt->incTotal; + oldNbErrors = ctxt->nbErrors; + ref->inc = xmlXIncludeCopyNode(ctxt, fallback, 1, ref->base); if (ctxt->nbErrors > oldNbErrors) ret = -1; - xmlXIncludeFreeContext(newctxt); - - ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, - fallback->children); - if (ctxt->incTab[nr]->inc == NULL) - ctxt->incTab[nr]->emptyFb = 1; } else { - ctxt->incTab[nr]->inc = NULL; - ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */ + ref->inc = NULL; } - ctxt->incTab[nr]->fallback = 1; + ref->fallback = 1; return(ret); } @@ -2009,143 +1806,110 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { ************************************************************************/ /** - * xmlXIncludePreProcessNode: + * xmlXIncludeExpandNode: * @ctxt: an XInclude context * @node: an XInclude node * - * Implement the XInclude preprocessing, currently just adding the element - * for further processing. + * If the XInclude node wasn't processed yet, create a new RefPtr, + * add it to ctxt->incTab and load the included items. * - * Returns the result list or NULL in case of error + * Returns the new or existing xmlXIncludeRefPtr, or NULL in case of error. */ -static xmlNodePtr -xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { - xmlXIncludeAddNode(ctxt, node); - return(NULL); +static xmlXIncludeRefPtr +xmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + xmlXIncludeRefPtr ref; + int i; + + if (ctxt->fatalErr) + return(NULL); + if (ctxt->depth >= XINCLUDE_MAX_DEPTH) { + xmlXIncludeErr(ctxt, node, XML_XINCLUDE_RECURSION, + "maximum recursion depth exceeded\n", NULL); + ctxt->fatalErr = 1; + return(NULL); + } + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * The XInclude engine offers no protection against exponential + * expansion attacks similar to "billion laughs". Avoid timeouts by + * limiting the total number of replacements when fuzzing. + * + * Unfortuately, a single XInclude can already result in quadratic + * behavior: + * + * + * + * + * + * + * + * + * + * + * + */ + if (ctxt->incTotal >= 20) + return(NULL); + ctxt->incTotal++; +#endif + + for (i = 0; i < ctxt->incNr; i++) { + if (ctxt->incTab[i]->elem == node) { + if (ctxt->incTab[i]->expanding) { + xmlXIncludeErr(ctxt, node, XML_XINCLUDE_RECURSION, + "inclusion loop detected\n", NULL); + return(NULL); + } + return(ctxt->incTab[i]); + } + } + + ref = xmlXIncludeAddNode(ctxt, node); + if (ref == NULL) + return(NULL); + ref->expanding = 1; + ctxt->depth++; + xmlXIncludeLoadNode(ctxt, ref); + ctxt->depth--; + ref->expanding = 0; + + return(ref); } /** * xmlXIncludeLoadNode: * @ctxt: an XInclude context - * @nr: the node number + * @ref: an xmlXIncludeRefPtr * * 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) { +xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlNodePtr cur; - xmlChar *href; - xmlChar *parse; - xmlChar *base; - xmlChar *oldBase; - xmlChar *URI; - int xml = 1; /* default Issue 64 */ int ret; - if (ctxt == NULL) + if ((ctxt == NULL) || (ref == NULL)) return(-1); - if ((nr < 0) || (nr >= ctxt->incNr)) - return(-1); - cur = ctxt->incTab[nr]->ref; + cur = ref->elem; 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); + if (ref->xml) { + ret = xmlXIncludeLoadDoc(ctxt, ref); /* xmlXIncludeGetFragment(ctxt, cur, URI); */ } else { - ret = xmlXIncludeLoadTxt(ctxt, URI, nr); + ret = xmlXIncludeLoadTxt(ctxt, ref); } - /* - * Restore the original base before checking for fallback - */ - ctxt->base = oldBase; - if (ret < 0) { xmlNodePtr children; /* * Time to try a fallback if available */ -#ifdef DEBUG_XINCLUDE - xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n"); -#endif children = cur->children; while (children != NULL) { if ((children->type == XML_ELEMENT_NODE) && @@ -2153,57 +1917,42 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { - ret = xmlXIncludeLoadFallback(ctxt, children, nr); + ret = xmlXIncludeLoadFallback(ctxt, children, ref); break; } children = children->next; } } if (ret < 0) { - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, - XML_XINCLUDE_NO_FALLBACK, + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_FALLBACK, "could not load %s, and no fallback was found\n", - URI); + ref->URI); } - /* - * Cleanup - */ - if (URI != NULL) - xmlFree(URI); - if (parse != NULL) - xmlFree(parse); - if (href != NULL) - xmlFree(href); - if (base != NULL) - xmlFree(base); return(0); } /** * xmlXIncludeIncludeNode: * @ctxt: an XInclude context - * @nr: the node number + * @ref: an xmlXIncludeRefPtr * * Implement the infoset replacement for the given node * * Returns 0 if substitution succeeded, -1 if some processing failed */ static int -xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { +xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlNodePtr cur, end, list, tmp; - if (ctxt == NULL) + if ((ctxt == NULL) || (ref == NULL)) return(-1); - if ((nr < 0) || (nr >= ctxt->incNr)) - return(-1); - cur = ctxt->incTab[nr]->ref; + cur = ref->elem; if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(-1); - list = ctxt->incTab[nr]->inc; - ctxt->incTab[nr]->inc = NULL; - ctxt->incTab[nr]->emptyFb = 0; + list = ref->inc; + ref->inc = NULL; /* * Check against the risk of generating a multi-rooted document @@ -2219,8 +1968,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { tmp = tmp->next; } if (nb_elem > 1) { - xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, - XML_XINCLUDE_MULTIPLE_ROOT, + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_MULTIPLE_ROOT, "XInclude error: would result in multiple root nodes\n", NULL); xmlFreeNodeList(list); @@ -2231,16 +1979,19 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { /* * Add the list of nodes + * + * TODO: Coalesce text nodes unless we are streaming mode. */ while (list != NULL) { end = list; list = list->next; - xmlAddPrevSibling(cur, end); + if (xmlAddPrevSibling(cur, end) == NULL) { + xmlUnlinkNode(end); + xmlFreeNode(end); + goto err_memory; + } } - /* - * FIXME: xmlUnlinkNode doesn't coalesce text nodes. - */ xmlUnlinkNode(cur); xmlFreeNode(cur); } else { @@ -2250,7 +2001,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { * Change the current node as an XInclude start one, and add an * XInclude end one */ - if (ctxt->incTab[nr]->fallback) + if (ref->fallback) xmlUnsetProp(cur, BAD_CAST "href"); cur->type = XML_XINCLUDE_START; /* Remove fallback children */ @@ -2260,15 +2011,13 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { xmlFreeNode(child); } 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); - xmlFreeNodeList(list); - return(-1); - } + if (end == NULL) + goto err_memory; end->type = XML_XINCLUDE_END; - xmlAddNextSibling(cur, end); + if (xmlAddNextSibling(cur, end) == NULL) { + xmlFreeNode(end); + goto err_memory; + } /* * Add the list of nodes @@ -2277,12 +2026,21 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { cur = list; list = list->next; - xmlAddPrevSibling(end, cur); + if (xmlAddPrevSibling(end, cur) == NULL) { + xmlUnlinkNode(cur); + xmlFreeNode(cur); + goto err_memory; + } } } return(0); + +err_memory: + xmlXIncludeErrMemory(ctxt); + xmlFreeNodeList(list); + return(-1); } /** @@ -2364,9 +2122,7 @@ xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { /** * xmlXIncludeDoProcess: * @ctxt: the XInclude processing context - * @doc: an XML document * @tree: the top of the tree to process - * @skipRoot: don't process the root node of the tree * * Implement the XInclude substitution on the XML document @doc * @@ -2374,63 +2130,26 @@ xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { * or the number of substitutions done. */ static int -xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, - int skipRoot) { +xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { + xmlXIncludeRefPtr ref; xmlNodePtr cur; int ret = 0; int i, start; - if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) - return(-1); - if ((skipRoot) && (tree->children == 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; - - /* - * TODO: The phases must run separately for recursive inclusions. - * - * - Phase 1 should start with top-level XInclude nodes, load documents, - * execute XPointer expressions, then process only the result nodes - * (not whole document, see bug #324081) and only for phase 1 - * recursively. We will need a backreference from xmlNodes to - * xmlIncludeRefs to detect references that were already visited. - * This can also be used for proper cycle detection, see bug #344240. - * - * - Phase 2 should visit all top-level XInclude nodes and expand - * possible subreferences in the replacement recursively. - * - * - Phase 3 should finally replace the top-level XInclude nodes. - * It could also be run together with phase 2. - */ - /* * First phase: lookup the elements in the document */ - if (skipRoot) - cur = tree->children; - else - cur = tree; + start = ctxt->incNr; + cur = tree; do { /* TODO: need to work on entities -> stack */ if (xmlXIncludeTestNode(ctxt, cur) == 1) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ref = xmlXIncludeExpandNode(ctxt, cur); /* - * Avoid superlinear expansion by limiting the total number - * of replacements. + * Mark direct includes. */ - if (ctxt->incTotal >= 20) - return(-1); -#endif - ctxt->incTotal++; - xmlXIncludePreProcessNode(ctxt, cur); + if (ref != NULL) + ref->replace = 1; } else if ((cur->children != NULL) && ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_ELEMENT_NODE))) { @@ -2449,35 +2168,95 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, } while ((cur != NULL) && (cur != tree)); /* - * Second Phase : collect the infosets fragments + * Second phase: extend the original document infoset. */ - for (i = start;i < ctxt->incNr; i++) { - xmlXIncludeLoadNode(ctxt, i); + for (i = start; i < ctxt->incNr; i++) { + if (ctxt->incTab[i]->replace != 0) { + xmlXIncludeIncludeNode(ctxt, ctxt->incTab[i]); + ctxt->incTab[i]->replace = 0; + } else { + /* + * Ignore includes which were added indirectly, for example + * inside xi:fallback elements. + */ + if (ctxt->incTab[i]->inc != NULL) { + xmlFreeNodeList(ctxt->incTab[i]->inc); + ctxt->incTab[i]->inc = NULL; + } + } 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]->emptyFb != 0)) /* (empty fallback) */ - xmlXIncludeIncludeNode(ctxt, i); + if (ctxt->isStream) { + /* + * incTab references nodes which will eventually be deleted in + * streaming mode. The table is only required for XPointer + * expressions which aren't allowed in streaming mode. + */ + for (i = 0;i < ctxt->incNr;i++) { + xmlXIncludeFreeRef(ctxt->incTab[i]); + } + ctxt->incNr = 0; } - if (doc->URL != NULL) - xmlXIncludeURLPop(ctxt); return(ret); } +/** + * xmlXIncludeDoProcessRoot: + * @ctxt: the XInclude processing context + * @tree: the top of the tree to process + * + * Implement the XInclude substitution on the XML document @doc + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ +static int +xmlXIncludeDoProcessRoot(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { + if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) + return(-1); + if (ctxt == NULL) + return(-1); + + return(xmlXIncludeDoProcess(ctxt, tree)); +} + +/** + * xmlXIncludeGetLastError: + * @ctxt: an XInclude processing context + * + * Available since 2.13.0. + * + * Returns the last error code. + */ +int +xmlXIncludeGetLastError(xmlXIncludeCtxtPtr ctxt) { + if (ctxt == NULL) + return(XML_ERR_ARGUMENT); + return(ctxt->errNo); +} + +/** + * xmlXIncludeSetErrorHandler: + * @ctxt: an XInclude processing context + * @handler: error handler + * @data: user data which will be passed to the handler + * + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * Available since 2.13.0. + */ +void +xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt, + xmlStructuredErrorFunc handler, void *data) { + if (ctxt == NULL) + return; + ctxt->errorHandler = handler; + ctxt->errorCtxt = data; +} + /** * xmlXIncludeSetFlags: * @ctxt: an XInclude processing context @@ -2495,6 +2274,23 @@ xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { return(0); } +/** + * xmlXIncludeSetStreamingMode: + * @ctxt: an XInclude processing context + * @mode: whether streaming mode should be enabled + * + * In streaming mode, XPointer expressions aren't allowed. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlXIncludeSetStreamingMode(xmlXIncludeCtxtPtr ctxt, int mode) { + if (ctxt == NULL) + return(-1); + ctxt->isStream = !!mode; + return(0); +} + /** * xmlXIncludeProcessTreeFlagsData: * @tree: an XML node @@ -2521,9 +2317,8 @@ xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { if (ctxt == NULL) return(-1); ctxt->_private = data; - ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); xmlXIncludeSetFlags(ctxt, flags); - ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0); + ret = xmlXIncludeDoProcessRoot(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; @@ -2605,9 +2400,8 @@ xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { ctxt = xmlXIncludeNewContext(tree->doc); if (ctxt == NULL) return(-1); - ctxt->base = xmlNodeGetBase(tree->doc, tree); xmlXIncludeSetFlags(ctxt, flags); - ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0); + ret = xmlXIncludeDoProcessRoot(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; @@ -2647,7 +2441,7 @@ xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (node->doc == NULL) || (ctxt == NULL)) return(-1); - ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0); + ret = xmlXIncludeDoProcessRoot(ctxt, node); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; return(ret); diff --git a/xlink.c b/xlink.c index 65715cb3a8f..3a77b1999de 100644 --- a/xlink.c +++ b/xlink.c @@ -19,9 +19,7 @@ #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/") diff --git a/xmlIO.c b/xmlIO.c index e47e2b15274..353771b7f25 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -4,8 +4,6 @@ * See Copyright for the status of this software. * * daniel@veillard.com - * - * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char */ #define IN_LIBXML @@ -15,9 +13,6 @@ #include #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif #ifdef HAVE_SYS_STAT_H #include #endif @@ -41,22 +36,8 @@ #include #endif -#ifndef S_ISDIR -# ifdef _S_ISDIR -# define S_ISDIR(x) _S_ISDIR(x) -# elif defined(S_IFDIR) -# ifdef S_IFMT -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -# elif defined(_S_IFMT) -# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) -# endif -# endif -#endif - -#include -#include -#include #include +#include #include #include #include @@ -64,19 +45,31 @@ #ifdef LIBXML_CATALOG_ENABLED #include #endif -#include -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" +#include "private/io.h" +#include "private/parser.h" /* #define VERBOSE_FAILURE */ -/* #define DEBUG_EXTERNAL_ENTITIES */ -/* #define DEBUG_INPUT */ -#ifdef DEBUG_INPUT -#define MINLEN 40 -#else #define MINLEN 4000 + +#ifndef STDOUT_FILENO + #define STDOUT_FILENO 1 +#endif + +#ifndef S_ISDIR +# ifdef _S_ISDIR +# define S_ISDIR(x) _S_ISDIR(x) +# elif defined(S_IFDIR) +# ifdef S_IFMT +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# elif defined(_S_IFMT) +# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) +# endif +# endif #endif /* @@ -89,11 +82,14 @@ typedef struct _xmlInputCallback { xmlInputCloseCallback closecallback; } xmlInputCallback; -#define MAX_INPUT_CALLBACK 15 +/* This dummy function only marks default IO in the callback table */ +static int +xmlIODefaultMatch(const char *filename); + +#define MAX_INPUT_CALLBACK 10 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; -static int xmlInputCallbackNr = 0; -static int xmlInputCallbackInitialized = 0; +static int xmlInputCallbackNr; #ifdef LIBXML_OUTPUT_ENABLED /* @@ -106,114 +102,18 @@ typedef struct _xmlOutputCallback { xmlOutputCloseCallback closecallback; } xmlOutputCallback; -#define MAX_OUTPUT_CALLBACK 15 +#define MAX_OUTPUT_CALLBACK 10 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; -static int xmlOutputCallbackNr = 0; -static int xmlOutputCallbackInitialized = 0; - -xmlOutputBufferPtr -xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); +static int xmlOutputCallbackNr; #endif /* LIBXML_OUTPUT_ENABLED */ /************************************************************************ * * - * Tree memory error handler * + * Error handling * * * ************************************************************************/ -static const char* const IOerr[] = { - "Unknown IO error", /* UNKNOWN */ - "Permission denied", /* EACCES */ - "Resource temporarily unavailable",/* EAGAIN */ - "Bad file descriptor", /* EBADF */ - "Bad message", /* EBADMSG */ - "Resource busy", /* EBUSY */ - "Operation canceled", /* ECANCELED */ - "No child processes", /* ECHILD */ - "Resource deadlock avoided",/* EDEADLK */ - "Domain error", /* EDOM */ - "File exists", /* EEXIST */ - "Bad address", /* EFAULT */ - "File too large", /* EFBIG */ - "Operation in progress", /* EINPROGRESS */ - "Interrupted function call",/* EINTR */ - "Invalid argument", /* EINVAL */ - "Input/output error", /* EIO */ - "Is a directory", /* EISDIR */ - "Too many open files", /* EMFILE */ - "Too many links", /* EMLINK */ - "Inappropriate message buffer length",/* EMSGSIZE */ - "Filename too long", /* ENAMETOOLONG */ - "Too many open files in system",/* ENFILE */ - "No such device", /* ENODEV */ - "No such file or directory",/* ENOENT */ - "Exec format error", /* ENOEXEC */ - "No locks available", /* ENOLCK */ - "Not enough space", /* ENOMEM */ - "No space left on device", /* ENOSPC */ - "Function not implemented", /* ENOSYS */ - "Not a directory", /* ENOTDIR */ - "Directory not empty", /* ENOTEMPTY */ - "Not supported", /* ENOTSUP */ - "Inappropriate I/O control operation",/* ENOTTY */ - "No such device or address",/* ENXIO */ - "Operation not permitted", /* EPERM */ - "Broken pipe", /* EPIPE */ - "Result too large", /* ERANGE */ - "Read-only file system", /* EROFS */ - "Invalid seek", /* ESPIPE */ - "No such process", /* ESRCH */ - "Operation timed out", /* ETIMEDOUT */ - "Improper link", /* EXDEV */ - "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ - "encoder error", /* XML_IO_ENCODER */ - "flush error", - "write error", - "no input", - "buffer full", - "loading error", - "not a socket", /* ENOTSOCK */ - "already connected", /* EISCONN */ - "connection refused", /* ECONNREFUSED */ - "unreachable network", /* ENETUNREACH */ - "address in use", /* EADDRINUSE */ - "already in use", /* EALREADY */ - "unknown address family", /* EAFNOSUPPORT */ -}; - -#if defined(_WIN32) -/** - * __xmlIOWin32UTF8ToWChar: - * @u8String: uft-8 string - * - * Convert a string from utf-8 to wchar (WINDOWS ONLY!) - */ -static wchar_t * -__xmlIOWin32UTF8ToWChar(const char *u8String) -{ - wchar_t *wString = NULL; - - if (u8String) { - int wLen = - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, - -1, NULL, 0); - if (wLen) { - wString = xmlMalloc(wLen * sizeof(wchar_t)); - if (wString) { - if (MultiByteToWideChar - (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { - xmlFree(wString); - wString = NULL; - } - } - } - } - - return wString; -} -#endif - /** * xmlIOErrMemory: * @extra: extra information @@ -221,9 +121,9 @@ __xmlIOWin32UTF8ToWChar(const char *u8String) * Handle an out of memory condition */ static void -xmlIOErrMemory(const char *extra) +xmlIOErrMemory(void) { - __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL); } /** @@ -234,13 +134,17 @@ xmlIOErrMemory(const char *extra) * * Handle an I/O error */ -void +int __xmlIOErr(int domain, int code, const char *extra) { - unsigned int idx; + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + const char *fmt, *arg1, *arg2; + int res; if (code == 0) { - if (errno == 0) code = 0; + if (errno == 0) code = XML_IO_UNKNOWN; #ifdef EACCES else if (errno == EACCES) code = XML_IO_EACCES; #endif @@ -396,189 +300,49 @@ __xmlIOErr(int domain, int code, const char *extra) #endif else code = XML_IO_UNKNOWN; } - idx = 0; - if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN; - if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0; - - __xmlSimpleError(domain, code, NULL, IOerr[idx], extra); -} - -/** - * xmlIOErr: - * @code: the error number - * @extra: extra information - * - * Handle an I/O error - */ -static void -xmlIOErr(int code, const char *extra) -{ - __xmlIOErr(XML_FROM_IO, code, extra); -} -/** - * __xmlLoaderErr: - * @ctx: the parser context - * @extra: extra information - * - * Handle a resource access error - */ -void -__xmlLoaderErr(void *ctx, const char *msg, const char *filename) -{ - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - void *data = NULL; - xmlErrorLevel level = XML_ERR_ERROR; - - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if ((ctxt != NULL) && (ctxt->sax != NULL)) { - if (ctxt->validate) { - channel = ctxt->sax->error; - level = XML_ERR_ERROR; - } else { - channel = ctxt->sax->warning; - level = XML_ERR_WARNING; - } - if (ctxt->sax->initialized == XML_SAX2_MAGIC) - schannel = ctxt->sax->serror; - data = ctxt->userData; + if (xmlStructuredError) { + schannel = xmlStructuredError; + data = xmlStructuredErrorContext; + } else { + channel = xmlGenericError; + data = xmlGenericErrorContext; } - __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO, - XML_IO_LOAD_ERROR, level, NULL, 0, - filename, NULL, NULL, 0, 0, - msg, filename); - -} - -/************************************************************************ - * * - * Tree memory error handler * - * * - ************************************************************************/ -/** - * xmlNormalizeWindowsPath: - * @path: the input file path - * - * This function is obsolete. Please see xmlURIFromPath in uri.c for - * a better solution. - * - * Returns a canonicalized version of the path - */ -xmlChar * -xmlNormalizeWindowsPath(const xmlChar *path) -{ - return xmlCanonicPath(path); -} - -/** - * xmlCleanupInputCallbacks: - * - * clears the entire input callback table. this includes the - * compiled-in I/O. - */ -void -xmlCleanupInputCallbacks(void) -{ - int i; - - if (!xmlInputCallbackInitialized) - return; - for (i = xmlInputCallbackNr - 1; i >= 0; i--) { - xmlInputCallbackTable[i].matchcallback = NULL; - xmlInputCallbackTable[i].opencallback = NULL; - xmlInputCallbackTable[i].readcallback = NULL; - xmlInputCallbackTable[i].closecallback = NULL; + if (extra != NULL) { + fmt = "%s: %s"; + } else { + fmt = "%s"; } - xmlInputCallbackNr = 0; - xmlInputCallbackInitialized = 0; -} - -/** - * xmlPopInputCallbacks: - * - * Clear the top input callback from the input stack. this includes the - * compiled-in I/O. - * - * Returns the number of input callback registered or -1 in case of error. - */ -int -xmlPopInputCallbacks(void) -{ - if (!xmlInputCallbackInitialized) - return(-1); - - if (xmlInputCallbackNr <= 0) - return(-1); - - xmlInputCallbackNr--; - xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL; - - return(xmlInputCallbackNr); -} - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlCleanupOutputCallbacks: - * - * clears the entire output callback table. this includes the - * compiled-in I/O callbacks. - */ -void -xmlCleanupOutputCallbacks(void) -{ - int i; - - if (!xmlOutputCallbackInitialized) - return; + arg1 = xmlErrString(code); + arg2 = extra; - for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { - xmlOutputCallbackTable[i].matchcallback = NULL; - xmlOutputCallbackTable[i].opencallback = NULL; - xmlOutputCallbackTable[i].writecallback = NULL; - xmlOutputCallbackTable[i].closecallback = NULL; + res = __xmlRaiseError(schannel, channel, data, NULL, NULL, + domain, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + fmt, arg1, arg2); + if (res < 0) { + xmlIOErrMemory(); + return(XML_ERR_NO_MEMORY); } - xmlOutputCallbackNr = 0; - xmlOutputCallbackInitialized = 0; + return(code); } /** - * xmlPopOutputCallbacks: - * - * Remove the top output callbacks from the output stack. This includes the - * compiled-in I/O. + * xmlIOErr: + * @code: the error number + * @extra: extra information * - * Returns the number of output callback registered or -1 in case of error. + * Handle an I/O error */ -int -xmlPopOutputCallbacks(void) +static int +xmlIOErr(int code, const char *extra) { - if (!xmlOutputCallbackInitialized) - return(-1); - - if (xmlOutputCallbackNr <= 0) - return(-1); - - xmlOutputCallbackNr--; - xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL; - - return(xmlOutputCallbackNr); + return(__xmlIOErr(XML_FROM_IO, code, extra)); } -#endif /* LIBXML_OUTPUT_ENABLED */ - /************************************************************************ * * * Standard I/O for file accesses * @@ -588,92 +352,65 @@ xmlPopOutputCallbacks(void) #if defined(_WIN32) /** - * xmlWrapOpenUtf8: - * @path: the path in utf-8 encoding - * @mode: type of access (0 - read, 1 - write) - * - * function opens the file specified by @path + * __xmlIOWin32UTF8ToWChar: + * @u8String: uft-8 string * + * Convert a string from utf-8 to wchar (WINDOWS ONLY!) */ -static FILE* -xmlWrapOpenUtf8(const char *path,int mode) -{ - FILE *fd = NULL; - wchar_t *wPath; - - wPath = __xmlIOWin32UTF8ToWChar(path); - if(wPath) - { - fd = _wfopen(wPath, mode ? L"wb" : L"rb"); - xmlFree(wPath); - } - /* maybe path in native encoding */ - if(fd == NULL) - fd = fopen(path, mode ? "wb" : "rb"); - - return fd; -} - -#ifdef LIBXML_ZLIB_ENABLED -static gzFile -xmlWrapGzOpenUtf8(const char *path, const char *mode) +static wchar_t * +__xmlIOWin32UTF8ToWChar(const char *u8String) { - gzFile fd; - wchar_t *wPath; + wchar_t *wString = NULL; + int i; - fd = gzopen (path, mode); - if (fd) - return fd; + if (u8String) { + int wLen = + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, + -1, NULL, 0); + if (wLen) { + wString = xmlMalloc(wLen * sizeof(wchar_t)); + if (wString) { + if (MultiByteToWideChar + (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { + xmlFree(wString); + wString = NULL; + } + } - wPath = __xmlIOWin32UTF8ToWChar(path); - if(wPath) - { - int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR); -#ifdef _O_BINARY - m |= (strstr(mode, "b") ? _O_BINARY : 0); -#endif - d = _wopen(wPath, m); - if (d >= 0) - fd = gzdopen(d, mode); - xmlFree(wPath); + /* + * Convert to backward slash + */ + for (i = 0; wString[i] != 0; i++) { + if (wString[i] == '/') + wString[i] = '\\'; + } + } } - return fd; + return wString; } + #endif /** - * xmlWrapStatUtf8: - * @path: the path in utf-8 encoding - * @info: structure that stores results + * xmlNormalizeWindowsPath: + * @path: the input file path * - * function obtains information about the file or directory + * DEPRECATED: This never really worked. * + * Returns a copy of path. */ -static int -xmlWrapStatUtf8(const char *path, struct _stat *info) { - int retval = -1; - wchar_t *wPath; - - wPath = __xmlIOWin32UTF8ToWChar(path); - if (wPath) { - retval = _wstat(wPath, info); - xmlFree(wPath); - } - /* maybe path in native encoding */ - if(retval < 0) - retval = _stat(path, info); - return retval; +xmlChar * +xmlNormalizeWindowsPath(const xmlChar *path) +{ + return xmlStrdup(path); } -#endif - /** * xmlCheckFilename: * @path: the path to check * - * function checks to see if @path is a valid source - * (file, socket...) for XML. + * DEPRECATED: Internal function, don't use. * * if stat is not available on the target machine, * returns 1. if stat fails, returns 0 (if calling @@ -681,9 +418,8 @@ xmlWrapStatUtf8(const char *path, struct _stat *info) { * if stat succeeds and the file is a directory, * returns 2. otherwise returns 1. */ - int -xmlCheckFilename (const char *path) +xmlCheckFilename(const char *path) { #ifdef HAVE_STAT #if defined(_WIN32) @@ -691,46 +427,147 @@ xmlCheckFilename (const char *path) #else struct stat stat_buffer; #endif + int res; #endif + if (path == NULL) return(0); #ifdef HAVE_STAT #if defined(_WIN32) - /* - * On Windows stat and wstat do not work with long pathname, - * which start with '\\?\' - */ - if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') && - (path[3] == '\\') ) - return 1; + { + wchar_t *wpath; - if (xmlWrapStatUtf8(path, &stat_buffer) == -1) - return 0; + /* + * On Windows stat and wstat do not work with long pathname, + * which start with '\\?\' + */ + if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') && + (path[3] == '\\') ) + return 1; + + wpath = __xmlIOWin32UTF8ToWChar(path); + if (wpath == NULL) + return(0); + res = _wstat(wpath, &stat_buffer); + xmlFree(wpath); + } #else - if (stat(path, &stat_buffer) == -1) - return 0; + res = stat(path, &stat_buffer); #endif + + if (res < 0) + return 0; + #ifdef S_ISDIR if (S_ISDIR(stat_buffer.st_mode)) return 2; #endif #endif /* HAVE_STAT */ + return 1; } -/** - * xmlInputReadCallbackNop: - * - * No Operation xmlInputReadCallback function, does nothing. - * - * Returns zero - */ -int -xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED, - char *buffer ATTRIBUTE_UNUSED, - int len ATTRIBUTE_UNUSED) { - return(0); +static int +xmlConvertUriToPath(const char *uri, char **out) { + const char *escaped; + char *unescaped; + + *out = NULL; + + if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) { + escaped = &uri[16]; + } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) { + escaped = &uri[7]; + } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) { + /* lots of generators seems to lazy to read RFC 1738 */ + escaped = &uri[5]; + } else { + return(1); + } + +#ifdef _WIN32 + /* Ignore slash like in file:///C:/file.txt */ + escaped += 1; +#endif + + unescaped = xmlURIUnescapeString(escaped, 0, NULL); + if (unescaped == NULL) + return(-1); + + *out = unescaped; + return(0); +} + +/** + * xmlFdOpen: + * @filename: the URI for matching + * @out: pointer to resulting context + * + * Returns an xmlParserErrors code + */ +static int +xmlFdOpen(const char *filename, int write, int *out) { + char *fromUri = NULL; + int flags; + int fd; + int ret; + + *out = -1; + if (filename == NULL) + return(XML_ERR_ARGUMENT); + + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(XML_ERR_NO_MEMORY); + + if (fromUri != NULL) + filename = fromUri; + +#if defined(_WIN32) + { + wchar_t *wpath; + + wpath = __xmlIOWin32UTF8ToWChar(filename); + if (wpath == NULL) { + xmlFree(fromUri); + return(XML_ERR_NO_MEMORY); + } + if (write) + flags = _O_WRONLY | _O_CREAT | _O_TRUNC; + else + flags = _O_RDONLY; + fd = _wopen(wpath, flags | _O_BINARY, 0666); + xmlFree(wpath); + } +#else + if (write) + flags = O_WRONLY | O_CREAT | O_TRUNC; + else + flags = O_RDONLY; + fd = open(filename, flags, 0666); +#endif /* WIN32 */ + + if (fd < 0) { + /* + * Windows and possibly other platforms return EINVAL + * for invalid filenames. + */ + if ((errno == ENOENT) || (errno == EINVAL)) { + ret = XML_IO_ENOENT; + } else { + /* + * This error won't be forwarded to the parser context + * which will report it a second time. + */ + ret = xmlIOErr(0, filename); + } + } else { + *out = fd; + ret = XML_ERR_OK; + } + + xmlFree(fromUri); + return(ret); } /** @@ -741,14 +578,32 @@ xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED, * * Read @len bytes to @buffer from the I/O channel. * - * Returns the number of bytes written + * Returns the number of bytes read */ static int -xmlFdRead (void * context, char * buffer, int len) { - int ret; +xmlFdRead(void *context, char *buffer, int len) { + int fd = (int) (ptrdiff_t) context; + int ret = 0; + int bytes; + + while (len > 0) { + bytes = read(fd, buffer, len); + if (bytes < 0) { + /* + * If we already got some bytes, return them without + * raising an error. + */ + if (ret > 0) + break; + return(-xmlIOErr(0, "read()")); + } + if (bytes == 0) + break; + ret += bytes; + buffer += bytes; + len -= bytes; + } - ret = read((int) (ptrdiff_t) context, &buffer[0], len); - if (ret < 0) xmlIOErr(0, "read()"); return(ret); } @@ -764,13 +619,20 @@ xmlFdRead (void * context, char * buffer, int len) { * Returns the number of bytes written */ static int -xmlFdWrite (void * context, const char * buffer, int len) { +xmlFdWrite(void *context, const char *buffer, int len) { + int fd = (int) (ptrdiff_t) context; int ret = 0; + int bytes; - if (len > 0) { - ret = write((int) (ptrdiff_t) context, &buffer[0], len); - if (ret < 0) xmlIOErr(0, "write()"); + while (len > 0) { + bytes = write(fd, buffer, len); + if (bytes < 0) + return(-xmlIOErr(0, "write()")); + ret += bytes; + buffer += bytes; + len -= bytes; } + return(ret); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -786,16 +648,19 @@ xmlFdWrite (void * context, const char * buffer, int len) { static int xmlFdClose (void * context) { int ret; + ret = close((int) (ptrdiff_t) context); - if (ret < 0) xmlIOErr(0, "close()"); - return(ret); + if (ret < 0) + return(xmlIOErr(0, "close()")); + + return(XML_ERR_OK); } /** * xmlFileMatch: * @filename: the URI for matching * - * input from FILE * + * DEPRECATED: Internal function, don't use. * * Returns 1 if matches, 0 otherwise */ @@ -805,139 +670,82 @@ xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { } /** - * xmlFileOpen_real: + * xmlFileOpenSafe: * @filename: the URI for matching + * @out: pointer to resulting context * - * input from FILE *, supports compressed input - * if @filename is " " then the standard input is used + * input from FILE * * * Returns an I/O context or NULL in case of error */ -static void * -xmlFileOpen_real (const char *filename) { - const char *path = filename; +static int +xmlFileOpenSafe(const char *filename, int write, void **out) { + char *fromUri = NULL; FILE *fd; + int ret = XML_ERR_OK; + *out = NULL; if (filename == NULL) - return(NULL); + return(XML_ERR_ARGUMENT); - if (!strcmp(filename, "-")) { - fd = stdin; - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { - /* lots of generators seems to lazy to read RFC 1738 */ -#if defined (_WIN32) - path = &filename[6]; -#else - path = &filename[5]; -#endif - } + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(XML_ERR_NO_MEMORY); - /* Do not check DDNAME on zOS ! */ -#if !defined(__MVS__) - if (!xmlCheckFilename(path)) - return(NULL); -#endif + if (fromUri != NULL) + filename = fromUri; #if defined(_WIN32) - fd = xmlWrapOpenUtf8(path, 0); + { + wchar_t *wpath; + + wpath = __xmlIOWin32UTF8ToWChar(filename); + if (wpath == NULL) { + xmlFree(fromUri); + return(XML_ERR_NO_MEMORY); + } + fd = _wfopen(wpath, write ? L"wb" : L"rb"); + xmlFree(wpath); + } #else - fd = fopen(path, "rb"); + fd = fopen(filename, write ? "wb" : "rb"); #endif /* WIN32 */ - if (fd == NULL) xmlIOErr(0, path); - return((void *) fd); -} -/** - * xmlFileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlFileOpen_real that try it with an unescaped - * version of @filename, if this fails fallback to @filename - * - * Returns a handler or NULL in case or failure - */ -void * -xmlFileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlFileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlFileOpen_real(unescaped); - xmlFree(unescaped); - } + if (fd == NULL) { + /* + * Windows and possibly other platforms return EINVAL + * for invalid filenames. + */ + if ((errno == ENOENT) || (errno == EINVAL)) { + ret = XML_IO_ENOENT; + } else { + /* + * This error won't be forwarded to the parser context + * which will report it a second time. + */ + ret = xmlIOErr(0, filename); + } } - return retval; + *out = fd; + xmlFree(fromUri); + return(ret); } -#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlFileOpenW: + * xmlFileOpen: * @filename: the URI for matching * - * output to from FILE *, - * if @filename is "-" then the standard output is used + * DEPRECATED: Internal function, don't use. * - * Returns an I/O context or NULL in case of error + * Returns an IO context or NULL in case or failure */ -static void * -xmlFileOpenW (const char *filename) { - const char *path = NULL; - FILE *fd; - - if (!strcmp(filename, "-")) { - fd = stdout; - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapOpenUtf8(path, 1); -#elif(__MVS__) - fd = fopen(path, "w"); -#else - fd = fopen(path, "wb"); -#endif /* WIN32 */ +void * +xmlFileOpen(const char *filename) { + void *context; - if (fd == NULL) xmlIOErr(0, path); - return((void *) fd); + xmlFileOpenSafe(filename, 0, &context); + return(context); } -#endif /* LIBXML_OUTPUT_ENABLED */ /** * xmlFileRead: @@ -945,18 +753,30 @@ xmlFileOpenW (const char *filename) { * @buffer: where to drop data * @len: number of bytes to write * - * Read @len bytes to @buffer from the I/O channel. + * DEPRECATED: Internal function, don't use. * - * Returns the number of bytes written or < 0 in case of failure + * Returns the number of bytes read or < 0 in case of failure */ int -xmlFileRead (void * context, char * buffer, int len) { - int ret; +xmlFileRead(void * context, char * buffer, int len) { + FILE *file = context; + size_t bytes; + if ((context == NULL) || (buffer == NULL)) return(-1); - ret = fread(&buffer[0], 1, len, (FILE *) context); - if (ret < 0) xmlIOErr(0, "fread()"); - return(ret); + + /* + * The C standard doesn't mandate that fread sets errno, only + * POSIX does. The Windows documentation isn't really clear. + * Set errno to zero which will be reported as unknown error + * if fread fails without setting errno. + */ + errno = 0; + bytes = fread(buffer, 1, len, file); + if ((bytes < (size_t) len) && (ferror(file))) + return(-xmlIOErr(0, "fread()")); + + return(bytes); } #ifdef LIBXML_OUTPUT_ENABLED @@ -971,66 +791,65 @@ xmlFileRead (void * context, char * buffer, int len) { * Returns the number of bytes written */ static int -xmlFileWrite (void * context, const char * buffer, int len) { - int items; +xmlFileWrite(void *context, const char *buffer, int len) { + FILE *file = context; + size_t bytes; if ((context == NULL) || (buffer == NULL)) return(-1); - items = fwrite(&buffer[0], len, 1, (FILE *) context); - if ((items == 0) && (ferror((FILE *) context))) { - xmlIOErr(0, "fwrite()"); - return(-1); - } - return(items * len); + + errno = 0; + bytes = fwrite(buffer, 1, len, file); + if (bytes < (size_t) len) + return(-xmlIOErr(0, "fwrite()")); + + return(len); } #endif /* LIBXML_OUTPUT_ENABLED */ /** - * xmlFileClose: + * xmlFileFlush: * @context: the I/O context * - * Close an I/O channel - * - * Returns 0 or -1 in case of error + * Flush an I/O channel */ -int -xmlFileClose (void * context) { - FILE *fil; - int ret; +static int +xmlFileFlush (void * context) { + FILE *file = context; - if (context == NULL) + if (file == NULL) return(-1); - fil = (FILE *) context; - if ((fil == stdout) || (fil == stderr)) { - ret = fflush(fil); - if (ret < 0) - xmlIOErr(0, "fflush()"); - return(0); - } - if (fil == stdin) - return(0); - ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0; - if (ret < 0) - xmlIOErr(0, "fclose()"); - return(ret); + + if (fflush(file) != 0) + return(xmlIOErr(0, "fflush()")); + + return(XML_ERR_OK); } /** - * xmlFileFlush: + * xmlFileClose: * @context: the I/O context * - * Flush an I/O channel + * DEPRECATED: Internal function, don't use. + * + * Returns 0 or -1 an error code case of error */ -static int -xmlFileFlush (void * context) { - int ret; +int +xmlFileClose (void * context) { + FILE *file = context; if (context == NULL) return(-1); - ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0; - if (ret < 0) - xmlIOErr(0, "fflush()"); - return(ret); + + if (file == stdin) + return(0); + if ((file == stdout) || (file == stderr)) + return(xmlFileFlush(file)); + + if (fclose(file) != 0) + return(xmlIOErr(0, "fclose()")); + + return(0); } #ifdef LIBXML_OUTPUT_ENABLED @@ -1042,7 +861,8 @@ xmlFileFlush (void * context) { * * Write @len bytes from @buffer to the xml buffer * - * Returns the number of bytes written + * Returns the number of bytes written or a negative xmlParserErrors + * value. */ static int xmlBufferWrite (void * context, const char * buffer, int len) { @@ -1050,7 +870,7 @@ xmlBufferWrite (void * context, const char * buffer, int len) { ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len); if (ret != 0) - return(-1); + return(-XML_ERR_NO_MEMORY); return(len); } #endif @@ -1061,148 +881,6 @@ xmlBufferWrite (void * context, const char * buffer, int len) { * I/O for compressed file accesses * * * ************************************************************************/ -/** - * xmlGzfileMatch: - * @filename: the URI for matching - * - * input from compressed file test - * - * Returns 1 if matches, 0 otherwise - */ -static int -xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) { - return(1); -} - -/** - * xmlGzfileOpen_real: - * @filename: the URI for matching - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlGzfileOpen_real (const char *filename) { - const char *path = NULL; - gzFile fd; - - if (!strcmp(filename, "-")) { - int duped_fd = dup(fileno(stdin)); - fd = gzdopen(duped_fd, "rb"); - if (fd == Z_NULL && duped_fd >= 0) { - close(duped_fd); /* gzdOpen() does not close on failure */ - } - - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - if (!xmlCheckFilename(path)) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapGzOpenUtf8(path, "rb"); -#else - fd = gzopen(path, "rb"); -#endif - return((void *) fd); -} - -/** - * xmlGzfileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlGzfileOpen_real if the open fails, it will - * try to unescape @filename - */ -static void * -xmlGzfileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlGzfileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlGzfileOpen_real(unescaped); - } - xmlFree(unescaped); - } - return retval; -} - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlGzfileOpenW: - * @filename: the URI for matching - * @compression: the compression factor (0 - 9 included) - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlGzfileOpenW (const char *filename, int compression) { - const char *path = NULL; - char mode[15]; - gzFile fd; - - snprintf(mode, sizeof(mode), "wb%d", compression); - if (!strcmp(filename, "-")) { - int duped_fd = dup(fileno(stdout)); - fd = gzdopen(duped_fd, "rb"); - if (fd == Z_NULL && duped_fd >= 0) { - close(duped_fd); /* gzdOpen() does not close on failure */ - } - - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapGzOpenUtf8(path, mode); -#else - fd = gzopen(path, mode); -#endif - return((void *) fd); -} -#endif /* LIBXML_OUTPUT_ENABLED */ /** * xmlGzfileRead: @@ -1260,112 +938,38 @@ xmlGzfileClose (void * context) { } #endif /* LIBXML_ZLIB_ENABLED */ -#ifdef LIBXML_LZMA_ENABLED /************************************************************************ * * * I/O for compressed file accesses * * * ************************************************************************/ -#include "xzlib.h" + +#ifdef LIBXML_LZMA_ENABLED + +#include "private/xzlib.h" + /** - * xmlXzfileMatch: - * @filename: the URI for matching + * xmlXzfileRead: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to write * - * input from compressed file test + * Read @len bytes to @buffer from the compressed I/O channel. * - * Returns 1 if matches, 0 otherwise + * Returns the number of bytes written */ static int -xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) { - return(1); +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); } /** - * xmlXzFileOpen_real: - * @filename: the URI for matching - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlXzfileOpen_real (const char *filename) { - const char *path = NULL; - xzFile fd; - - if (!strcmp(filename, "-")) { - fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb"); - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { - path = &filename[16]; - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { - path = &filename[7]; - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { - /* lots of generators seems to lazy to read RFC 1738 */ - path = &filename[5]; - } else - path = filename; - - if (path == NULL) - return(NULL); - if (!xmlCheckFilename(path)) - return(NULL); - - fd = __libxml2_xzopen(path, "rb"); - return((void *) fd); -} - -/** - * xmlXzfileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlXzfileOpen_real that try it with an unescaped - * version of @filename, if this fails fallback to @filename - * - * Returns a handler or NULL in case or failure - */ -static void * -xmlXzfileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlXzfileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlXzfileOpen_real(unescaped); - } - xmlFree(unescaped); - } - - return retval; -} - -/** - * xmlXzfileRead: - * @context: the I/O context - * @buffer: where to drop data - * @len: number of bytes to write - * - * Read @len bytes to @buffer from the compressed I/O channel. - * - * Returns the number of bytes written - */ -static int -xmlXzfileRead (void * context, char * buffer, int len) { - int ret; - - ret = __libxml2_xzread((xzFile) context, &buffer[0], len); - if (ret < 0) xmlIOErr(0, "xzread()"); - return(ret); -} - -/** - * xmlXzfileClose: - * @context: the I/O context + * xmlXzfileClose: + * @context: the I/O context * * Close a compressed I/O channel */ @@ -1379,392 +983,19 @@ xmlXzfileClose (void * context) { } #endif /* LIBXML_LZMA_ENABLED */ -#ifdef LIBXML_HTTP_ENABLED /************************************************************************ * * * I/O for HTTP file accesses * * * ************************************************************************/ -#ifdef LIBXML_OUTPUT_ENABLED -typedef struct xmlIOHTTPWriteCtxt_ -{ - int compression; - - char * uri; - - void * doc_buff; - -} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr; - -#ifdef LIBXML_ZLIB_ENABLED - -#define DFLT_WBITS ( -15 ) -#define DFLT_MEM_LVL ( 8 ) -#define GZ_MAGIC1 ( 0x1f ) -#define GZ_MAGIC2 ( 0x8b ) -#define LXML_ZLIB_OS_CODE ( 0x03 ) -#define INIT_HTTP_BUFF_SIZE ( 32768 ) -#define DFLT_ZLIB_RATIO ( 5 ) - -/* -** Data structure and functions to work with sending compressed data -** via HTTP. -*/ - -typedef struct xmlZMemBuff_ -{ - unsigned long size; - unsigned long crc; - - unsigned char * zbuff; - z_stream zctrl; - -} xmlZMemBuff, *xmlZMemBuffPtr; - -/** - * append_reverse_ulong - * @buff: Compressed memory buffer - * @data: Unsigned long to append - * - * Append a unsigned long in reverse byte order to the end of the - * memory buffer. - */ -static void -append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) { - - int idx; - - if ( buff == NULL ) - return; - - /* - ** This is plagiarized from putLong in gzio.c (zlib source) where - ** the number "4" is hardcoded. If zlib is ever patched to - ** support 64 bit file sizes, this code would need to be patched - ** as well. - */ - - for ( idx = 0; idx < 4; idx++ ) { - *buff->zctrl.next_out = ( data & 0xff ); - data >>= 8; - buff->zctrl.next_out++; - } - - return; -} - -/** - * - * xmlFreeZMemBuff - * @buff: The memory buffer context to clear - * - * Release all the resources associated with the compressed memory buffer. - */ -static void -xmlFreeZMemBuff( xmlZMemBuffPtr buff ) { - -#ifdef DEBUG_HTTP - int z_err; -#endif - - if ( buff == NULL ) - return; - - xmlFree( buff->zbuff ); -#ifdef DEBUG_HTTP - z_err = deflateEnd( &buff->zctrl ); - if ( z_err != Z_OK ) - xmlGenericError( xmlGenericErrorContext, - "xmlFreeZMemBuff: Error releasing zlib context: %d\n", - z_err ); -#else - deflateEnd( &buff->zctrl ); -#endif - - xmlFree( buff ); - return; -} - -/** - * xmlCreateZMemBuff - *@compression: Compression value to use - * - * Create a memory buffer to hold the compressed XML document. The - * compressed document in memory will end up being identical to what - * would be created if gzopen/gzwrite/gzclose were being used to - * write the document to disk. The code for the header/trailer data to - * the compression is plagiarized from the zlib source files. - */ -static void * -xmlCreateZMemBuff( int compression ) { - - int z_err; - int hdr_lgth; - xmlZMemBuffPtr buff = NULL; - - if ( ( compression < 1 ) || ( compression > 9 ) ) - return ( NULL ); - - /* Create the control and data areas */ - - buff = xmlMalloc( sizeof( xmlZMemBuff ) ); - if ( buff == NULL ) { - xmlIOErrMemory("creating buffer context"); - return ( NULL ); - } - - (void)memset( buff, 0, sizeof( xmlZMemBuff ) ); - buff->size = INIT_HTTP_BUFF_SIZE; - buff->zbuff = xmlMalloc( buff->size ); - if ( buff->zbuff == NULL ) { - xmlFreeZMemBuff( buff ); - xmlIOErrMemory("creating buffer"); - return ( NULL ); - } - - z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED, - DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY ); - if ( z_err != Z_OK ) { - xmlChar msg[500]; - xmlFreeZMemBuff( buff ); - buff = NULL; - xmlStrPrintf(msg, 500, - "xmlCreateZMemBuff: %s %d\n", - "Error initializing compression context. ZLIB error:", - z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - return ( NULL ); - } - - /* Set the header data. The CRC will be needed for the trailer */ - buff->crc = crc32( 0L, NULL, 0 ); - hdr_lgth = snprintf( (char *)buff->zbuff, buff->size, - "%c%c%c%c%c%c%c%c%c%c", - GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, - 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE ); - buff->zctrl.next_out = buff->zbuff + hdr_lgth; - buff->zctrl.avail_out = buff->size - hdr_lgth; - - return ( buff ); -} - -/** - * xmlZMemBuffExtend - * @buff: Buffer used to compress and consolidate data. - * @ext_amt: Number of bytes to extend the buffer. - * - * Extend the internal buffer used to store the compressed data by the - * specified amount. - * - * Returns 0 on success or -1 on failure to extend the buffer. On failure - * the original buffer still exists at the original size. - */ -static int -xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) { - - int rc = -1; - size_t new_size; - size_t cur_used; - - unsigned char * tmp_ptr = NULL; - - if ( buff == NULL ) - return ( -1 ); - - else if ( ext_amt == 0 ) - return ( 0 ); - - cur_used = buff->zctrl.next_out - buff->zbuff; - new_size = buff->size + ext_amt; - -#ifdef DEBUG_HTTP - if ( cur_used > new_size ) - xmlGenericError( xmlGenericErrorContext, - "xmlZMemBuffExtend: %s\n%s %d bytes.\n", - "Buffer overwrite detected during compressed memory", - "buffer extension. Overflowed by", - (cur_used - new_size ) ); -#endif - - tmp_ptr = xmlRealloc( buff->zbuff, new_size ); - if ( tmp_ptr != NULL ) { - rc = 0; - buff->size = new_size; - buff->zbuff = tmp_ptr; - buff->zctrl.next_out = tmp_ptr + cur_used; - buff->zctrl.avail_out = new_size - cur_used; - } - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffExtend: %s %lu bytes.\n", - "Allocation failure extending output buffer to", - (unsigned long) new_size ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - return ( rc ); -} - -/** - * xmlZMemBuffAppend - * @buff: Buffer used to compress and consolidate data - * @src: Uncompressed source content to append to buffer - * @len: Length of source data to append to buffer - * - * Compress and append data to the internal buffer. The data buffer - * will be expanded if needed to store the additional data. - * - * Returns the number of bytes appended to the buffer or -1 on error. - */ -static int -xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) { - - int z_err; - size_t min_accept; - - if ( ( buff == NULL ) || ( src == NULL ) ) - return ( -1 ); - - buff->zctrl.avail_in = len; - buff->zctrl.next_in = (unsigned char *)src; - while ( buff->zctrl.avail_in > 0 ) { - /* - ** Extend the buffer prior to deflate call if a reasonable amount - ** of output buffer space is not available. - */ - min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO; - if ( buff->zctrl.avail_out <= min_accept ) { - if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) - return ( -1 ); - } - - z_err = deflate( &buff->zctrl, Z_NO_FLUSH ); - if ( z_err != Z_OK ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffAppend: %s %d %s - %d", - "Compression error while appending", - len, "bytes to buffer. ZLIB error", z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - return ( -1 ); - } - } - - buff->crc = crc32( buff->crc, (unsigned char *)src, len ); - - return ( len ); -} - -/** - * xmlZMemBuffGetContent - * @buff: Compressed memory content buffer - * @data_ref: Pointer reference to point to compressed content - * - * Flushes the compression buffers, appends gzip file trailers and - * returns the compressed content and length of the compressed data. - * NOTE: The gzip trailer code here is plagiarized from zlib source. - * - * Returns the length of the compressed data or -1 on error. - */ -static int -xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) { - - int zlgth = -1; - int z_err; - - if ( ( buff == NULL ) || ( data_ref == NULL ) ) - return ( -1 ); - - /* Need to loop until compression output buffers are flushed */ - - do - { - z_err = deflate( &buff->zctrl, Z_FINISH ); - if ( z_err == Z_OK ) { - /* In this case Z_OK means more buffer space needed */ - - if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) - return ( -1 ); - } - } - while ( z_err == Z_OK ); - - /* If the compression state is not Z_STREAM_END, some error occurred */ - - if ( z_err == Z_STREAM_END ) { - - /* Need to append the gzip data trailer */ - - if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) { - if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 ) - return ( -1 ); - } - - /* - ** For whatever reason, the CRC and length data are pushed out - ** in reverse byte order. So a memcpy can't be used here. - */ - - append_reverse_ulong( buff, buff->crc ); - append_reverse_ulong( buff, buff->zctrl.total_in ); - - zlgth = buff->zctrl.next_out - buff->zbuff; - *data_ref = (char *)buff->zbuff; - } - - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffGetContent: %s - %d\n", - "Error flushing zlib buffers. Error code", z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - return ( zlgth ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ -#endif /* LIBXML_ZLIB_ENABLED */ - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlFreeHTTPWriteCtxt - * @ctxt: Context to cleanup - * - * Free allocated memory and reclaim system resources. - * - * No return value. - */ -static void -xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt ) -{ - if ( ctxt->uri != NULL ) - xmlFree( ctxt->uri ); - - if ( ctxt->doc_buff != NULL ) { - -#ifdef LIBXML_ZLIB_ENABLED - if ( ctxt->compression > 0 ) { - xmlFreeZMemBuff( ctxt->doc_buff ); - } - else -#endif - { - xmlOutputBufferClose( ctxt->doc_buff ); - } - } - - xmlFree( ctxt ); - return; -} -#endif /* LIBXML_OUTPUT_ENABLED */ - - +#ifdef LIBXML_HTTP_ENABLED /** * xmlIOHTTPMatch: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * check if the URI matches an HTTP one * * Returns 1 if matches, 0 otherwise @@ -1780,6 +1011,8 @@ xmlIOHTTPMatch (const char *filename) { * xmlIOHTTPOpen: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * open an HTTP I/O channel * * Returns an I/O context or NULL in case of error @@ -1795,78 +1028,15 @@ xmlIOHTTPOpen (const char *filename) { * @post_uri: The destination URI for the document * @compression: The compression desired for the document. * - * Open a temporary buffer to collect the document for a subsequent HTTP POST - * request. Non-static as is called from the output buffer creation routine. + * DEPRECATED: Support for HTTP POST has been removed. * - * Returns an I/O context or NULL in case of error. + * Returns NULL. */ - void * -xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED) +xmlIOHTTPOpenW(const char *post_uri ATTRIBUTE_UNUSED, + int compression ATTRIBUTE_UNUSED) { - - xmlIOHTTPWriteCtxtPtr ctxt = NULL; - - if (post_uri == NULL) - return (NULL); - - ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt)); - if (ctxt == NULL) { - xmlIOErrMemory("creating HTTP output context"); - return (NULL); - } - - (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt)); - - ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri); - if (ctxt->uri == NULL) { - xmlIOErrMemory("copying URI"); - xmlFreeHTTPWriteCtxt(ctxt); - return (NULL); - } - - /* - * ** Since the document length is required for an HTTP post, - * ** need to put the document into a buffer. A memory buffer - * ** is being used to avoid pushing the data to disk and back. - */ - -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9)) { - - ctxt->compression = compression; - ctxt->doc_buff = xmlCreateZMemBuff(compression); - } else -#endif - { - /* Any character conversions should have been done before this */ - - ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL); - } - - if (ctxt->doc_buff == NULL) { - xmlFreeHTTPWriteCtxt(ctxt); - ctxt = NULL; - } - - return (ctxt); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTPDfltOpenW - * @post_uri: The destination URI for this document. - * - * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent - * HTTP post command. This function should generally not be used as - * the open callback is short circuited in xmlOutputBufferCreateFile. - * - * Returns a pointer to the new IO context. - */ -static void * -xmlIOHTTPDfltOpenW( const char * post_uri ) { - return ( xmlIOHTTPOpenW( post_uri, 0 ) ); + return(NULL); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -1876,6 +1046,8 @@ xmlIOHTTPDfltOpenW( const char * post_uri ) { * @buffer: where to drop data * @len: number of bytes to write * + * DEPRECATED: Internal function, don't use. + * * Read @len bytes to @buffer from the I/O channel. * * Returns the number of bytes written @@ -1886,59 +1058,12 @@ xmlIOHTTPRead(void * context, char * buffer, int len) { return(xmlNanoHTTPRead(context, &buffer[0], len)); } -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTPWrite - * @context: previously opened writing context - * @buffer: data to output to temporary buffer - * @len: bytes to output - * - * Collect data from memory buffer into a temporary file for later - * processing. - * - * Returns number of bytes written. - */ - -static int -xmlIOHTTPWrite( void * context, const char * buffer, int len ) { - - xmlIOHTTPWriteCtxtPtr ctxt = context; - - if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) ) - return ( -1 ); - - if ( len > 0 ) { - - /* Use gzwrite or fwrite as previously setup in the open call */ - -#ifdef LIBXML_ZLIB_ENABLED - if ( ctxt->compression > 0 ) - len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len ); - - else -#endif - len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer ); - - if ( len < 0 ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPWrite: %s\n%s '%s'.\n", - "Error appending to internal buffer.", - "Error sending document to URI", - ctxt->uri ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - } - - return ( len ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - - /** * xmlIOHTTPClose: * @context: the I/O context * + * DEPRECATED: Internal function, don't use. + * * Close an HTTP I/O channel * * Returns 0 @@ -1948,171 +1073,6 @@ xmlIOHTTPClose (void * context) { xmlNanoHTTPClose(context); return 0; } - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTCloseWrite - * @context: The I/O context - * @http_mthd: The HTTP method to be used when sending the data - * - * Close the transmit HTTP I/O channel and actually send the data. - */ -static int -xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) { - - int close_rc = -1; - int http_rtn = 0; - int content_lgth = 0; - xmlIOHTTPWriteCtxtPtr ctxt = context; - - char * http_content = NULL; - char * content_encoding = NULL; - char * content_type = (char *) "text/xml"; - void * http_ctxt = NULL; - - if ( ( ctxt == NULL ) || ( http_mthd == NULL ) ) - return ( -1 ); - - /* Retrieve the content from the appropriate buffer */ - -#ifdef LIBXML_ZLIB_ENABLED - - if ( ctxt->compression > 0 ) { - content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content ); - content_encoding = (char *) "Content-Encoding: gzip"; - } - else -#endif - { - /* Pull the data out of the memory output buffer */ - - xmlOutputBufferPtr dctxt = ctxt->doc_buff; - http_content = (char *) xmlBufContent(dctxt->buffer); - content_lgth = xmlBufUse(dctxt->buffer); - } - - if ( http_content == NULL ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n", - "Error retrieving content.\nUnable to", - http_mthd, "data to URI", ctxt->uri ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - else { - - http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content, - &content_type, content_encoding, - content_lgth ); - - if ( http_ctxt != NULL ) { -#ifdef DEBUG_HTTP - /* If testing/debugging - dump reply with request content */ - - FILE * tst_file = NULL; - char buffer[ 4096 ]; - char * dump_name = NULL; - int avail; - - xmlGenericError( xmlGenericErrorContext, - "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n", - http_mthd, ctxt->uri, - xmlNanoHTTPReturnCode( http_ctxt ) ); - - /* - ** Since either content or reply may be gzipped, - ** dump them to separate files instead of the - ** standard error context. - */ - - dump_name = tempnam( NULL, "lxml" ); - if ( dump_name != NULL ) { - (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name ); - - tst_file = fopen( buffer, "wb" ); - if ( tst_file != NULL ) { - xmlGenericError( xmlGenericErrorContext, - "Transmitted content saved in file: %s\n", buffer ); - - fwrite( http_content, sizeof( char ), - content_lgth, tst_file ); - fclose( tst_file ); - } - - (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name ); - tst_file = fopen( buffer, "wb" ); - if ( tst_file != NULL ) { - xmlGenericError( xmlGenericErrorContext, - "Reply content saved in file: %s\n", buffer ); - - - while ( (avail = xmlNanoHTTPRead( http_ctxt, - buffer, sizeof( buffer ) )) > 0 ) { - - fwrite( buffer, sizeof( char ), avail, tst_file ); - } - - fclose( tst_file ); - } - - free( dump_name ); - } -#endif /* DEBUG_HTTP */ - - http_rtn = xmlNanoHTTPReturnCode( http_ctxt ); - if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) ) - close_rc = 0; - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n", - http_mthd, content_lgth, - "bytes to URI", ctxt->uri, - "failed. HTTP return code:", http_rtn ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - xmlNanoHTTPClose( http_ctxt ); - xmlFree( content_type ); - } - } - - /* Final cleanups */ - - xmlFreeHTTPWriteCtxt( ctxt ); - - return ( close_rc ); -} - -/** - * xmlIOHTTPClosePut - * - * @context: The I/O context - * - * Close the transmit HTTP I/O channel and actually send data using a PUT - * HTTP method. - */ -static int -xmlIOHTTPClosePut( void * ctxt ) { - return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) ); -} - - -/** - * xmlIOHTTPClosePost - * - * @context: The I/O context - * - * Close the transmit HTTP I/O channel and actually send data using a POST - * HTTP method. - */ -static int -xmlIOHTTPClosePost( void * ctxt ) { - return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - #endif /* LIBXML_HTTP_ENABLED */ #ifdef LIBXML_FTP_ENABLED @@ -2125,6 +1085,8 @@ xmlIOHTTPClosePost( void * ctxt ) { * xmlIOFTPMatch: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * check if the URI matches an FTP one * * Returns 1 if matches, 0 otherwise @@ -2140,6 +1102,8 @@ xmlIOFTPMatch (const char *filename) { * xmlIOFTPOpen: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * open an FTP I/O channel * * Returns an I/O context or NULL in case of error @@ -2155,6 +1119,8 @@ xmlIOFTPOpen (const char *filename) { * @buffer: where to drop data * @len: number of bytes to write * + * DEPRECATED: Internal function, don't use. + * * Read @len bytes to @buffer from the I/O channel. * * Returns the number of bytes written @@ -2169,6 +1135,8 @@ xmlIOFTPRead(void * context, char * buffer, int len) { * xmlIOFTPClose: * @context: the I/O context * + * DEPRECATED: Internal function, don't use. + * * Close an FTP I/O channel * * Returns 0 @@ -2179,161 +1147,192 @@ xmlIOFTPClose (void * context) { } #endif /* LIBXML_FTP_ENABLED */ +/************************************************************************ + * * + * Input/output buffers * + * * + ************************************************************************/ -/** - * xmlRegisterInputCallbacks: - * @matchFunc: the xmlInputMatchCallback - * @openFunc: the xmlInputOpenCallback - * @readFunc: the xmlInputReadCallback - * @closeFunc: the xmlInputCloseCallback - * - * Register a new set of I/O callback for handling parser input. - * - * Returns the registered handler number or -1 in case of error - */ -int -xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, - xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, - xmlInputCloseCallback closeFunc) { - if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { - return(-1); - } - xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; - xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; - xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; - xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; - xmlInputCallbackInitialized = 1; - return(xmlInputCallbackNr++); +static int +xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) { + return(1); } -#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlRegisterOutputCallbacks: - * @matchFunc: the xmlOutputMatchCallback - * @openFunc: the xmlOutputOpenCallback - * @writeFunc: the xmlOutputWriteCallback - * @closeFunc: the xmlOutputCloseCallback + * xmlInputDefaultOpen: + * @buf: input buffer to be filled + * @filename: filename or URI * - * Register a new set of I/O callback for handling output. - * - * Returns the registered handler number or -1 in case of error + * Returns an xmlParserErrors code. */ -int -xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, - xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, - xmlOutputCloseCallback closeFunc) { - if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { - return(-1); +static int +xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) { + int ret; + int fd; + +#ifdef LIBXML_FTP_ENABLED + if (xmlIOFTPMatch(filename)) { + buf->context = xmlIOFTPOpen(filename); + + if (buf->context != NULL) { + buf->readcallback = xmlIOFTPRead; + buf->closecallback = xmlIOFTPClose; + return(XML_ERR_OK); + } } - xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; - xmlOutputCallbackInitialized = 1; - return(xmlOutputCallbackNr++); -} -#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* LIBXML_FTP_ENABLED */ -/** - * xmlRegisterDefaultInputCallbacks: - * - * Registers the default compiled-in I/O handlers. - */ -void -xmlRegisterDefaultInputCallbacks(void) { - if (xmlInputCallbackInitialized) - return; +#ifdef LIBXML_HTTP_ENABLED + if (xmlIOHTTPMatch(filename)) { + buf->context = xmlIOHTTPOpen(filename); + + if (buf->context != NULL) { + buf->readcallback = xmlIOHTTPRead; + buf->closecallback = xmlIOHTTPClose; + return(XML_ERR_OK); + } + } +#endif /* LIBXML_HTTP_ENABLED */ + + if (!xmlFileMatch(filename)) + return(XML_IO_ENOENT); - xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, - xmlFileRead, xmlFileClose); -#ifdef LIBXML_ZLIB_ENABLED - xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, - xmlGzfileRead, xmlGzfileClose); -#endif /* LIBXML_ZLIB_ENABLED */ #ifdef LIBXML_LZMA_ENABLED - xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen, - xmlXzfileRead, xmlXzfileClose); + { + xzFile xzStream; + + ret = xmlFdOpen(filename, 0, &fd); + if (ret != XML_ERR_OK) + return(ret); + + xzStream = __libxml2_xzdopen(filename, fd, "rb"); + + if (xzStream == NULL) { + close(fd); + } else { + if (__libxml2_xzcompressed(xzStream) > 0) { + buf->context = xzStream; + buf->readcallback = xmlXzfileRead; + buf->closecallback = xmlXzfileClose; + buf->compressed = 1; + + return(XML_ERR_OK); + } + + xmlXzfileClose(xzStream); + } + } #endif /* LIBXML_LZMA_ENABLED */ -#ifdef LIBXML_HTTP_ENABLED - xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, - xmlIOHTTPRead, xmlIOHTTPClose); -#endif /* LIBXML_HTTP_ENABLED */ +#ifdef LIBXML_ZLIB_ENABLED + { + gzFile gzStream; -#ifdef LIBXML_FTP_ENABLED - xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, - xmlIOFTPRead, xmlIOFTPClose); -#endif /* LIBXML_FTP_ENABLED */ - xmlInputCallbackInitialized = 1; + ret = xmlFdOpen(filename, 0, &fd); + if (ret != XML_ERR_OK) + return(ret); + + gzStream = gzdopen(fd, "rb"); + + if (gzStream == NULL) { + close(fd); + } else { + char buff4[4]; + + if ((gzread(gzStream, buff4, 4) > 0) && + (gzdirect(gzStream) == 0)) { + gzrewind(gzStream); + + buf->context = gzStream; + buf->readcallback = xmlGzfileRead; + buf->closecallback = xmlGzfileClose; + buf->compressed = 1; + + return(XML_ERR_OK); + } + + xmlGzfileClose(gzStream); + } + } +#endif /* LIBXML_ZLIB_ENABLED */ + + ret = xmlFdOpen(filename, 0, &fd); + if (ret != XML_ERR_OK) + return(ret); + + buf->context = (void *) (ptrdiff_t) fd; + buf->readcallback = xmlFdRead; + buf->closecallback = xmlFdClose; + return(XML_ERR_OK); } #ifdef LIBXML_OUTPUT_ENABLED /** - * xmlRegisterDefaultOutputCallbacks: + * xmlOutputDefaultOpen: + * @buf: input buffer to be filled + * @filename: filename or URI + * @compression: compression level or 0 + * @is_file_uri: whether filename is a file URI * - * Registers the default compiled-in I/O handlers. + * Returns an xmlParserErrors code. */ -void -xmlRegisterDefaultOutputCallbacks (void) { - if (xmlOutputCallbackInitialized) - return; +static int +xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename, + int compression) { + int fd; - xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, - xmlFileWrite, xmlFileClose); + (void) compression; -#ifdef LIBXML_HTTP_ENABLED - xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, - xmlIOHTTPWrite, xmlIOHTTPClosePut); -#endif + if (!strcmp(filename, "-")) { + fd = dup(STDOUT_FILENO); + + if (fd < 0) + return(xmlIOErr(0, "dup()")); + } else { + int ret; -/********************************* - No way a-priori to distinguish between gzipped files from - uncompressed ones except opening if existing then closing - and saving with same compression ratio ... a pain. + ret = xmlFdOpen(filename, /* write */ 1, &fd); + if (ret != XML_ERR_OK) + return(ret); + } #ifdef LIBXML_ZLIB_ENABLED - xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen, - xmlGzfileWrite, xmlGzfileClose); -#endif + if ((compression > 0) && (compression <= 9)) { + gzFile gzStream; + char mode[15]; - Nor FTP PUT .... -#ifdef LIBXML_FTP_ENABLED - xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, - xmlIOFTPWrite, xmlIOFTPClose); -#endif - **********************************/ - xmlOutputCallbackInitialized = 1; -} + snprintf(mode, sizeof(mode), "wb%d", compression); + gzStream = gzdopen(fd, mode); -#ifdef LIBXML_HTTP_ENABLED -/** - * xmlRegisterHTTPPostCallbacks: - * - * By default, libxml submits HTTP output requests using the "PUT" method. - * Calling this method changes the HTTP output method to use the "POST" - * method instead. - * - */ -void -xmlRegisterHTTPPostCallbacks( void ) { + if (gzStream == NULL) { + close(fd); + return(xmlIOErr(XML_IO_UNKNOWN, "gzdopen()")); + } - /* Register defaults if not done previously */ + buf->context = gzStream; + buf->writecallback = xmlGzfileWrite; + buf->closecallback = xmlGzfileClose; - if ( xmlOutputCallbackInitialized == 0 ) - xmlRegisterDefaultOutputCallbacks( ); + return(XML_ERR_OK); + } +#endif /* LIBXML_ZLIB_ENABLED */ - xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, - xmlIOHTTPWrite, xmlIOHTTPClosePost); - return; + buf->context = (void *) (ptrdiff_t) fd; + buf->writecallback = xmlFdWrite; + buf->closecallback = xmlFdClose; + return(XML_ERR_OK); } #endif -#endif /* LIBXML_OUTPUT_ENABLED */ /** * xmlAllocParserInputBuffer: - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * - * Create a buffered parser input for progressive parsing + * Create a buffered parser input for progressive parsing. + * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. * * Returns the new parser input or NULL */ @@ -2343,17 +1342,22 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) { ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); if (ret == NULL) { - xmlIOErrMemory("creating input buffer"); return(NULL); } - memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); + memset(ret, 0, sizeof(xmlParserInputBuffer)); ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize); if (ret->buffer == NULL) { xmlFree(ret); return(NULL); } xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); - ret->encoder = xmlGetCharEncodingHandler(enc); + if (enc != XML_CHAR_ENCODING_NONE) { + if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != 0) { + /* We can't handle errors properly here. */ + xmlFreeParserInputBuffer(ret); + return(NULL); + } + } if (ret->encoder != NULL) ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); else @@ -2382,16 +1386,15 @@ xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) { ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (ret == NULL) { - xmlIOErrMemory("creating output buffer"); return(NULL); } - memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); + memset(ret, 0, sizeof(xmlOutputBuffer)); ret->buffer = xmlBufCreate(); if (ret->buffer == NULL) { xmlFree(ret); return(NULL); } - xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); + xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO); ret->encoder = encoder; if (encoder != NULL) { @@ -2430,10 +1433,9 @@ xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) { ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (ret == NULL) { - xmlIOErrMemory("creating output buffer"); return(NULL); } - memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); + memset(ret, 0, sizeof(xmlOutputBuffer)); ret->buffer = xmlBufCreate(); if (ret->buffer == NULL) { xmlFree(ret); @@ -2507,22 +1509,36 @@ xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { * flushes and close the output I/O channel * and free up all the associated resources * - * Returns the number of byte written or -1 in case of error. + * Returns the number of byte written or a negative xmlParserErrors + * code in case of error. */ int xmlOutputBufferClose(xmlOutputBufferPtr out) { - int written; - int err_rc = 0; + int ret; if (out == NULL) return (-1); + if (out->writecallback != NULL) xmlOutputBufferFlush(out); + if (out->closecallback != NULL) { - err_rc = out->closecallback(out->context); + int code = out->closecallback(out->context); + + if ((code != XML_ERR_OK) && (out->error == XML_ERR_OK)) { + if (code < 0) + out->error = XML_IO_UNKNOWN; + else + out->error = code; + } } - written = out->written; + + if (out->error != XML_ERR_OK) + ret = -out->error; + else + ret = out->written; + if (out->conv) { xmlBufFree(out->conv); out->conv = NULL; @@ -2535,81 +1551,79 @@ xmlOutputBufferClose(xmlOutputBufferPtr out) out->buffer = NULL; } - if (out->error) - err_rc = -1; xmlFree(out); - return ((err_rc == 0) ? written : err_rc); + + return(ret); } #endif /* LIBXML_OUTPUT_ENABLED */ -xmlParserInputBufferPtr -__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { - xmlParserInputBufferPtr ret; - int i = 0; - void *context = NULL; +/** + * xmlParserInputBufferCreateFilenameInt: + * @URI: the filename or URI + * @enc: encoding enum (deprecated) + * @out: pointer to resulting input buffer + * + * Returns an xmlParserErrors code. + */ +static int +xmlParserInputBufferCreateFilenameInt(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out) { + xmlParserInputBufferPtr buf; + int ret; + int i; + + xmlInitParser(); - if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); + *out = NULL; + if (URI == NULL) + return(XML_ERR_ARGUMENT); - if (URI == NULL) return(NULL); + /* + * Allocate the Input buffer front-end. + */ + buf = xmlAllocParserInputBuffer(enc); + if (buf == NULL) + return(XML_ERR_NO_MEMORY); /* * Try to find one of the input accept method accepting that scheme * Go in reverse to give precedence to user defined handlers. */ - if (context == NULL) { - for (i = xmlInputCallbackNr - 1;i >= 0;i--) { - if ((xmlInputCallbackTable[i].matchcallback != NULL) && - (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { - context = xmlInputCallbackTable[i].opencallback(URI); - if (context != NULL) { - break; - } - } - } + ret = XML_IO_ENOENT; + for (i = xmlInputCallbackNr - 1; i >= 0; i--) { + xmlInputCallback *cb = &xmlInputCallbackTable[i]; + + if (cb->matchcallback == xmlIODefaultMatch) { + ret = xmlInputDefaultOpen(buf, URI); + + if ((ret == XML_ERR_OK) || (ret != XML_IO_ENOENT)) + break; + } else if ((cb->matchcallback != NULL) && + (cb->matchcallback(URI) != 0)) { + buf->context = cb->opencallback(URI); + if (buf->context != NULL) { + buf->readcallback = cb->readcallback; + buf->closecallback = cb->closecallback; + ret = XML_ERR_OK; + break; + } + } } - if (context == NULL) { - return(NULL); + if (ret != XML_ERR_OK) { + xmlFreeParserInputBuffer(buf); + *out = NULL; + return(ret); } - /* - * Allocate the Input buffer front-end. - */ - ret = xmlAllocParserInputBuffer(enc); - if (ret != NULL) { - ret->context = context; - ret->readcallback = xmlInputCallbackTable[i].readcallback; - ret->closecallback = xmlInputCallbackTable[i].closecallback; -#ifdef LIBXML_ZLIB_ENABLED - if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) && - (strcmp(URI, "-") != 0)) { -#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230 - ret->compressed = !gzdirect(context); -#else - if (((z_stream *)context)->avail_in > 4) { - char *cptr, buff4[4]; - cptr = (char *) ((z_stream *)context)->next_in; - if (gzread(context, buff4, 4) == 4) { - if (strncmp(buff4, cptr, 4) == 0) - ret->compressed = 0; - else - ret->compressed = 1; - gzrewind(context); - } - } -#endif - } -#endif -#ifdef LIBXML_LZMA_ENABLED - if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) && - (strcmp(URI, "-") != 0)) { - ret->compressed = __libxml2_xzcompressed(context); - } -#endif - } - else - xmlInputCallbackTable[i].closecallback (context); + *out = buf; + return(ret); +} + +xmlParserInputBufferPtr +__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + xmlParserInputBufferCreateFilenameInt(URI, enc, &ret); return(ret); } @@ -2619,7 +1633,6 @@ __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing of a file - * If filename is "-' then we use stdin as the input. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * Do an encoding check if enc == XML_CHAR_ENCODING_NONE @@ -2628,135 +1641,106 @@ __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { */ xmlParserInputBufferPtr xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { - if ((xmlParserInputBufferCreateFilenameValue)) { - return xmlParserInputBufferCreateFilenameValue(URI, enc); - } - return __xmlParserInputBufferCreateFilename(URI, enc); + if (xmlParserInputBufferCreateFilenameValue != NULL) + return(xmlParserInputBufferCreateFilenameValue(URI, enc)); + + return(__xmlParserInputBufferCreateFilename(URI, enc)); +} + +/** + * xmlParserInputBufferCreateFilenameSafe: + * @URI: the filename or URI + * @enc: encoding enum (deprecated) + * @out: pointer to resulting input buffer + * + * Create an input buffer for a filename or URI. + * + * Returns an xmlParserErrors code. + */ +int +xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out) { + if (xmlParserInputBufferCreateFilenameValue != NULL) { + *out = xmlParserInputBufferCreateFilenameValue(URI, enc); + + if (*out == NULL) + return(XML_IO_ENOENT); + return(XML_ERR_OK); + } + + return(xmlParserInputBufferCreateFilenameInt(URI, enc, out)); } #ifdef LIBXML_OUTPUT_ENABLED xmlOutputBufferPtr __xmlOutputBufferCreateFilename(const char *URI, xmlCharEncodingHandlerPtr encoder, - int compression ATTRIBUTE_UNUSED) { + int compression) { xmlOutputBufferPtr ret; xmlURIPtr puri; int i = 0; - void *context = NULL; char *unescaped = NULL; -#ifdef LIBXML_ZLIB_ENABLED - int is_file_uri = 1; -#endif - if (xmlOutputCallbackInitialized == 0) - xmlRegisterDefaultOutputCallbacks(); + xmlInitParser(); - if (URI == NULL) return(NULL); + if (URI == NULL) + return(NULL); puri = xmlParseURI(URI); if (puri != NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((puri->scheme != NULL) && - (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) - is_file_uri = 0; -#endif - /* - * try to limit the damages of the URI unescaping code. - */ - if ((puri->scheme == NULL) || - (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) - unescaped = xmlURIUnescapeString(URI, 0, NULL); - xmlFreeURI(puri); + /* + * try to limit the damages of the URI unescaping code. + */ + if (puri->scheme == NULL) { + unescaped = xmlURIUnescapeString(URI, 0, NULL); + if (unescaped == NULL) { + xmlFreeURI(puri); + return(NULL); + } + URI = unescaped; + } + xmlFreeURI(puri); } /* - * Try to find one of the output accept method accepting that scheme - * Go in reverse to give precedence to user defined handlers. - * try with an unescaped version of the URI + * Allocate the Output buffer front-end. */ - if (unescaped != NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { - context = xmlGzfileOpenW(unescaped, compression); - if (context != NULL) { - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlGzfileWrite; - ret->closecallback = xmlGzfileClose; - } - xmlFree(unescaped); - return(ret); - } - } -#endif - for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { - if ((xmlOutputCallbackTable[i].matchcallback != NULL) && - (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) { -#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) - /* Need to pass compression parameter into HTTP open calls */ - if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) - context = xmlIOHTTPOpenW(unescaped, compression); - else -#endif - context = xmlOutputCallbackTable[i].opencallback(unescaped); - if (context != NULL) - break; - } - } - xmlFree(unescaped); + ret = xmlAllocOutputBufferInternal(encoder); + if (ret == NULL) { + xmlFree(unescaped); + return(NULL); } /* - * If this failed try with a non-escaped URI this may be a strange - * filename + * Try to find one of the output accept method accepting that scheme + * Go in reverse to give precedence to user defined handlers. */ - if (context == NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { - context = xmlGzfileOpenW(URI, compression); - if (context != NULL) { - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlGzfileWrite; - ret->closecallback = xmlGzfileClose; - } - else - xmlGzfileClose(context); - return(ret); - } - } -#endif - for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { - if ((xmlOutputCallbackTable[i].matchcallback != NULL) && - (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { -#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) - /* Need to pass compression parameter into HTTP open calls */ - if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) - context = xmlIOHTTPOpenW(URI, compression); - else -#endif - context = xmlOutputCallbackTable[i].opencallback(URI); - if (context != NULL) - break; - } - } - } + for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { + xmlOutputCallback *cb = &xmlOutputCallbackTable[i]; + int code; - if (context == NULL) { - return(NULL); + if (cb->matchcallback == xmlIODefaultMatch) { + code = xmlOutputDefaultOpen(ret, URI, compression); + /* TODO: Handle other errors */ + if (code == XML_ERR_OK) + break; + } else if ((cb->matchcallback != NULL) && + (cb->matchcallback(URI) != 0)) { + ret->context = cb->opencallback(URI); + if (ret->context != NULL) { + ret->writecallback = cb->writecallback; + ret->closecallback = cb->closecallback; + break; + } + } } - /* - * Allocate the Output buffer front-end. - */ - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlOutputCallbackTable[i].writecallback; - ret->closecallback = xmlOutputCallbackTable[i].closecallback; + if (ret->context == NULL) { + xmlOutputBufferClose(ret); + ret = NULL; } + + xmlFree(unescaped); return(ret); } @@ -2789,27 +1773,28 @@ xmlOutputBufferCreateFilename(const char *URI, /** * xmlParserInputBufferCreateFile: * @file: a FILE* - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing of a FILE * * buffered C I/O * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; - if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); - if (file == NULL) return(NULL); ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = file; ret->readcallback = xmlFileRead; - ret->closecallback = xmlFileFlush; + ret->closecallback = NULL; } return(ret); @@ -2830,9 +1815,6 @@ xmlOutputBufferPtr xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { xmlOutputBufferPtr ret; - if (xmlOutputCallbackInitialized == 0) - xmlRegisterDefaultOutputCallbacks(); - if (file == NULL) return(NULL); ret = xmlAllocOutputBufferInternal(encoder); @@ -2877,7 +1859,7 @@ xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, */ const xmlChar * xmlOutputBufferGetContent(xmlOutputBufferPtr out) { - if ((out == NULL) || (out->buffer == NULL)) + if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) return(NULL); return(xmlBufContent(out->buffer)); @@ -2893,7 +1875,7 @@ xmlOutputBufferGetContent(xmlOutputBufferPtr out) { */ size_t xmlOutputBufferGetSize(xmlOutputBufferPtr out) { - if ((out == NULL) || (out->buffer == NULL)) + if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) return(0); return(xmlBufUse(out->buffer)); @@ -2905,11 +1887,15 @@ xmlOutputBufferGetSize(xmlOutputBufferPtr out) { /** * xmlParserInputBufferCreateFd: * @fd: a file descriptor number - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing for the input * from a file descriptor * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr @@ -2922,87 +1908,207 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { if (ret != NULL) { ret->context = (void *) (ptrdiff_t) fd; ret->readcallback = xmlFdRead; - ret->closecallback = xmlFdClose; } return(ret); } +typedef struct { + char *mem; + const char *cur; + size_t size; +} xmlMemIOCtxt; + +static int +xmlMemRead(void *vctxt, char *buf, int size) { + xmlMemIOCtxt *ctxt = vctxt; + + if ((size_t) size > ctxt->size) + size = ctxt->size; + + memcpy(buf, ctxt->cur, size); + ctxt->cur += size; + ctxt->size -= size; + + return size; +} + +static int +xmlMemClose(void *vctxt) { + xmlMemIOCtxt *ctxt = vctxt; + + if (ctxt->mem != NULL) + xmlFree(ctxt->mem); + xmlFree(ctxt); + return(0); +} + /** - * xmlParserInputBufferCreateMem: - * @mem: the memory input - * @size: the length of the memory block - * @enc: the charset encoding if known + * xmlNewInputBufferMemory: + * @mem: memory buffer + * @size: size of buffer + * @flags: flags + * @enc: the charset encoding if known (deprecated) * - * Create a buffered parser input for the progressive parsing for the input - * from a memory area. + * Create an input buffer for memory. * - * Returns the new parser input or NULL + * Returns the new input buffer or NULL. */ xmlParserInputBufferPtr -xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { +xmlNewInputBufferMemory(const void *mem, size_t size, int flags, + xmlCharEncoding enc) { xmlParserInputBufferPtr ret; - int errcode; + xmlMemIOCtxt *ctxt; + char *copy = NULL; + + if ((flags & XML_INPUT_BUF_STATIC) == 0) { + if (size + 1 == 0) + return(NULL); + copy = xmlMalloc(size + 1); + if (copy == NULL) + return(NULL); + memcpy(copy, mem, size); + copy[size] = 0; - if (size < 0) return(NULL); - if (mem == NULL) return(NULL); + mem = copy; + } ret = xmlAllocParserInputBuffer(enc); - if (ret != NULL) { - ret->context = (void *) mem; - ret->readcallback = xmlInputReadCallbackNop; - ret->closecallback = NULL; - errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size); - if (errcode != 0) { - xmlFree(ret); - return(NULL); - } + if (ret == NULL) { + xmlFree(copy); + return(NULL); + } + + ctxt = xmlMalloc(sizeof(*ctxt)); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(ret); + xmlFree(copy); + return(NULL); } + ctxt->mem = copy; + ctxt->cur = mem; + ctxt->size = size; + + ret->context = ctxt; + ret->readcallback = xmlMemRead; + ret->closecallback = xmlMemClose; + return(ret); } +/** + * xmlParserInputBufferCreateMem: + * @mem: the memory input + * @size: the length of the memory block + * @enc: the charset encoding if known (deprecated) + * + * Create a parser input buffer for parsing from a memory area. + * + * This function makes a copy of the whole input buffer. If you are sure + * that the contents of the buffer will remain valid until the document + * was parsed, you can avoid the copy by using + * xmlParserInputBufferCreateStatic. + * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * + * Returns the new parser input or NULL in case of error. + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { + if ((mem == NULL) || (size < 0)) + return(NULL); + + return(xmlNewInputBufferMemory(mem, size, 0, enc)); +} + /** * 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. + * Create a parser input buffer for parsing from a memory area. * - * Returns the new parser input or NULL + * This functions assumes that the contents of the input buffer remain + * valid until the document was parsed. Use xmlParserInputBufferCreateMem + * otherwise. + * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * + * Returns the new parser input or NULL in case of error. */ xmlParserInputBufferPtr xmlParserInputBufferCreateStatic(const char *mem, int size, xmlCharEncoding enc) { + if ((mem == NULL) || (size < 0)) + return(NULL); + + return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc)); +} + +typedef struct { + const char *str; +} xmlStringIOCtxt; + +static int +xmlStringRead(void *vctxt, char *buf, int size) { + xmlStringIOCtxt *ctxt = vctxt; + const char *zero; + size_t len; + + zero = memchr(ctxt->str, 0, size); + len = zero ? zero - ctxt->str : size; + + memcpy(buf, ctxt->str, len); + ctxt->str += len; + + return(len); +} + +static int +xmlStringClose(void *vctxt) { + xmlFree(vctxt); + return(0); +} + +/** + * xmlNewInputBufferString: + * @str: C string + * @flags: flags + * + * Create an input buffer for a null-teriminated C string. + * + * Returns the new input buffer or NULL. + */ +xmlParserInputBufferPtr +xmlNewInputBufferString(const char *str, int flags) { xmlParserInputBufferPtr ret; + xmlStringIOCtxt *ctxt; - if (size < 0) return(NULL); - if (mem == NULL) return(NULL); + if ((flags & XML_INPUT_BUF_STATIC) == 0) + return(xmlNewInputBufferMemory(str, strlen(str), flags, + XML_CHAR_ENCODING_NONE)); - ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); - if (ret == NULL) { - xmlIOErrMemory("creating input buffer"); - return(NULL); - } - memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); - ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size); - if (ret->buffer == NULL) { - xmlFree(ret); - return(NULL); + ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + if (ret == NULL) + return(NULL); + + ctxt = xmlMalloc(sizeof(*ctxt)); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(ret); + return(NULL); } - ret->encoder = xmlGetCharEncodingHandler(enc); - if (ret->encoder != NULL) - ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); - else - ret->raw = NULL; - ret->compressed = -1; - ret->context = (void *) mem; - ret->readcallback = NULL; - ret->closecallback = NULL; + + ctxt->str = str; + + ret->context = ctxt; + ret->readcallback = xmlStringRead; + ret->closecallback = xmlStringClose; return(ret); } @@ -3040,11 +2146,15 @@ xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { * @ioread: an I/O read function * @ioclose: an I/O close function * @ioctx: an I/O handler - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing for the input * from an I/O handler * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr @@ -3105,13 +2215,17 @@ xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, * Returns the old value of the registration function */ xmlParserInputBufferCreateFilenameFunc -xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) +xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func) { - xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; - if (old == NULL) { - old = __xmlParserInputBufferCreateFilename; - } + xmlParserInputBufferCreateFilenameFunc old; + old = xmlParserInputBufferCreateFilenameValue; + if (old == NULL) + old = __xmlParserInputBufferCreateFilename; + + if (func == __xmlParserInputBufferCreateFilename) + func = NULL; xmlParserInputBufferCreateFilenameValue = func; return(old); } @@ -3159,40 +2273,36 @@ xmlParserInputBufferPush(xmlParserInputBufferPtr in, 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 = xmlBufCreate(); + if (in->raw == NULL) { + in->error = XML_ERR_NO_MEMORY; + return(-1); + } } ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len); - if (ret != 0) + if (ret != 0) { + in->error = XML_ERR_NO_MEMORY; return(-1); + } /* * convert as much as possible to the parser reading buffer. */ - use = xmlBufUse(in->raw); - nbchars = xmlCharEncInput(in, 1); - if (nbchars < 0) { - xmlIOErr(XML_IO_ENCODER, NULL); - in->error = XML_IO_ENCODER; + nbchars = xmlCharEncInput(in); + if (nbchars < 0) return(-1); - } - in->rawconsumed += (use - xmlBufUse(in->raw)); } else { nbchars = len; ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars); - if (ret != 0) + if (ret != 0) { + in->error = XML_ERR_NO_MEMORY; return(-1); + } } -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, - "I/O: pushed %d chars, buffer %d/%d\n", - nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer)); -#endif return(nbchars); } @@ -3226,41 +2336,48 @@ endOfInput (void * context ATTRIBUTE_UNUSED, */ int xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { - char *buffer = NULL; + xmlBufPtr buf; int res = 0; - int nbchars = 0; if ((in == NULL) || (in->error)) return(-1); if ((len <= MINLEN) && (len != 4)) len = MINLEN; - if (xmlBufAvail(in->buffer) <= 0) { - xmlIOErr(XML_IO_BUFFER_FULL, NULL); - in->error = XML_IO_BUFFER_FULL; - return(-1); - } - - if (xmlBufGrow(in->buffer, len + 1) < 0) { - xmlIOErrMemory("growing input buffer"); - in->error = XML_ERR_NO_MEMORY; - return(-1); + if (in->encoder == NULL) { + if (in->readcallback == NULL) + return(0); + buf = in->buffer; + } else { + if (in->raw == NULL) { + in->raw = xmlBufCreate(); + } + buf = in->raw; } - buffer = (char *)xmlBufEnd(in->buffer); /* * Call the read method for this I/O type. */ if (in->readcallback != NULL) { - res = in->readcallback(in->context, &buffer[0], len); + if (xmlBufGrow(buf, len + 1) < 0) { + in->error = XML_ERR_NO_MEMORY; + return(-1); + } + + res = in->readcallback(in->context, (char *)xmlBufEnd(buf), 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); + if (res < 0) { + if (res == -1) + in->error = XML_IO_UNKNOWN; + else + in->error = -res; + return(-1); + } + + if (xmlBufAddLen(buf, res) < 0) { + in->error = XML_ERR_NO_MEMORY; + return(-1); + } } /* @@ -3273,41 +2390,12 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { #endif } - len = res; if (in->encoder != NULL) { - unsigned int use; - - /* - * Store the data in the incoming raw buffer - */ - if (in->raw == NULL) { - in->raw = xmlBufCreate(); - } - res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len); - if (res != 0) - return(-1); - - /* - * convert as much as possible to the parser reading buffer. - */ - use = xmlBufUse(in->raw); - nbchars = xmlCharEncInput(in, 1); - if (nbchars < 0) { - xmlIOErr(XML_IO_ENCODER, NULL); - in->error = XML_IO_ENCODER; + res = xmlCharEncInput(in); + if (res < 0) return(-1); - } - in->rawconsumed += (use - xmlBufUse(in->raw)); - } else { - nbchars = len; - xmlBufAddLen(in->buffer, nbchars); } -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, - "I/O: read %d chars, buffer %d\n", - nbchars, xmlBufUse(in->buffer)); -#endif - return(nbchars); + return(res); } /** @@ -3324,13 +2412,7 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { */ int xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { - if ((in == NULL) || (in->error)) return(-1); - if (in->readcallback != NULL) - return(xmlParserInputBufferGrow(in, len)); - else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE) - return(0); - else - return(-1); + return(xmlParserInputBufferGrow(in, len)); } #ifdef LIBXML_OUTPUT_ENABLED @@ -3373,10 +2455,16 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { */ if (out->conv == NULL) { out->conv = xmlBufCreate(); + if (out->conv == NULL) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); - if (ret != 0) + if (ret != 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + } if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len)) goto done; @@ -3385,19 +2473,18 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { * convert as much as possible to the parser reading buffer. */ ret = xmlCharEncOutput(out, 0); - if ((ret < 0) && (ret != -3)) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (ret < 0) return(-1); - } if (out->writecallback) nbchars = xmlBufUse(out->conv); else nbchars = ret >= 0 ? ret : 0; } else { ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); - if (ret != 0) + if (ret != 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + } if (out->writecallback) nbchars = xmlBufUse(out->buffer); else @@ -3425,8 +2512,10 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_WRITE, NULL); - out->error = XML_IO_WRITE; + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + + xmlIOErr(errNo, NULL); + out->error = errNo; return(ret); } if (out->written > INT_MAX - ret) @@ -3438,10 +2527,6 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { } while (len > 0); done: -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, - "I/O: wrote %d chars\n", written); -#endif return(written); } @@ -3496,7 +2581,7 @@ xmlEscapeContent(unsigned char* out, int *outlen, *out++ = '3'; *out++ = ';'; } else { - *out++ = (unsigned char) *in; + *out++ = *in; } ++in; } @@ -3532,8 +2617,7 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, int cons; /* byte from str consumed */ if ((out == NULL) || (out->error) || (str == NULL) || - (out->buffer == NULL) || - (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)) + (out->buffer == NULL)) return(-1); len = strlen((const char *)str); if (len < 0) return(0); @@ -3554,8 +2638,10 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, * not the case force a flush, but make sure we stay in the loop */ if (chunk < 40) { - if (xmlBufGrow(out->buffer, 100) < 0) + if (xmlBufGrow(out->buffer, 100) < 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + } oldwritten = -1; continue; } @@ -3569,11 +2655,17 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, */ if (out->conv == NULL) { out->conv = xmlBufCreate(); + if (out->conv == NULL) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } ret = escaping(xmlBufEnd(out->buffer) , &chunk, str, &cons); - if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ - return(-1); + if (ret < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } xmlBufAddLen(out->buffer, chunk); if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len)) @@ -3583,19 +2675,18 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, * convert as much as possible to the output buffer. */ ret = xmlCharEncOutput(out, 0); - if ((ret < 0) && (ret != -3)) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (ret < 0) return(-1); - } if (out->writecallback) nbchars = xmlBufUse(out->conv); else nbchars = ret >= 0 ? ret : 0; } else { ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons); - if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ - return(-1); + if (ret < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } xmlBufAddLen(out->buffer, chunk); if (out->writecallback) nbchars = xmlBufUse(out->buffer); @@ -3624,25 +2715,25 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_WRITE, NULL); - out->error = XML_IO_WRITE; - return(ret); + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + xmlIOErr(errNo, NULL); + out->error = errNo; + return(-1); } if (out->written > INT_MAX - ret) out->written = INT_MAX; else out->written += ret; } else if (xmlBufAvail(out->buffer) < MINLEN) { - xmlBufGrow(out->buffer, MINLEN); + if (xmlBufGrow(out->buffer, MINLEN) < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } written += nbchars; } while ((len > 0) && (oldwritten != written)); done: -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, - "I/O: wrote %d chars\n", written); -#endif return(written); } @@ -3673,6 +2764,56 @@ xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { return(len); } +/** + * xmlOutputBufferWriteQuotedString: + * @buf: output buffer + * @string: the string to add + * + * routine which manage and grows an output buffer. This one writes + * a quoted or double quoted #xmlChar string, checking first if it holds + * quote or double-quotes internally + */ +void +xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf, + const xmlChar *string) { + const xmlChar *cur, *base; + + if ((buf == NULL) || (buf->error)) + return; + + if (xmlStrchr(string, '\"')) { + if (xmlStrchr(string, '\'')) { + xmlOutputBufferWrite(buf, 1, "\""); + base = cur = string; + while(*cur != 0){ + if(*cur == '"'){ + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, + (const char *) base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } + else { + cur++; + } + } + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 1, "\""); + } + else{ + xmlOutputBufferWrite(buf, 1, "'"); + xmlOutputBufferWriteString(buf, (const char *) string); + xmlOutputBufferWrite(buf, 1, "'"); + } + } else { + xmlOutputBufferWrite(buf, 1, "\""); + xmlOutputBufferWriteString(buf, (const char *) string); + xmlOutputBufferWrite(buf, 1, "\""); + } +} + /** * xmlOutputBufferFlush: * @out: a buffered output @@ -3695,11 +2836,8 @@ xmlOutputBufferFlush(xmlOutputBufferPtr out) { */ do { nbchars = xmlCharEncOutput(out, 0); - if (nbchars < 0) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (nbchars < 0) return(-1); - } } while (nbchars); } @@ -3721,8 +2859,10 @@ xmlOutputBufferFlush(xmlOutputBufferPtr out) { xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_FLUSH, NULL); - out->error = XML_IO_FLUSH; + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + + xmlIOErr(errNo, NULL); + out->error = errNo; return(ret); } if (out->written > INT_MAX - ret) @@ -3730,10 +2870,6 @@ xmlOutputBufferFlush(xmlOutputBufferPtr out) { else out->written += ret; -#ifdef DEBUG_INPUT - xmlGenericError(xmlGenericErrorContext, - "I/O: flushed %d chars\n", ret); -#endif return(ret); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -3752,9 +2888,6 @@ xmlParserGetDirectory(const char *filename) { char dir[1024]; char *cur; - if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); - if (filename == NULL) return(NULL); #if defined(_WIN32) @@ -3775,347 +2908,220 @@ xmlParserGetDirectory(const char *filename) { else *cur = 0; ret = xmlMemStrdup(dir); } else { - if (getcwd(dir, 1024) != NULL) { - dir[1023] = 0; - ret = xmlMemStrdup(dir); - } + ret = xmlMemStrdup("."); } return(ret); #undef IS_XMLPGD_SEP } -/**************************************************************** - * * - * External entities loading * - * * - ****************************************************************/ - /** - * xmlCheckHTTPInput: - * @ctxt: an XML parser context - * @ret: an XML parser input + * xmlNoNetExists: + * @filename: the path to check + * + * DEPRECATED: Internal function, don't use. * - * Check an input in case it was created from an HTTP stream, in that - * case it will handle encoding and update of the base URL in case of - * redirection. It also checks for HTTP errors in which case the input - * is cleanly freed up and an appropriate error is raised in context + * Like xmlCheckFilename but handles file URIs. * - * Returns the input or NULL in case of HTTP error. + * Returns 0, 1, or 2. */ -xmlParserInputPtr -xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { - /* Avoid unused variable warning if features are disabled. */ - (void) ctxt; +int +xmlNoNetExists(const char *filename) { + char *fromUri; + int ret; -#ifdef LIBXML_HTTP_ENABLED - if ((ret != NULL) && (ret->buf != NULL) && - (ret->buf->readcallback == xmlIOHTTPRead) && - (ret->buf->context != NULL)) { - const char *encoding; - const char *redir; - const char *mime; - int code; + if (filename == NULL) + return(0); - code = xmlNanoHTTPReturnCode(ret->buf->context); - if (code >= 400) { - /* fatal error */ - if (ret->filename != NULL) - __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n", - (const char *) ret->filename); - else - __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL); - xmlFreeInputStream(ret); - ret = NULL; - } else { + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(0); - mime = xmlNanoHTTPMimeType(ret->buf->context); - if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || - (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { - encoding = xmlNanoHTTPEncoding(ret->buf->context); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr handler; - - handler = xmlFindCharEncodingHandler(encoding); - if (handler != NULL) { - xmlSwitchInputEncoding(ctxt, ret, handler); - } else { - __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, - "Unknown encoding %s", - BAD_CAST encoding, NULL); - } - if (ret->encoding == NULL) - ret->encoding = xmlStrdup(BAD_CAST encoding); - } -#if 0 - } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { -#endif - } - redir = xmlNanoHTTPRedir(ret->buf->context); - if (redir != NULL) { - if (ret->filename != NULL) - xmlFree((xmlChar *) ret->filename); - if (ret->directory != NULL) { - xmlFree((xmlChar *) ret->directory); - ret->directory = NULL; - } - ret->filename = - (char *) xmlStrdup((const xmlChar *) redir); - } - } - } -#endif + if (fromUri != NULL) + filename = fromUri; + + ret = xmlCheckFilename(filename); + + xmlFree(fromUri); return(ret); } -static int xmlNoNetExists(const char *URL) { - const char *path; +/************************************************************************ + * * + * Input/output callbacks * + * * + ************************************************************************/ - if (URL == NULL) - return(0); +/** + * xmlInitIOCallbacks: + * + * Initialize callback tables. + */ +void +xmlInitIOCallbacks(void) +{ + xmlInputCallbackNr = 1; + xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch; - if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &URL[17]; -#else - path = &URL[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &URL[8]; -#else - path = &URL[7]; +#ifdef LIBXML_OUTPUT_ENABLED + xmlOutputCallbackNr = 1; + xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch; #endif - } else - path = URL; - - return xmlCheckFilename(path); } -#ifdef LIBXML_CATALOG_ENABLED - /** - * xmlResolveResourceFromCatalog: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlRegisterInputCallbacks: + * @matchFunc: the xmlInputMatchCallback + * @openFunc: the xmlInputOpenCallback + * @readFunc: the xmlInputReadCallback + * @closeFunc: the xmlInputCloseCallback * - * Resolves the URL and ID against the appropriate catalog. - * This function is used by xmlDefaultExternalEntityLoader and - * xmlNoNetExternalEntityLoader. + * Register a new set of I/O callback for handling parser input. * - * Returns a new allocated URL, or NULL. + * Returns the registered handler number or -1 in case of error */ -static xmlChar * -xmlResolveResourceFromCatalog(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - xmlChar *resource = NULL; - xmlCatalogAllow pref; - - /* - * If the resource doesn't exists as a file, - * try to load it from the resource pointed in the catalogs - */ - pref = xmlCatalogGetDefaults(); - - if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { - /* - * Do a local lookup - */ - if ((ctxt != NULL) && (ctxt->catalogs != NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_DOCUMENT))) { - resource = xmlCatalogLocalResolve(ctxt->catalogs, - (const xmlChar *)ID, - (const xmlChar *)URL); - } - /* - * Try a global lookup - */ - if ((resource == NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_GLOBAL))) { - resource = xmlCatalogResolve((const xmlChar *)ID, - (const xmlChar *)URL); - } - if ((resource == NULL) && (URL != NULL)) - resource = xmlStrdup((const xmlChar *) URL); - - /* - * TODO: do an URI lookup on the reference - */ - if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { - xmlChar *tmp = NULL; - - if ((ctxt != NULL) && (ctxt->catalogs != NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_DOCUMENT))) { - tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); - } - if ((tmp == NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_GLOBAL))) { - tmp = xmlCatalogResolveURI(resource); - } +int +xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc) { + xmlInitParser(); - if (tmp != NULL) { - xmlFree(resource); - resource = tmp; - } - } + if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { + return(-1); } - - return resource; + xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; + xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; + xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; + xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; + return(xmlInputCallbackNr++); } -#endif +/** + * xmlRegisterDefaultInputCallbacks: + * + * Registers the default compiled-in I/O handlers. + */ +void +xmlRegisterDefaultInputCallbacks(void) { + xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); +} /** - * xmlDefaultExternalEntityLoader: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlPopInputCallbacks: * - * By default we don't load external entities, yet. + * Clear the top input callback from the input stack. this includes the + * compiled-in I/O. * - * Returns a new allocated xmlParserInputPtr, or NULL. + * Returns the number of input callback registered or -1 in case of error. */ -static xmlParserInputPtr -xmlDefaultExternalEntityLoader(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) +int +xmlPopInputCallbacks(void) { - xmlParserInputPtr ret = NULL; - xmlChar *resource = NULL; - -#ifdef DEBUG_EXTERNAL_ENTITIES - xmlGenericError(xmlGenericErrorContext, - "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); -#endif - if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { - int options = ctxt->options; + xmlInitParser(); - ctxt->options -= XML_PARSE_NONET; - ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); - ctxt->options = options; - return(ret); - } -#ifdef LIBXML_CATALOG_ENABLED - resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); -#endif + if (xmlInputCallbackNr <= 0) + return(-1); - if (resource == NULL) - resource = (xmlChar *) URL; + xmlInputCallbackNr--; - if (resource == NULL) { - if (ID == NULL) - ID = "NULL"; - __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID); - return (NULL); - } - ret = xmlNewInputFromFile(ctxt, (const char *) resource); - if ((resource != NULL) && (resource != (xmlChar *) URL)) - xmlFree(resource); - return (ret); + return(xmlInputCallbackNr); } -static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = - xmlDefaultExternalEntityLoader; - /** - * xmlSetExternalEntityLoader: - * @f: the new entity resolver function + * xmlCleanupInputCallbacks: * - * Changes the defaultexternal entity resolver function for the application + * clears the entire input callback table. this includes the + * compiled-in I/O. */ void -xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { - xmlCurrentExternalEntityLoader = f; +xmlCleanupInputCallbacks(void) +{ + xmlInitParser(); + + xmlInputCallbackNr = 0; } +#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlGetExternalEntityLoader: + * xmlRegisterOutputCallbacks: + * @matchFunc: the xmlOutputMatchCallback + * @openFunc: the xmlOutputOpenCallback + * @writeFunc: the xmlOutputWriteCallback + * @closeFunc: the xmlOutputCloseCallback + * + * Register a new set of I/O callback for handling output. * - * Get the default external entity resolver function for the application + * Returns the registered handler number or -1 in case of error + */ +int +xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc) { + xmlInitParser(); + + if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { + return(-1); + } + xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; + return(xmlOutputCallbackNr++); +} + +/** + * xmlRegisterDefaultOutputCallbacks: * - * Returns the xmlExternalEntityLoader function pointer + * Registers the default compiled-in I/O handlers. */ -xmlExternalEntityLoader -xmlGetExternalEntityLoader(void) { - return(xmlCurrentExternalEntityLoader); +void +xmlRegisterDefaultOutputCallbacks (void) { + xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); } /** - * xmlLoadExternalEntity: - * @URL: the URL for the entity to load - * @ID: the Public ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlPopOutputCallbacks: * - * Load an external entity, note that the use of this function for - * unparsed entities may generate problems + * Remove the top output callbacks from the output stack. This includes the + * compiled-in I/O. * - * Returns the xmlParserInputPtr or NULL + * Returns the number of output callback registered or -1 in case of error. */ -xmlParserInputPtr -xmlLoadExternalEntity(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { - char *canonicFilename; - xmlParserInputPtr ret; - - canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); - if (canonicFilename == NULL) { - xmlIOErrMemory("building canonical path\n"); - return(NULL); - } +int +xmlPopOutputCallbacks(void) +{ + xmlInitParser(); - ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); - xmlFree(canonicFilename); - return(ret); - } - return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); -} + if (xmlOutputCallbackNr <= 0) + return(-1); -/************************************************************************ - * * - * Disabling Network access * - * * - ************************************************************************/ + xmlOutputCallbackNr--; + + return(xmlOutputCallbackNr); +} /** - * xmlNoNetExternalEntityLoader: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL - * - * A specific entity loader disabling network accesses, though still - * allowing local catalog accesses for resolution. + * xmlCleanupOutputCallbacks: * - * Returns a new allocated xmlParserInputPtr, or NULL. + * clears the entire output callback table. this includes the + * compiled-in I/O callbacks. */ -xmlParserInputPtr -xmlNoNetExternalEntityLoader(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - xmlParserInputPtr input = NULL; - xmlChar *resource = NULL; - -#ifdef LIBXML_CATALOG_ENABLED - resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); -#endif +void +xmlCleanupOutputCallbacks(void) +{ + xmlInitParser(); - if (resource == NULL) - resource = (xmlChar *) URL; + xmlOutputCallbackNr = 0; +} - if (resource != NULL) { - if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || - (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { - xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); - if (resource != (xmlChar *) URL) - xmlFree(resource); - return(NULL); - } - } - input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); - if (resource != (xmlChar *) URL) - xmlFree(resource); - return(input); +#ifdef LIBXML_HTTP_ENABLED +/** + * xmlRegisterHTTPPostCallbacks: + * + * DEPRECATED: Support for HTTP POST has been removed. + */ +void +xmlRegisterHTTPPostCallbacks(void) { + xmlRegisterDefaultOutputCallbacks(); } +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ diff --git a/xmlcatalog.c b/xmlcatalog.c new file mode 100644 index 00000000000..cfc55132f3f --- /dev/null +++ b/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 +#include + +#ifdef HAVE_LIBREADLINE +#include +#ifdef HAVE_LIBHISTORY +#include +#endif +#endif + +#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 SYSCONFDIR "/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); + fflush(stdout); + 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") || + !strcmp(command, "quit") || + !strcmp(command, "bye")) { + free(cmdline); + 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 ((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 (void specification possibly expressed as \"\"\n\ +\tappoints the default system one) 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 information\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; + + if (filename == NULL && argv[i][0] == '\0') { + /* Interpret empty-string catalog specification as + a shortcut for a default system catalog. */ + xmlInitializeCatalog(); + } else { + filename = argv[i]; + ret = xmlLoadCatalog(argv[i]); + if ((ret < 0) && (create)) { + xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL); + } + + /* + * Catalogs are loaded lazily. Make sure that dumping works + * by the issuing a dummy request that forces the catalog to + * be loaded. + */ + xmlCatalogResolvePublic(BAD_CAST ""); + } + 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; + + xmlFreeCatalog(catal); + xmlFreeCatalog(super); + } 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(); + 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/xmllint.c b/xmllint.c new file mode 100644 index 00000000000..3a7a8a002e9 --- /dev/null +++ b/xmllint.c @@ -0,0 +1,3787 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIMEB_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#elif defined (_WIN32) +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +/* seems needed for Solaris */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif +#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 +#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 + +#ifdef XMLLINT_FUZZ + #define ERR_STREAM stdout +#else + #define ERR_STREAM stderr +#endif + +#ifndef XML_XML_DEFAULT_CATALOG +#define XML_XML_DEFAULT_CATALOG "file://" SYSCONFDIR "/xml/catalog" +#endif + +#ifndef STDIN_FILENO + #define STDIN_FILENO 0 +#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,*/ + XMLLINT_ERR_MEM = 9, /* Out of memory error */ + XMLLINT_ERR_XPATH = 10, /* XPath evaluation error */ + XMLLINT_ERR_XPATH_EMPTY = 11 /* XPath result is empty */ +} 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 noout = 0; +#ifdef LIBXML_OUTPUT_ENABLED +static const char *output = NULL; +static int format = 0; +static const char *encoding = NULL; +static int compress = 0; +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED +static int postvalid = 0; +static const char *dtdvalid = NULL; +static const char *dtdvalidfpi = NULL; +static int insert = 0; +#endif +#ifdef LIBXML_SCHEMAS_ENABLED +static const char *relaxng = NULL; +static xmlRelaxNGPtr relaxngschemas = NULL; +static const char *schema = NULL; +static xmlSchemaPtr wxschemas = NULL; +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED +static const char *schematron = NULL; +static xmlSchematronPtr wxschematron = NULL; +#endif +static int repeat = 0; +#if defined(LIBXML_HTML_ENABLED) +static int html = 0; +static int xmlout = 0; +#endif +static int htmlout = 0; +#ifdef LIBXML_PUSH_ENABLED +static int push = 0; +static int pushsize = 4096; +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_MMAP +static int memory = 0; +#endif +static int testIO = 0; +#ifdef LIBXML_XINCLUDE_ENABLED +static int xinclude = 0; +#endif +static xmllintReturnCode progresult = XMLLINT_RETURN_OK; +static int quiet = 0; +static int timing = 0; +static int generate = 0; +static int dropdtd = 0; +#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 walker = 0; +#ifdef LIBXML_PATTERN_ENABLED +static const char *pattern = NULL; +static xmlPatternPtr patternc = NULL; +static xmlStreamCtxtPtr patstream = NULL; +#endif +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_XPATH_ENABLED +static const char *xpathquery = NULL; +#endif +static int options = XML_PARSE_COMPACT | XML_PARSE_BIG_LINES; +static unsigned maxAmpl = 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(ERR_STREAM, "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 \ + (ERR_STREAM, + "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 \ + (ERR_STREAM, + "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(ERR_STREAM, "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) +{ + size_t oldsize = xmlMemSize(mem); + + if (xmlMemUsed() + size - oldsize > (size_t) maxmem) { + OOM(); + return (NULL); + } + + return (xmlMemRealloc(mem, size)); +} +static char * +myStrdupFunc(const char *str) +{ + char *ret; + + ret = xmlMemoryStrdup(str); + if (ret != NULL) { + if (xmlMemUsed() > maxmem) { + OOM(); + xmlMemFree(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 LIBXML_ATTR_FORMAT(1,2) +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; + + va_start(ap, fmt); + vfprintf(ERR_STREAM, fmt, ap); + va_end(ap); + + fprintf(ERR_STREAM, " took %ld ms\n", msec); +} +#else +/* + * 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 LIBXML_ATTR_FORMAT(1,2) +endTimer(const char *fmt, ...) +{ + long msec; + va_list ap; + + end = clock(); + msec = ((end - begin) * 1000) / CLOCKS_PER_SEC; + + va_start(ap, fmt); + vfprintf(ERR_STREAM, fmt, ap); + va_end(ap); + fprintf(ERR_STREAM, " took %ld ms\n", msec); +} +#endif +/************************************************************************ + * * + * HTML output * + * * + ************************************************************************/ +static char buffer[50000]; + +static void +xmlHTMLEncodeSend(void) { + char *result; + + /* + * xmlEncodeEntitiesReentrant assumes valid UTF-8, but the buffer might + * end with a truncated UTF-8 sequence. This is a hack to at least avoid + * an out-of-bounds read. + */ + memset(&buffer[sizeof(buffer)-4], 0, 4); + result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer); + if (result) { + fprintf(ERR_STREAM, "%s", result); + xmlFree(result); + } + buffer[0] = 0; +} + +/** + * xmlHTMLPrintFileInfo: + * @input: an xmlParserInputPtr input + * + * Displays the associated file and line information for the current input + */ + +static void +xmlHTMLPrintFileInfo(xmlParserInputPtr input) { + int len; + fprintf(ERR_STREAM, "

"); + + 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; + fprintf(ERR_STREAM, "

\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 > base) && ((*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();
+    fprintf(ERR_STREAM, "
"); +} + +/** + * 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 LIBXML_ATTR_FORMAT(2,3) +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); + + fprintf(ERR_STREAM, "error: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "

\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 LIBXML_ATTR_FORMAT(2,3) +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); + + fprintf(ERR_STREAM, "warning: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "

\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 LIBXML_ATTR_FORMAT(2,3) +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 != NULL) { + if ((input->filename == NULL) && (ctxt->inputNr > 1)) + input = ctxt->inputTab[ctxt->inputNr - 2]; + + xmlHTMLPrintFileInfo(input); + } + + fprintf(ERR_STREAM, "validity error: "); + len = strlen(buffer); + va_start(args, msg); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "

\n"); + + if (input != NULL) + 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 LIBXML_ATTR_FORMAT(2,3) +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); + + fprintf(ERR_STREAM, "validity warning: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "

\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); + fflush(stdout); + 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(void *f, char *buf, int len) { + return(fread(buf, 1, len, (FILE *) f)); +} +static int myClose(void *context) { + FILE *f = (FILE *) context; + if (f == stdin) + return(0); + return(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(ERR_STREAM, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(ERR_STREAM, "%s validation generated an internal error\n", + filename); + progresult = XMLLINT_ERR_VALID; + } + } + xmlSchemaFreeValidCtxt(vctxt); + } else +#endif + { + xmlParserCtxtPtr ctxt = NULL; + + /* + * Create the parser context amd hook the input + */ + ctxt = xmlNewSAXParserCtxt(handler, (void *) user_data); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + return; + } + if (maxAmpl > 0) + xmlCtxtSetMaxAmplification(ctxt, maxAmpl); + + if (strcmp(filename, "-") == 0) + xmlCtxtReadFd(ctxt, STDIN_FILENO, "-", NULL, options); + else + xmlCtxtReadFile(ctxt, filename, NULL, options); + + if (ctxt->myDoc != NULL) { + fprintf(ERR_STREAM, "SAX generated a doc !\n"); + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + 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(ERR_STREAM, "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(ERR_STREAM, + "xmlPatternMatch and xmlStreamPush disagree\n"); + if (path != NULL) + fprintf(ERR_STREAM, " pattern %s node %s\n", + pattern, path); + else + fprintf(ERR_STREAM, " 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(ERR_STREAM, "xmlStreamPop() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } + if (path != NULL) + xmlFree(path); + } +#endif +} + +static void streamFile(const char *filename) { + xmlTextReaderPtr reader; + int ret; +#ifdef HAVE_MMAP + int fd = -1; + struct stat info; + const char *base = 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) { + close(fd); + fprintf(ERR_STREAM, "mmap failure for file %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + return; + } + + reader = xmlReaderForMemory(base, info.st_size, filename, + NULL, options); + } else +#endif + if (strcmp(filename, "-") == 0) + reader = xmlReaderForFd(STDIN_FILENO, "-", NULL, options); + else + reader = xmlReaderForFile(filename, NULL, options); +#ifdef LIBXML_PATTERN_ENABLED + if (patternc != NULL) { + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream != NULL) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(ERR_STREAM, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } +#endif + + + if (reader != NULL) { + if (maxAmpl > 0) + xmlTextReaderSetMaxAmplification(reader, maxAmpl); +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxng != NULL) { + if ((timing) && (!repeat)) { + startTimer(); + } + ret = xmlTextReaderRelaxNGValidate(reader, relaxng); + if (ret < 0) { + fprintf(ERR_STREAM, + "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) { + fprintf(ERR_STREAM, + "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 (options & XML_PARSE_DTDVALID) + endTimer("Parsing and validating"); + else +#endif + endTimer("Parsing"); + } + +#ifdef LIBXML_VALID_ENABLED + if (options & XML_PARSE_DTDVALID) { + if (xmlTextReaderIsValid(reader) != 1) { + fprintf(ERR_STREAM, + "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(ERR_STREAM, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + if (!quiet) { + fprintf(ERR_STREAM, "%s validates\n", filename); + } + } + } +#endif + /* + * Done, cleanup and status + */ + xmlFreeTextReader(reader); + if (ret != 0) { + fprintf(ERR_STREAM, "%s : failed to parse\n", filename); + progresult = XMLLINT_ERR_UNCLASS; + } + } else { + fprintf(ERR_STREAM, "Unable to open %s\n", filename); + progresult = XMLLINT_ERR_UNCLASS; + } +#ifdef LIBXML_PATTERN_ENABLED + if (patstream != NULL) { + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } +#endif +#ifdef HAVE_MMAP + if (memory) { + munmap((char *) base, info.st_size); + close(fd); + } +#endif +} + +static void walkDoc(xmlDocPtr doc) { + xmlTextReaderPtr reader; + int ret; + +#ifdef LIBXML_PATTERN_ENABLED + if (pattern != NULL) { + xmlNodePtr root; + const xmlChar *namespaces[22]; + int i; + xmlNsPtr ns; + + root = xmlDocGetRootElement(doc); + if (root == NULL ) { + fprintf(ERR_STREAM, + "Document does not have a root element"); + progresult = XMLLINT_ERR_UNCLASS; + return; + } + 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; + + ret = xmlPatternCompileSafe((const xmlChar *) pattern, doc->dict, + 0, &namespaces[0], &patternc); + if (patternc == NULL) { + if (ret < 0) { + progresult = XMLLINT_ERR_MEM; + } else { + fprintf(ERR_STREAM, + "Pattern %s failed to compile\n", pattern); + progresult = XMLLINT_ERR_SCHEMAPAT; + } + goto error; + } + + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream == NULL) { + progresult = XMLLINT_ERR_MEM; + goto error; + } + + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(ERR_STREAM, "xmlStreamPush() failure\n"); + progresult = XMLLINT_ERR_MEM; + goto error; + } + } +#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(ERR_STREAM, "failed to walk through the doc\n"); + progresult = XMLLINT_ERR_UNCLASS; + } + } else { + fprintf(ERR_STREAM, "Failed to crate a reader from the document\n"); + progresult = XMLLINT_ERR_UNCLASS; + } + +#ifdef LIBXML_PATTERN_ENABLED +error: + if (patternc != NULL) { + xmlFreePattern(patternc); + patternc = NULL; + } + 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: { +#ifdef LIBXML_OUTPUT_ENABLED + xmlOutputBufferPtr buf; + xmlNodePtr node; + int i; + + if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr <= 0)) { + progresult = XMLLINT_ERR_XPATH_EMPTY; + if (!quiet) { + fprintf(ERR_STREAM, "XPath set is empty\n"); + } + break; + } + buf = xmlOutputBufferCreateFile(stdout, NULL); + if (buf == NULL) { + fprintf(ERR_STREAM, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + for (i = 0;i < cur->nodesetval->nodeNr;i++) { + node = cur->nodesetval->nodeTab[i]; + xmlNodeDumpOutput(buf, NULL, node, 0, 0, NULL); + xmlOutputBufferWrite(buf, 1, "\n"); + } + xmlOutputBufferClose(buf); +#else + printf("xpath returned %d nodes\n", cur->nodesetval->nodeNr); +#endif + break; + } + case XPATH_BOOLEAN: + if (cur->boolval) printf("true\n"); + else printf("false\n"); + break; + case XPATH_NUMBER: + switch (xmlXPathIsInf(cur->floatval)) { + case 1: + printf("Infinity\n"); + break; + case -1: + printf("-Infinity\n"); + break; + default: + if (xmlXPathIsNaN(cur->floatval)) { + printf("NaN\n"); + } else { + printf("%0g\n", cur->floatval); + } + } + break; + case XPATH_STRING: + printf("%s\n", (const char *) cur->stringval); + break; + case XPATH_UNDEFINED: + fprintf(ERR_STREAM, "XPath Object is uninitialized\n"); + progresult = XMLLINT_ERR_XPATH; + break; + default: + fprintf(ERR_STREAM, "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(ERR_STREAM, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + ctxt->node = (xmlNodePtr) doc; + res = xmlXPathEval(BAD_CAST query, ctxt); + xmlXPathFreeContext(ctxt); + + if (res == NULL) { + fprintf(ERR_STREAM, "XPath evaluation failure\n"); + progresult = XMLLINT_ERR_XPATH; + return; + } + doXPathDump(res); + xmlXPathFreeObject(res); +} +#endif /* LIBXML_XPATH_ENABLED */ + +/************************************************************************ + * * + * Tree Test processing * + * * + ************************************************************************/ + +static xmlDocPtr +parseFile(const char *filename, xmlParserCtxtPtr rectxt) { + xmlParserCtxtPtr ctxt; + xmlDocPtr doc = NULL; + +#ifdef LIBXML_TREE_ENABLED + if ((generate) && (filename == NULL)) { + xmlNodePtr n; + + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) { + progresult = XMLLINT_ERR_MEM; + return(NULL); + } + n = xmlNewDocNode(doc, NULL, BAD_CAST "info", NULL); + if (n == NULL) { + xmlFreeDoc(doc); + progresult = XMLLINT_ERR_MEM; + return(NULL); + } + if (xmlNodeSetContent(n, BAD_CAST "abc") < 0) { + xmlFreeNode(n); + xmlFreeDoc(doc); + progresult = XMLLINT_ERR_MEM; + return(NULL); + } + xmlDocSetRootElement(doc, n); + + return(doc); + } +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_HTML_ENABLED +#ifdef LIBXML_PUSH_ENABLED + if ((html) && (push)) { + FILE *f; + int res; + char chars[4096]; + + if ((filename[0] == '-') && (filename[1] == 0)) { + f = stdin; + } else { + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(ERR_STREAM, "Can't open %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + return(NULL); + } + } + + res = fread(chars, 1, 4, f); + ctxt = htmlCreatePushParserCtxt(NULL, NULL, + chars, res, filename, XML_CHAR_ENCODING_NONE); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + if (f != stdin) + fclose(f); + return(NULL); + } + htmlCtxtUseOptions(ctxt, options); + while ((res = fread(chars, 1, pushsize, f)) > 0) { + htmlParseChunk(ctxt, chars, res, 0); + } + htmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + htmlFreeParserCtxt(ctxt); + if (f != stdin) + fclose(f); + + return(doc); + } +#endif /* LIBXML_PUSH_ENABLED */ + +#ifdef HAVE_MMAP + if ((html) && (memory)) { + int fd; + struct stat info; + const char *base; + if (stat(filename, &info) < 0) + return(NULL); + if ((fd = open(filename, O_RDONLY)) < 0) + return(NULL); + base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ; + if (base == (void *) MAP_FAILED) { + close(fd); + fprintf(ERR_STREAM, "mmap failure for file %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + return(NULL); + } + + doc = htmlReadMemory((char *) base, info.st_size, filename, + NULL, options); + + munmap((char *) base, info.st_size); + close(fd); + + return(doc); + } +#endif + + if (html) { + if (strcmp(filename, "-") == 0) + doc = htmlReadFd(STDIN_FILENO, "-", NULL, options); + else + doc = htmlReadFile(filename, NULL, options); + + return(doc); + } +#endif /* LIBXML_HTML_ENABLED */ + +#ifdef LIBXML_PUSH_ENABLED + if (push) { + FILE *f; + int res; + char chars[4096]; + + if ((filename[0] == '-') && (filename[1] == 0)) { + f = stdin; + } else { + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(ERR_STREAM, "Can't open %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + return(NULL); + } + } + + res = fread(chars, 1, 4, f); + ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, filename); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + if (f != stdin) + fclose(f); + return(NULL); + } + xmlCtxtUseOptions(ctxt, options); + + if (maxAmpl > 0) + xmlCtxtSetMaxAmplification(ctxt, maxAmpl); + + if (htmlout) { + ctxt->sax->error = xmlHTMLError; + ctxt->sax->warning = xmlHTMLWarning; + ctxt->vctxt.error = xmlHTMLValidityError; + ctxt->vctxt.warning = xmlHTMLValidityWarning; + } + + while ((res = fread(chars, 1, pushsize, f)) > 0) { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + + doc = ctxt->myDoc; + if (f != stdin) + fclose(f); + } else +#endif /* LIBXML_PUSH_ENABLED */ + { + if (rectxt == NULL) { + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + return(NULL); + } + } else { + ctxt = rectxt; + } + + if (maxAmpl > 0) + xmlCtxtSetMaxAmplification(ctxt, maxAmpl); + + if (htmlout) { + ctxt->sax->error = xmlHTMLError; + ctxt->sax->warning = xmlHTMLWarning; + ctxt->vctxt.error = xmlHTMLValidityError; + ctxt->vctxt.warning = xmlHTMLValidityWarning; + } + + if (testIO) { + FILE *f; + + if ((filename[0] == '-') && (filename[1] == 0)) { + f = stdin; + } else { + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(ERR_STREAM, "Can't open %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + goto error; + } + } + + doc = xmlCtxtReadIO(ctxt, myRead, myClose, f, filename, NULL, + options); +#ifdef HAVE_MMAP + } else if (memory) { + int fd; + struct stat info; + const char *base; + + if (stat(filename, &info) < 0) + goto error; + if ((fd = open(filename, O_RDONLY)) < 0) + goto error; + base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ; + if (base == (void *) MAP_FAILED) { + close(fd); + fprintf(ERR_STREAM, "mmap failure for file %s\n", filename); + progresult = XMLLINT_ERR_RDFILE; + goto error; + } + + doc = xmlCtxtReadMemory(ctxt, base, info.st_size, filename, NULL, + options); + + munmap((char *) base, info.st_size); + close(fd); +#endif + } else { + if (strcmp(filename, "-") == 0) + doc = xmlCtxtReadFd(ctxt, STDIN_FILENO, "-", NULL, options); + else + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + } + } + + if (doc == NULL) { + if (ctxt->errNo == XML_ERR_NO_MEMORY) + progresult = XMLLINT_ERR_MEM; + else + progresult = XMLLINT_ERR_RDFILE; + } else { +#ifdef LIBXML_VALID_ENABLED + if ((options & XML_PARSE_DTDVALID) && (ctxt->valid == 0)) + progresult = XMLLINT_ERR_VALID; +#endif /* LIBXML_VALID_ENABLED */ + } + +error: + if (ctxt != rectxt) + xmlFreeParserCtxt(ctxt); + + return(doc); +} + +static void +parseAndPrintFile(const char *filename, xmlParserCtxtPtr rectxt) { + xmlDocPtr doc; + + if ((timing) && (!repeat)) + startTimer(); + + doc = parseFile(filename, rectxt); + if (doc == NULL) { + if (progresult == XMLLINT_RETURN_OK) + progresult = XMLLINT_ERR_UNCLASS; + return; + } + + if ((timing) && (!repeat)) { + endTimer("Parsing"); + } + + if (dropdtd) { + xmlDtdPtr dtd; + + dtd = xmlGetIntSubset(doc); + if (dtd != NULL) { + xmlUnlinkNode((xmlNodePtr)dtd); + doc->intSubset = 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) { + xmlDocPtr tmp; + + tmp = doc; + if (timing) { + startTimer(); + } + doc = xmlCopyDoc(doc, 1); + if (doc == NULL) { + progresult = XMLLINT_ERR_MEM; + xmlFreeDoc(tmp); + return; + } + if (timing) { + endTimer("Copying"); + } + if (timing) { + startTimer(); + } + xmlFreeDoc(tmp); + if (timing) { + endTimer("Freeing original"); + } + } +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED + if ((insert) +#ifdef LIBXML_HTML_ENABLED + && (!html) +#endif + ) { + const xmlChar* list[256]; + int nb, i; + xmlNodePtr node; + + if (doc->children != NULL) { + node = doc->children; + while ((node != NULL) && + ((node->type != XML_ELEMENT_NODE) || + (node->last == NULL))) + node = node->next; + if (node != NULL) { + nb = xmlValidGetValidElements(node->last, NULL, list, 256); + if (nb < 0) { + fprintf(ERR_STREAM, "could not get valid list of elements\n"); + } else if (nb == 0) { + fprintf(ERR_STREAM, "No element can be inserted under root\n"); + } else { + fprintf(ERR_STREAM, "%d element types can be inserted under root:\n", + nb); + for (i = 0;i < nb;i++) { + fprintf(ERR_STREAM, "%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) { + if (compress) + xmlSetDocCompressMode(doc, 9); + + /* + * print it. + */ +#ifdef LIBXML_DEBUG_ENABLED + if (!debug) { +#endif + if ((timing) && (!repeat)) { + startTimer(); + } +#ifdef LIBXML_HTML_ENABLED + if ((html) && (!xmlout)) { + if (compress) { + htmlSaveFile(output ? output : "-", doc); + } + else if (encoding != NULL) { + if (format == 1) { + htmlSaveFileFormat(output ? output : "-", doc, encoding, 1); + } + else { + htmlSaveFileFormat(output ? output : "-", doc, encoding, 0); + } + } + else if (format == 1) { + htmlSaveFileFormat(output ? output : "-", doc, NULL, 1); + } + else { + FILE *out; + if (output == NULL) + out = stdout; + else { + out = fopen(output,"wb"); + } + if (out != NULL) { + if (htmlDocDump(out, doc) < 0) + progresult = XMLLINT_ERR_OUT; + + if (output != NULL) + fclose(out); + } else { + fprintf(ERR_STREAM, "failed to open %s\n", output); + progresult = XMLLINT_ERR_OUT; + } + } + if ((timing) && (!repeat)) { + endTimer("Saving"); + } + } else +#endif +#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(ERR_STREAM, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(ERR_STREAM, "Failed to canonicalize\n"); + progresult = XMLLINT_ERR_OUT; + } + } else if (canonical_11) { + 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(ERR_STREAM, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(ERR_STREAM, "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(ERR_STREAM, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(ERR_STREAM, "Failed to canonicalize\n"); + progresult = XMLLINT_ERR_OUT; + } + } else +#endif +#ifdef HAVE_MMAP + 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(ERR_STREAM, "Failed to save\n"); + progresult = XMLLINT_ERR_OUT; + } else { + if (write(1, result, len) == -1) { + fprintf(ERR_STREAM, "Can't write data\n"); + } + xmlFree(result); + } + + } else +#endif /* HAVE_MMAP */ + if (compress) { + xmlSaveFile(output ? output : "-", doc); + } else { + xmlSaveCtxtPtr ctxt; + int saveOpts = 0; + + if (format == 1) + saveOpts |= XML_SAVE_FORMAT; + else if (format == 2) + saveOpts |= XML_SAVE_WSNONSIG; + +#if defined(LIBXML_HTML_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(ERR_STREAM, "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(ERR_STREAM, "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) + fprintf(ERR_STREAM, + "Could not parse DTD %s\n", dtdvalid); + else + fprintf(ERR_STREAM, + "Could not parse DTD %s\n", dtdvalidfpi); + progresult = XMLLINT_ERR_DTD; + } else { + xmlValidCtxtPtr cvp; + + if ((cvp = xmlNewValidCtxt()) == NULL) { + fprintf(ERR_STREAM, + "Couldn't allocate validation context\n"); + progresult = XMLLINT_ERR_MEM; + xmlFreeDtd(dtd); + return; + } + + if ((timing) && (!repeat)) { + startTimer(); + } + if (!xmlValidateDtd(cvp, doc, dtd)) { + if (dtdvalid != NULL) + fprintf(ERR_STREAM, + "Document %s does not validate against %s\n", + filename, dtdvalid); + else + fprintf(ERR_STREAM, + "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) { + fprintf(ERR_STREAM, + "Couldn't allocate validation context\n"); + progresult = XMLLINT_ERR_MEM; + xmlFreeDoc(doc); + return; + } + + if ((timing) && (!repeat)) { + startTimer(); + } + if (!xmlValidateDocument(cvp, doc)) { + fprintf(ERR_STREAM, + "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 (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + xmlFreeDoc(doc); + return; + } + ret = xmlSchematronValidateDoc(ctxt, doc); + if (ret == 0) { + if (!quiet) { + fprintf(ERR_STREAM, "%s validates\n", filename); + } + } else if (ret > 0) { + fprintf(ERR_STREAM, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(ERR_STREAM, "%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); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + xmlFreeDoc(doc); + return; + } + ret = xmlRelaxNGValidateDoc(ctxt, doc); + if (ret == 0) { + if (!quiet) { + fprintf(ERR_STREAM, "%s validates\n", filename); + } + } else if (ret > 0) { + fprintf(ERR_STREAM, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(ERR_STREAM, "%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); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + xmlFreeDoc(doc); + return; + } + ret = xmlSchemaValidateDoc(ctxt, doc); + if (ret == 0) { + if (!quiet) { + fprintf(ERR_STREAM, "%s validates\n", filename); + } + } else if (ret > 0) { + fprintf(ERR_STREAM, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(ERR_STREAM, "%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 ((debugent) +#if defined(LIBXML_HTML_ENABLED) + && (!html) +#endif + ) + xmlDebugDumpEntities(ERR_STREAM, doc); +#endif + + /* + * free it. + */ + if ((timing) && (!repeat)) { + startTimer(); + } + xmlFreeDoc(doc); + if ((timing) && (!repeat)) { + endTimer("Freeing"); + } +} + +/************************************************************************ + * * + * Usage and Main * + * * + ************************************************************************/ + +static void showVersion(const char *name) { + fprintf(ERR_STREAM, "%s: using libxml version %s\n", name, xmlParserVersion); + fprintf(ERR_STREAM, " compiled with: "); + if (xmlHasFeature(XML_WITH_THREAD)) fprintf(ERR_STREAM, "Threads "); + if (xmlHasFeature(XML_WITH_TREE)) fprintf(ERR_STREAM, "Tree "); + if (xmlHasFeature(XML_WITH_OUTPUT)) fprintf(ERR_STREAM, "Output "); + if (xmlHasFeature(XML_WITH_PUSH)) fprintf(ERR_STREAM, "Push "); + if (xmlHasFeature(XML_WITH_READER)) fprintf(ERR_STREAM, "Reader "); + if (xmlHasFeature(XML_WITH_PATTERN)) fprintf(ERR_STREAM, "Patterns "); + if (xmlHasFeature(XML_WITH_WRITER)) fprintf(ERR_STREAM, "Writer "); + if (xmlHasFeature(XML_WITH_SAX1)) fprintf(ERR_STREAM, "SAXv1 "); + if (xmlHasFeature(XML_WITH_FTP)) fprintf(ERR_STREAM, "FTP "); + if (xmlHasFeature(XML_WITH_HTTP)) fprintf(ERR_STREAM, "HTTP "); + if (xmlHasFeature(XML_WITH_VALID)) fprintf(ERR_STREAM, "DTDValid "); + if (xmlHasFeature(XML_WITH_HTML)) fprintf(ERR_STREAM, "HTML "); + if (xmlHasFeature(XML_WITH_LEGACY)) fprintf(ERR_STREAM, "Legacy "); + if (xmlHasFeature(XML_WITH_C14N)) fprintf(ERR_STREAM, "C14N "); + if (xmlHasFeature(XML_WITH_CATALOG)) fprintf(ERR_STREAM, "Catalog "); + if (xmlHasFeature(XML_WITH_XPATH)) fprintf(ERR_STREAM, "XPath "); + if (xmlHasFeature(XML_WITH_XPTR)) fprintf(ERR_STREAM, "XPointer "); + if (xmlHasFeature(XML_WITH_XINCLUDE)) fprintf(ERR_STREAM, "XInclude "); + if (xmlHasFeature(XML_WITH_ICONV)) fprintf(ERR_STREAM, "Iconv "); + if (xmlHasFeature(XML_WITH_ICU)) fprintf(ERR_STREAM, "ICU "); + if (xmlHasFeature(XML_WITH_ISO8859X)) fprintf(ERR_STREAM, "ISO8859X "); + if (xmlHasFeature(XML_WITH_UNICODE)) fprintf(ERR_STREAM, "Unicode "); + if (xmlHasFeature(XML_WITH_REGEXP)) fprintf(ERR_STREAM, "Regexps "); + if (xmlHasFeature(XML_WITH_AUTOMATA)) fprintf(ERR_STREAM, "Automata "); + if (xmlHasFeature(XML_WITH_EXPR)) fprintf(ERR_STREAM, "Expr "); + if (xmlHasFeature(XML_WITH_SCHEMAS)) fprintf(ERR_STREAM, "Schemas "); + if (xmlHasFeature(XML_WITH_SCHEMATRON)) fprintf(ERR_STREAM, "Schematron "); + if (xmlHasFeature(XML_WITH_MODULES)) fprintf(ERR_STREAM, "Modules "); + if (xmlHasFeature(XML_WITH_DEBUG)) fprintf(ERR_STREAM, "Debug "); + if (xmlHasFeature(XML_WITH_ZLIB)) fprintf(ERR_STREAM, "Zlib "); + if (xmlHasFeature(XML_WITH_LZMA)) fprintf(ERR_STREAM, "Lzma "); + fprintf(ERR_STREAM, "\n"); +} + +static void usage(FILE *f, const char *name) { + fprintf(f, "Usage : %s [options] XMLfiles ...\n", name); +#ifdef LIBXML_OUTPUT_ENABLED + fprintf(f, "\tParse the XML files and output the result of the parsing\n"); +#else + fprintf(f, "\tParse the XML files\n"); +#endif /* LIBXML_OUTPUT_ENABLED */ + fprintf(f, "\t--version : display the version of the XML library used\n"); +#ifdef LIBXML_DEBUG_ENABLED + fprintf(f, "\t--debug : dump a debug tree of the in-memory document\n"); + fprintf(f, "\t--shell : run a navigating shell\n"); + fprintf(f, "\t--debugent : debug the entities defined in the document\n"); +#else +#ifdef LIBXML_READER_ENABLED + fprintf(f, "\t--debug : dump the nodes content when using --stream\n"); +#endif /* LIBXML_READER_ENABLED */ +#endif +#ifdef LIBXML_TREE_ENABLED + fprintf(f, "\t--copy : used to test the internal copy implementation\n"); +#endif /* LIBXML_TREE_ENABLED */ + fprintf(f, "\t--recover : output what was parsable on broken XML documents\n"); + fprintf(f, "\t--huge : remove any internal arbitrary parser limits\n"); + fprintf(f, "\t--noent : substitute entity references by their value\n"); + fprintf(f, "\t--noenc : ignore any encoding specified inside the document\n"); + fprintf(f, "\t--noout : don't output the result tree\n"); + fprintf(f, "\t--path 'paths': provide a set of paths for resources\n"); + fprintf(f, "\t--load-trace : print trace of all external entities loaded\n"); + fprintf(f, "\t--nonet : refuse to fetch DTDs or entities over network\n"); + fprintf(f, "\t--nocompact : do not generate compact text nodes\n"); + fprintf(f, "\t--htmlout : output results as HTML\n"); + fprintf(f, "\t--nowrap : do not put HTML doc wrapper\n"); +#ifdef LIBXML_VALID_ENABLED + fprintf(f, "\t--valid : validate the document in addition to std well-formed check\n"); + fprintf(f, "\t--postvalid : do a posteriori validation, i.e after parsing\n"); + fprintf(f, "\t--dtdvalid URL : do a posteriori validation against a given DTD\n"); + fprintf(f, "\t--dtdvalidfpi FPI : same but name the DTD with a Public Identifier\n"); + fprintf(f, "\t--insert : ad-hoc test for valid insertions\n"); +#endif /* LIBXML_VALID_ENABLED */ + fprintf(f, "\t--quiet : be quiet when succeeded\n"); + fprintf(f, "\t--timing : print some timings\n"); + fprintf(f, "\t--repeat : repeat 100 times, for timing or profiling\n"); + fprintf(f, "\t--dropdtd : remove the DOCTYPE of the input docs\n"); +#ifdef LIBXML_HTML_ENABLED + fprintf(f, "\t--html : use the HTML parser\n"); + fprintf(f, "\t--xmlout : force to use the XML serializer when using --html\n"); + fprintf(f, "\t--nodefdtd : do not default HTML doctype\n"); +#endif +#ifdef LIBXML_PUSH_ENABLED + fprintf(f, "\t--push : use the push mode of the parser\n"); + fprintf(f, "\t--pushsmall : use the push mode of the parser using tiny increments\n"); +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_MMAP + fprintf(f, "\t--memory : parse from memory\n"); +#endif + fprintf(f, "\t--maxmem nbbytes : limits memory allocation to nbbytes bytes\n"); + fprintf(f, "\t--nowarning : do not emit warnings from parser/validator\n"); + fprintf(f, "\t--noblanks : drop (ignorable?) blanks spaces\n"); + fprintf(f, "\t--nocdata : replace cdata section with text nodes\n"); +#ifdef LIBXML_OUTPUT_ENABLED + fprintf(f, "\t--output file or -o file: save to a given file\n"); + fprintf(f, "\t--format : reformat/reindent the output\n"); + fprintf(f, "\t--encode encoding : output in the given encoding\n"); + fprintf(f, "\t--pretty STYLE : pretty-print in a particular style\n"); + fprintf(f, "\t 0 Do not pretty print\n"); + fprintf(f, "\t 1 Format the XML content, as --format\n"); + fprintf(f, "\t 2 Add whitespace inside tags, preserving content\n"); +#ifdef LIBXML_ZLIB_ENABLED + fprintf(f, "\t--compress : turn on gzip compression of output\n"); +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ + fprintf(f, "\t--c14n : save in W3C canonical format v1.0 (with comments)\n"); + fprintf(f, "\t--c14n11 : save in W3C canonical format v1.1 (with comments)\n"); + fprintf(f, "\t--exc-c14n : save in W3C exclusive canonical format (with comments)\n"); +#ifdef LIBXML_C14N_ENABLED +#endif /* LIBXML_C14N_ENABLED */ + fprintf(f, "\t--nsclean : remove redundant namespace declarations\n"); + fprintf(f, "\t--testIO : test user I/O support\n"); +#ifdef LIBXML_CATALOG_ENABLED + fprintf(f, "\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n"); + fprintf(f, "\t otherwise XML Catalogs starting from \n"); + fprintf(f, "\t %s are activated by default\n", XML_XML_DEFAULT_CATALOG); + fprintf(f, "\t--nocatalogs: deactivate all catalogs\n"); +#endif + fprintf(f, "\t--auto : generate a small doc on the fly\n"); +#ifdef LIBXML_XINCLUDE_ENABLED + fprintf(f, "\t--xinclude : do XInclude processing\n"); + fprintf(f, "\t--noxincludenode : same but do not generate XInclude nodes\n"); + fprintf(f, "\t--nofixup-base-uris : do not fixup xml:base uris\n"); +#endif + fprintf(f, "\t--loaddtd : fetch external DTD\n"); + fprintf(f, "\t--dtdattr : loaddtd + populate the tree with inherited attributes \n"); +#ifdef LIBXML_READER_ENABLED + fprintf(f, "\t--stream : use the streaming interface to process very large files\n"); + fprintf(f, "\t--walker : create a reader and walk though the resulting doc\n"); +#ifdef LIBXML_PATTERN_ENABLED + fprintf(f, "\t--pattern pattern_value : test the pattern support\n"); +#endif +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + fprintf(f, "\t--relaxng schema : do RelaxNG validation against the schema\n"); + fprintf(f, "\t--schema schema : do validation against the WXS schema\n"); +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + fprintf(f, "\t--schematron schema : do validation against a schematron\n"); +#endif +#ifdef LIBXML_SAX1_ENABLED + fprintf(f, "\t--sax1: use the old SAX1 interfaces for processing\n"); +#endif + fprintf(f, "\t--sax: do not build a tree but work just at the SAX level\n"); + fprintf(f, "\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n"); +#ifdef LIBXML_XPATH_ENABLED + fprintf(f, "\t--xpath expr: evaluate the XPath expression, imply --noout\n"); +#endif + fprintf(f, "\t--max-ampl value: set maximum amplification factor\n"); + + fprintf(f, "\nLibxml project home page: https://gitlab.gnome.org/GNOME/libxml2\n"); +} + +static unsigned long +parseInteger(const char *ctxt, const char *str, + unsigned long min, unsigned long max) { + char *strEnd; + unsigned long val; + + errno = 0; + val = strtoul(str, &strEnd, 10); + if (errno == EINVAL || *strEnd != 0) { + fprintf(ERR_STREAM, "%s: invalid integer: %s\n", ctxt, str); + exit(XMLLINT_ERR_UNCLASS); + } + if (errno != 0 || val < min || val > max) { + fprintf(ERR_STREAM, "%s: integer out of range: %s\n", ctxt, str); + exit(XMLLINT_ERR_UNCLASS); + } + + return(val); +} + +static int +skipArgs(const char *arg) { + if ((!strcmp(arg, "-path")) || + (!strcmp(arg, "--path")) || + (!strcmp(arg, "-maxmem")) || + (!strcmp(arg, "--maxmem")) || +#ifdef LIBXML_OUTPUT_ENABLED + (!strcmp(arg, "-o")) || + (!strcmp(arg, "-output")) || + (!strcmp(arg, "--output")) || + (!strcmp(arg, "-encode")) || + (!strcmp(arg, "--encode")) || + (!strcmp(arg, "-pretty")) || + (!strcmp(arg, "--pretty")) || +#endif +#ifdef LIBXML_VALID_ENABLED + (!strcmp(arg, "-dtdvalid")) || + (!strcmp(arg, "--dtdvalid")) || + (!strcmp(arg, "-dtdvalidfpi")) || + (!strcmp(arg, "--dtdvalidfpi")) || +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + (!strcmp(arg, "-relaxng")) || + (!strcmp(arg, "--relaxng")) || + (!strcmp(arg, "-schema")) || + (!strcmp(arg, "--schema")) || +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + (!strcmp(arg, "-schematron")) || + (!strcmp(arg, "--schematron")) || +#endif +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED) + (!strcmp(arg, "-pattern")) || + (!strcmp(arg, "--pattern")) || +#endif +#ifdef LIBXML_XPATH_ENABLED + (!strcmp(arg, "-xpath")) || + (!strcmp(arg, "--xpath")) || +#endif + (!strcmp(arg, "-max-ampl")) || + (!strcmp(arg, "--max-ampl")) + ) { + return(1); + } + + return(0); +} + +static int +xmllintMain(int argc, const char **argv) { + int i, acount; + int files = 0; + int version = 0; + int nowrap = 0; + int sax = 0; +#ifdef LIBXML_READER_ENABLED + int stream = 0; +#endif +#ifdef LIBXML_CATALOG_ENABLED + int catalogs = 0; + int nocatalogs = 0; +#endif + +#ifdef XMLLINT_FUZZ +#ifdef LIBXML_DEBUG_ENABLED + shell = 0; + debugent = 0; +#endif + debug = 0; + maxmem = 0; +#ifdef LIBXML_TREE_ENABLED + copy = 0; +#endif /* LIBXML_TREE_ENABLED */ + noout = 0; +#ifdef LIBXML_OUTPUT_ENABLED + format = 0; + output = NULL; + compress = 0; +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED + postvalid = 0; + dtdvalid = NULL; + dtdvalidfpi = NULL; + insert = 0; +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + relaxng = NULL; + relaxngschemas = NULL; + schema = NULL; + wxschemas = NULL; +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + schematron = NULL; + wxschematron = NULL; +#endif + repeat = 0; +#if defined(LIBXML_HTML_ENABLED) + html = 0; + xmlout = 0; +#endif + htmlout = 0; +#ifdef LIBXML_PUSH_ENABLED + push = 0; + pushsize = 4096; +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_MMAP + memory = 0; +#endif + testIO = 0; + encoding = NULL; +#ifdef LIBXML_XINCLUDE_ENABLED + xinclude = 0; +#endif + progresult = XMLLINT_RETURN_OK; + quiet = 0; + timing = 0; + generate = 0; + dropdtd = 0; +#ifdef LIBXML_C14N_ENABLED + canonical = 0; + canonical_11 = 0; + exc_canonical = 0; +#endif +#ifdef LIBXML_READER_ENABLED + walker = 0; +#ifdef LIBXML_PATTERN_ENABLED + pattern = NULL; + patternc = NULL; + patstream = NULL; +#endif +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_XPATH_ENABLED + xpathquery = NULL; +#endif + options = XML_PARSE_COMPACT | XML_PARSE_BIG_LINES; + maxAmpl = 0; + defaultEntityLoader = NULL; +#endif /* XMLLINT_FUZZ */ + + if (argc <= 1) { + usage(ERR_STREAM, argv[0]); + return(XMLLINT_ERR_UNCLASS); + } + + /* xmlMemSetup must be called before initializing the parser. */ + for (i = 1; i < argc ; i++) { + if ((!strcmp(argv[i], "-maxmem")) || + (!strcmp(argv[i], "--maxmem"))) { + i++; + if (i >= argc) { + fprintf(ERR_STREAM, "maxmem: missing integer value\n"); + return(XMLLINT_ERR_UNCLASS); + } + errno = 0; + maxmem = parseInteger("maxmem", argv[i], 0, INT_MAX); + } else if (argv[i][0] == '-') { + i += skipArgs(argv[i]); + } + } + if (maxmem != 0) + xmlMemSetup(myFreeFunc, myMallocFunc, myReallocFunc, myStrdupFunc); + + LIBXML_TEST_VERSION + + for (i = 1; i < argc ; i++) { + if (argv[i][0] != '-' || argv[i][1] == 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"))) { + 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"))) { + options |= XML_PARSE_NOENT; + } else if ((!strcmp(argv[i], "-noenc")) || + (!strcmp(argv[i], "--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++; + else if ((!strcmp(argv[i], "-htmlout")) || + (!strcmp(argv[i], "--htmlout"))) + htmlout++; + else if ((!strcmp(argv[i], "-nowrap")) || + (!strcmp(argv[i], "--nowrap"))) + nowrap++; +#ifdef LIBXML_HTML_ENABLED + else if ((!strcmp(argv[i], "-html")) || + (!strcmp(argv[i], "--html"))) { + html++; + } + else if ((!strcmp(argv[i], "-xmlout")) || + (!strcmp(argv[i], "--xmlout"))) { + xmlout++; + } else if ((!strcmp(argv[i], "-nodefdtd")) || + (!strcmp(argv[i], "--nodefdtd"))) { + options |= HTML_PARSE_NODEFDTD; + } +#endif /* LIBXML_HTML_ENABLED */ + else if ((!strcmp(argv[i], "-loaddtd")) || + (!strcmp(argv[i], "--loaddtd"))) { + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdattr")) || + (!strcmp(argv[i], "--dtdattr"))) { + options |= XML_PARSE_DTDATTR; + } +#ifdef LIBXML_VALID_ENABLED + else if ((!strcmp(argv[i], "-valid")) || + (!strcmp(argv[i], "--valid"))) { + options |= XML_PARSE_DTDVALID; + } else if ((!strcmp(argv[i], "-postvalid")) || + (!strcmp(argv[i], "--postvalid"))) { + postvalid++; + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdvalid")) || + (!strcmp(argv[i], "--dtdvalid"))) { + i++; + dtdvalid = argv[i]; + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdvalidfpi")) || + (!strcmp(argv[i], "--dtdvalidfpi"))) { + i++; + dtdvalidfpi = argv[i]; + options |= XML_PARSE_DTDLOAD; + } + else if ((!strcmp(argv[i], "-insert")) || + (!strcmp(argv[i], "--insert"))) + insert++; +#endif /* LIBXML_VALID_ENABLED */ + else if ((!strcmp(argv[i], "-dropdtd")) || + (!strcmp(argv[i], "--dropdtd"))) + dropdtd++; + else if ((!strcmp(argv[i], "-quiet")) || + (!strcmp(argv[i], "--quiet"))) + quiet++; + 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++; + else if ((!strcmp(argv[i], "-pushsmall")) || + (!strcmp(argv[i], "--pushsmall"))) { + push++; + pushsize = 10; + } +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_MMAP + 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 + else if ((!strcmp(argv[i], "-nowarning")) || + (!strcmp(argv[i], "--nowarning"))) { + options |= XML_PARSE_NOWARNING; + options &= ~XML_PARSE_PEDANTIC; + } + else if ((!strcmp(argv[i], "-pedantic")) || + (!strcmp(argv[i], "--pedantic"))) { + options |= XML_PARSE_PEDANTIC; + options &= ~XML_PARSE_NOWARNING; + } +#ifdef LIBXML_DEBUG_ENABLED + else if ((!strcmp(argv[i], "-debugent")) || + (!strcmp(argv[i], "--debugent"))) { + debugent++; + } +#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], "-noblanks")) || + (!strcmp(argv[i], "--noblanks"))) { + options |= XML_PARSE_NOBLANKS; + } + else if ((!strcmp(argv[i], "-maxmem")) || + (!strcmp(argv[i], "--maxmem"))) { + i++; + } +#ifdef LIBXML_OUTPUT_ENABLED + else if ((!strcmp(argv[i], "-o")) || + (!strcmp(argv[i], "-output")) || + (!strcmp(argv[i], "--output"))) { + i++; + output = argv[i]; + } + else if ((!strcmp(argv[i], "-format")) || + (!strcmp(argv[i], "--format"))) { + format = 1; + options |= XML_PARSE_NOBLANKS; + } + 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], "-pretty")) || + (!strcmp(argv[i], "--pretty"))) { + i++; + if (argv[i] != NULL) + format = atoi(argv[i]); + } +#ifdef LIBXML_ZLIB_ENABLED + else if ((!strcmp(argv[i], "-compress")) || + (!strcmp(argv[i], "--compress"))) { + compress++; + } +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ +#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++; + } +#ifdef LIBXML_PATTERN_ENABLED + else if ((!strcmp(argv[i], "-pattern")) || + (!strcmp(argv[i], "--pattern"))) { + i++; + pattern = argv[i]; + } +#endif +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_SAX1_ENABLED + else if ((!strcmp(argv[i], "-sax1")) || + (!strcmp(argv[i], "--sax1"))) { + options |= XML_PARSE_SAX1; + } +#endif /* LIBXML_SAX1_ENABLED */ + else if ((!strcmp(argv[i], "-sax")) || + (!strcmp(argv[i], "--sax"))) { + sax++; + } +#ifdef LIBXML_SCHEMAS_ENABLED + else if ((!strcmp(argv[i], "-relaxng")) || + (!strcmp(argv[i], "--relaxng"))) { + i++; + relaxng = argv[i]; + options |= XML_PARSE_NOENT; + } else if ((!strcmp(argv[i], "-schema")) || + (!strcmp(argv[i], "--schema"))) { + i++; + schema = argv[i]; + options |= XML_PARSE_NOENT; + } +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + else if ((!strcmp(argv[i], "-schematron")) || + (!strcmp(argv[i], "--schematron"))) { + i++; + schematron = argv[i]; + options |= XML_PARSE_NOENT; + } +#endif + else if ((!strcmp(argv[i], "-nonet")) || + (!strcmp(argv[i], "--nonet"))) { + options |= XML_PARSE_NONET; +#ifndef XMLLINT_FUZZ + xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader); +#endif + } 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_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"))) { + options |= XML_PARSE_OLD10; + } else if ((!strcmp(argv[i], "-max-ampl")) || + (!strcmp(argv[i], "--max-ampl"))) { + i++; + if (i >= argc) { + fprintf(ERR_STREAM, "max-ampl: missing integer value\n"); + return(XMLLINT_ERR_UNCLASS); + } + maxAmpl = parseInteger("max-ampl", argv[i], 1, UINT_MAX); + } else { + fprintf(ERR_STREAM, "Unknown option %s\n", argv[i]); + usage(ERR_STREAM, argv[0]); + return(XMLLINT_ERR_UNCLASS); + } + } + +#ifdef LIBXML_CATALOG_ENABLED + if (nocatalogs == 0) { + if (catalogs) { + const char *catal; + + catal = getenv("SGML_CATALOG_FILES"); + if (catal != NULL) { + xmlLoadCatalogs(catal); + } else { + fprintf(ERR_STREAM, "Variable $SGML_CATALOG_FILES not set\n"); + } + } + } +#endif + +#ifdef LIBXML_OUTPUT_ENABLED + { + const char *indent = getenv("XMLLINT_INDENT"); + if (indent != NULL) { + xmlTreeIndentString = indent; + } + } +#endif + + defaultEntityLoader = xmlGetExternalEntityLoader(); + xmlSetExternalEntityLoader(xmllintExternalEntityLoader); + + if ((htmlout) && (!nowrap)) { + fprintf(ERR_STREAM, + "\n"); + fprintf(ERR_STREAM, + "%s output\n", + argv[0]); + fprintf(ERR_STREAM, + "

%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 */ + options |= XML_PARSE_DTDLOAD; + if (timing) { + startTimer(); + } + ctxt = xmlSchematronNewParserCtxt(schematron); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + goto error; + } + wxschematron = xmlSchematronParse(ctxt); + if (wxschematron == NULL) { + fprintf(ERR_STREAM, + "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 */ + options |= XML_PARSE_DTDLOAD; + if (timing) { + startTimer(); + } + ctxt = xmlRelaxNGNewParserCtxt(relaxng); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + goto error; + } + relaxngschemas = xmlRelaxNGParse(ctxt); + if (relaxngschemas == NULL) { + fprintf(ERR_STREAM, + "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); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + goto error; + } + wxschemas = xmlSchemaParse(ctxt); + if (wxschemas == NULL) { + fprintf(ERR_STREAM, + "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 */ +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED) + if ((pattern != NULL) && (walker == 0)) { + patternc = xmlPatterncompile((const xmlChar *) pattern, NULL, 0, NULL); + if (patternc == NULL) { + fprintf(ERR_STREAM, + "Pattern %s failed to compile\n", pattern); + progresult = XMLLINT_ERR_SCHEMAPAT; + pattern = NULL; + } + } +#endif /* LIBXML_READER_ENABLED && LIBXML_PATTERN_ENABLED */ + for (i = 1; i < argc ; i++) { + if ((argv[i][0] == '-') && (strcmp(argv[i], "-") != 0)) { + i += skipArgs(argv[i]); + continue; + } + if ((timing) && (repeat)) + startTimer(); + if (repeat) { + xmlParserCtxtPtr ctxt; + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + goto error; + } + if (maxAmpl > 0) + xmlCtxtSetMaxAmplification(ctxt, maxAmpl); + + 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 { + parseAndPrintFile(argv[i], ctxt); + } +#ifdef LIBXML_READER_ENABLED + } +#endif /* LIBXML_READER_ENABLED */ + } + + xmlFreeParserCtxt(ctxt); + } else { +#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); + } + } + files ++; + if ((timing) && (repeat)) { + endTimer("%d iterations", repeat); + } + } + if (generate) + parseAndPrintFile(NULL, NULL); + if ((htmlout) && (!nowrap)) { + fprintf(ERR_STREAM, "\n"); + } + if ((files == 0) && (!generate) && (version == 0)) { + usage(ERR_STREAM, argv[0]); + progresult = XMLLINT_ERR_UNCLASS; + } +#ifdef LIBXML_SCHEMATRON_ENABLED + if (wxschematron != NULL) + xmlSchematronFree(wxschematron); +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxngschemas != NULL) + xmlRelaxNGFree(relaxngschemas); + if (wxschemas != NULL) + xmlSchemaFree(wxschemas); +#endif +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED) + if (patternc != NULL) + xmlFreePattern(patternc); +#endif + + /* Avoid unused label warning if features are disabled. */ + goto error; + +error: + if (defaultEntityLoader != NULL) + xmlSetExternalEntityLoader(defaultEntityLoader); + xmlCleanupParser(); + + return(progresult); +} + +#ifndef XMLLINT_FUZZ +int +main(int argc, char **argv) { + return(xmllintMain(argc, (const char **) argv)); +} +#endif + diff --git a/xmlmemory.c b/xmlmemory.c index 892d50c306d..f0628e2a83a 100644 --- a/xmlmemory.c +++ b/xmlmemory.c @@ -12,32 +12,17 @@ #include #include -/* #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 #include -static int xmlMemInitialized = 0; +#include "private/memory.h" +#include "private/threads.h" + static unsigned long debugMemSize = 0; static unsigned long debugMemBlocks = 0; -static unsigned long debugMaxMemSize = 0; -static xmlMutexPtr xmlMemMutex = NULL; - -void xmlMallocBreakpoint(void); +static xmlMutex xmlMemMutex; /************************************************************************ * * @@ -45,51 +30,23 @@ void xmlMallocBreakpoint(void); * * ************************************************************************/ -#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED) -#ifdef xmlMalloc -#undef xmlMalloc -#endif -#ifdef xmlRealloc -#undef xmlRealloc -#endif -#ifdef xmlMemStrdup -#undef xmlMemStrdup -#endif -#endif - /* * Each of the blocks allocated begin with a header containing information */ #define MEMTAG 0x5aa5U -#define MALLOC_TYPE 1 -#define REALLOC_TYPE 2 -#define STRDUP_TYPE 3 -#define MALLOC_ATOMIC_TYPE 4 -#define REALLOC_ATOMIC_TYPE 5 - typedef struct memnod { unsigned int mh_tag; - unsigned int mh_type; - unsigned long mh_number; size_t mh_size; -#ifdef MEM_LIST - struct memnod *mh_next; - struct memnod *mh_prev; -#endif - const char *mh_file; - unsigned int mh_line; -} MEMHDR; - +} MEMHDR; #ifdef SUN4 #define ALIGN_SIZE 16 #else #define ALIGN_SIZE sizeof(double) #endif -#define HDR_SIZE sizeof(MEMHDR) -#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \ +#define RESERVE_SIZE (((sizeof(MEMHDR) + ALIGN_SIZE - 1) \ / ALIGN_SIZE ) * ALIGN_SIZE) #define MAX_SIZE_T ((size_t)-1) @@ -97,113 +54,21 @@ typedef struct memnod { #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE)) #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE)) - -static unsigned int block=0; -static unsigned int xmlMemStopAtBlock = 0; -static void *xmlMemTraceBlockAt = NULL; -#ifdef MEM_LIST -static MEMHDR *memlist = NULL; -#endif - -static void debugmem_tag_error(void *addr); -#ifdef MEM_LIST -static void debugmem_list_add(MEMHDR *); -static void debugmem_list_delete(MEMHDR *); -#endif -#define Mem_Tag_Err(a) debugmem_tag_error(a); - -#ifndef TEST_POINT -#define TEST_POINT -#endif - -/** - * xmlMallocBreakpoint: - * - * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block - * number reaches the specified value this function is called. One need to add a breakpoint - * to it to get the context in which the given block is allocated. - */ - -void -xmlMallocBreakpoint(void) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock); -} - /** * xmlMallocLoc: * @size: an int specifying the size in byte to allocate. * @file: the file name or NULL * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlMallocLoc(size_t size, const char * file, int line) +xmlMallocLoc(size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { - MEMHDR *p; - void *ret; - - if (!xmlMemInitialized) xmlInitMemory(); -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "Malloc(%d)\n",size); -#endif - - TEST_POINT - - if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocLoc : Unsigned overflow\n"); - xmlMemoryDump(); - return(NULL); - } - - 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); + return(xmlMemMalloc(size)); } /** @@ -212,196 +77,119 @@ xmlMallocLoc(size_t size, const char * file, int line) * @file: the file name or NULL * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ +void * +xmlMallocAtomicLoc(size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) +{ + return(xmlMemMalloc(size)); +} +/** + * xmlMemMalloc: + * @size: an int specifying the size in byte to allocate. + * + * a malloc() equivalent, with logging of the allocation info. + * + * Returns a pointer to the allocated area or NULL in case of lack of memory. + */ void * -xmlMallocAtomicLoc(size_t size, const char * file, int line) +xmlMemMalloc(size_t size) { MEMHDR *p; - void *ret; - - if (!xmlMemInitialized) xmlInitMemory(); -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "Malloc(%d)\n",size); -#endif - TEST_POINT + xmlInitParser(); if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocAtomicLoc : Unsigned overflow\n"); - xmlMemoryDump(); - return(NULL); + fprintf(stderr, "xmlMemMalloc: Unsigned overflow\n"); + return(NULL); } - p = (MEMHDR *) malloc(RESERVE_SIZE+size); - + p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocAtomicLoc : Out of free space\n"); - xmlMemoryDump(); - return(NULL); + fprintf(stderr, "xmlMemMalloc: Out of memory\n"); + return(NULL); } p->mh_tag = MEMTAG; p->mh_size = size; - p->mh_type = MALLOC_ATOMIC_TYPE; - p->mh_file = file; - p->mh_line = line; - xmlMutexLock(xmlMemMutex); - p->mh_number = ++block; + + xmlMutexLock(&xmlMemMutex); 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(); + xmlMutexUnlock(&xmlMemMutex); - ret = HDR_2_CLIENT(p); - - if (xmlMemTraceBlockAt == ret) { - xmlGenericError(xmlGenericErrorContext, - "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, - (long unsigned)size); - xmlMallocBreakpoint(); - } - - TEST_POINT - - return(ret); + return(HDR_2_CLIENT(p)); } + /** - * xmlMemMalloc: + * xmlReallocLoc: + * @ptr: the initial memory block pointer * @size: an int specifying the size in byte to allocate. + * @file: the file name or NULL + * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlMemMalloc(size_t size) +xmlReallocLoc(void *ptr, size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { - return(xmlMallocLoc(size, "none", 0)); + return(xmlMemRealloc(ptr, size)); } /** - * xmlReallocLoc: + * xmlMemRealloc: * @ptr: the initial memory block pointer * @size: an int specifying the size in byte to allocate. - * @file: the file name or NULL - * @line: the line number * * a realloc() equivalent, with logging of the allocation info. * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlReallocLoc(void *ptr,size_t size, const char * file, int line) -{ +xmlMemRealloc(void *ptr, size_t size) { MEMHDR *p, *tmp; - unsigned long number; -#ifdef DEBUG_MEMORY - size_t oldsize; -#endif + size_t oldSize; if (ptr == NULL) - return(xmlMallocLoc(size, file, line)); + return(xmlMemMalloc(size)); + + xmlInitParser(); - if (!xmlMemInitialized) xmlInitMemory(); - TEST_POINT + if (size > (MAX_SIZE_T - RESERVE_SIZE)) { + fprintf(stderr, "xmlMemRealloc: Unsigned overflow\n"); + return(NULL); + } p = CLIENT_2_HDR(ptr); - number = p->mh_number; - if (xmlMemStopAtBlock == number) xmlMallocBreakpoint(); if (p->mh_tag != MEMTAG) { - Mem_Tag_Err(p); - goto error; + fprintf(stderr, "xmlMemRealloc: Tag error\n"); + return(NULL); } + oldSize = p->mh_size; p->mh_tag = ~MEMTAG; - xmlMutexLock(xmlMemMutex); - debugMemSize -= p->mh_size; - debugMemBlocks--; -#ifdef DEBUG_MEMORY - oldsize = p->mh_size; -#endif -#ifdef MEM_LIST - debugmem_list_delete(p); -#endif - xmlMutexUnlock(xmlMemMutex); - - if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlReallocLoc : Unsigned overflow\n"); - xmlMemoryDump(); - return(NULL); - } - tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size); + tmp = (MEMHDR *) realloc(p, RESERVE_SIZE + size); if (!tmp) { - free(p); - goto error; + p->mh_tag = MEMTAG; + fprintf(stderr, "xmlMemRealloc: Out of memory\n"); + return(NULL); } p = tmp; - if (xmlMemTraceBlockAt == ptr) { - xmlGenericError(xmlGenericErrorContext, - "%p : Realloced(%lu -> %lu) Ok\n", - xmlMemTraceBlockAt, (long unsigned)p->mh_size, - (long unsigned)size); - xmlMallocBreakpoint(); - } p->mh_tag = MEMTAG; - p->mh_number = number; - p->mh_type = REALLOC_TYPE; p->mh_size = size; - p->mh_file = file; - p->mh_line = line; - xmlMutexLock(xmlMemMutex); - debugMemSize += size; - debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif - xmlMutexUnlock(xmlMemMutex); - TEST_POINT + xmlMutexLock(&xmlMemMutex); + debugMemSize -= oldSize; + debugMemSize += size; + xmlMutexUnlock(&xmlMemMutex); -#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)); } /** @@ -414,64 +202,30 @@ void xmlMemFree(void *ptr) { MEMHDR *p; - char *target; -#ifdef DEBUG_MEMORY - size_t size; -#endif if (ptr == NULL) - return; + return; if (ptr == (void *) -1) { - xmlGenericError(xmlGenericErrorContext, - "trying to free pointer from freed area\n"); - goto error; - } - - if (xmlMemTraceBlockAt == ptr) { - xmlGenericError(xmlGenericErrorContext, - "%p : Freed()\n", xmlMemTraceBlockAt); - xmlMallocBreakpoint(); + fprintf(stderr, "xmlMemFree: Pointer from freed area\n"); + return; } - TEST_POINT - - target = (char *) ptr; - p = CLIENT_2_HDR(ptr); if (p->mh_tag != MEMTAG) { - Mem_Tag_Err(p); - goto error; + fprintf(stderr, "xmlMemFree: Tag error\n"); + return; } - if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); p->mh_tag = ~MEMTAG; - memset(target, -1, p->mh_size); - xmlMutexLock(xmlMemMutex); + memset(ptr, -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); + xmlMutexUnlock(&xmlMemMutex); free(p); - TEST_POINT - -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "Freed(%d) Ok\n", size); -#endif - - return; - -error: - xmlGenericError(xmlGenericErrorContext, - "xmlMemFree(%p) error\n", ptr); - xmlMallocBreakpoint(); return; } @@ -481,79 +235,77 @@ error: * @file: the file name or NULL * @line: the line number * - * a strdup() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the new string or NULL if allocation error occurred. */ - char * -xmlMemStrdupLoc(const char *str, const char *file, int line) +xmlMemStrdupLoc(const char *str, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { + return(xmlMemoryStrdup(str)); +} + +/** + * xmlMemoryStrdup: + * @str: the initial string pointer + * + * a strdup() equivalent, with logging of the allocation info. + * + * Returns a pointer to the new string or NULL if allocation error occurred. + */ +char * +xmlMemoryStrdup(const char *str) { char *s; size_t size = strlen(str) + 1; MEMHDR *p; - if (!xmlMemInitialized) xmlInitMemory(); - TEST_POINT + xmlInitParser(); if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMemStrdupLoc : Unsigned overflow\n"); - xmlMemoryDump(); - return(NULL); + fprintf(stderr, "xmlMemoryStrdup: Unsigned overflow\n"); + return(NULL); } - p = (MEMHDR *) malloc(RESERVE_SIZE+size); + p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) { - goto error; + fprintf(stderr, "xmlMemoryStrdup: Out of memory\n"); + return(NULL); } p->mh_tag = MEMTAG; p->mh_size = size; - p->mh_type = STRDUP_TYPE; - p->mh_file = file; - p->mh_line = line; - xmlMutexLock(xmlMemMutex); - p->mh_number = ++block; + + xmlMutexLock(&xmlMemMutex); debugMemSize += size; debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif - xmlMutexUnlock(xmlMemMutex); + xmlMutexUnlock(&xmlMemMutex); s = (char *) HDR_2_CLIENT(p); - if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); - - strcpy(s,str); - - TEST_POINT - - if (xmlMemTraceBlockAt == s) { - xmlGenericError(xmlGenericErrorContext, - "%p : Strdup() Ok\n", xmlMemTraceBlockAt); - xmlMallocBreakpoint(); - } + memcpy(s, str, size); return(s); - -error: - return(NULL); } /** - * xmlMemoryStrdup: - * @str: the initial string pointer - * - * a strdup() equivalent, with logging of the allocation info. + * xmlMemSize: + * @ptr: pointer to the memory allocation * - * Returns a pointer to the new string or NULL if allocation error occurred. + * Returns the size of a memory allocation. */ -char * -xmlMemoryStrdup(const char *str) { - return(xmlMemStrdupLoc(str, "none", 0)); +size_t +xmlMemSize(void *ptr) { + MEMHDR *p; + + if (ptr == NULL) + return(0); + + p = CLIENT_2_HDR(ptr); + if (p->mh_tag != MEMTAG) + return(0); + + return(p->mh_size); } /** @@ -566,12 +318,7 @@ xmlMemoryStrdup(const char *str) { int xmlMemUsed(void) { - int res; - - xmlMutexLock(xmlMemMutex); - res = debugMemSize; - xmlMutexUnlock(xmlMemMutex); - return(res); + return(debugMemSize); } /** @@ -586,343 +333,55 @@ int xmlMemBlocks(void) { int res; - xmlMutexLock(xmlMemMutex); + xmlMutexLock(&xmlMemMutex); res = debugMemBlocks; - xmlMutexUnlock(xmlMemMutex); + xmlMutexUnlock(&xmlMemMutex); return(res); } -#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; - const char *buf; - - if (p == NULL) { - fprintf(fp, " NULL"); - return; - } - len = p->mh_size; - buf = (const char *) HDR_2_CLIENT(p); - - 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 + * @fp: a FILE descriptor * @nbBytes: the amount of memory to dump * - * the last nbBytes of memory allocated and not freed, useful for dumping - * the memory left allocated between two places at runtime. + * DEPRECATED: This feature was removed. */ - void -xmlMemDisplayLast(FILE *fp, long nbBytes) +xmlMemDisplayLast(FILE *fp ATTRIBUTE_UNUSED, long nbBytes ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; - unsigned idx; - int nb = 0; -#endif - FILE *old_fp = fp; - - if (nbBytes <= 0) - return; - - if (fp == NULL) { - fp = fopen(".memorylist", "w"); - if (fp == NULL) - return; - } - -#ifdef MEM_LIST - fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", - nbBytes, debugMemSize, debugMaxMemSize); - fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); - idx = 0; - xmlMutexLock(xmlMemMutex); - p = memlist; - while ((p) && (nbBytes > 0)) { - fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, - (unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default: - fprintf(fp,"Unknown memory block, may be corrupted"); - xmlMutexUnlock(xmlMemMutex); - if (old_fp == NULL) - fclose(fp); - return; - } - if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - nb++; - 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 + * @fp: a FILE descriptor * - * show in-extenso the memory blocks allocated + * DEPRECATED: This feature was removed. */ - void -xmlMemDisplay(FILE *fp) +xmlMemDisplay(FILE *fp ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; - unsigned idx; - int nb = 0; - time_t currentTime; - char buf[500]; - struct tm * tstruct; -#endif - FILE *old_fp = fp; - - if (fp == NULL) { - fp = fopen(".memorylist", "w"); - if (fp == NULL) - return; - } - -#ifdef MEM_LIST - currentTime = time(NULL); - tstruct = localtime(¤tTime); - strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); - fprintf(fp," %s\n\n", buf); - - - fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", - debugMemSize, debugMaxMemSize); - fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); - idx = 0; - xmlMutexLock(xmlMemMutex); - p = memlist; - while (p) { - fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, - (unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default: - fprintf(fp,"Unknown memory block, may be corrupted"); - xmlMutexUnlock(xmlMemMutex); - if (old_fp == NULL) - fclose(fp); - return; - } - if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - nb++; - 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 + * @fp: a FILE descriptor * @nr: number of entries to dump * - * show a show display of the memory allocated, and dump - * the @nr last allocated areas which were not freed + * DEPRECATED: This feature was removed. */ - void -xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) +xmlMemShow(FILE *fp ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; -#endif - - if (fp != NULL) - fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", - debugMemSize, debugMaxMemSize); -#ifdef MEM_LIST - xmlMutexLock(xmlMemMutex); - if (nr > 0) { - fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); - p = memlist; - while ((p) && nr > 0) { - fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default:fprintf(fp," ??? in ");break; - } - if (p->mh_file != NULL) - fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - 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 + * DEPRECATED: This feature was removed. */ - void xmlMemoryDump(void) { -#ifdef MEM_LIST - FILE *dump; - - if (debugMaxMemSize == 0) - return; - dump = fopen(".memdump", "w"); - if (dump == NULL) - xmlMemoryDumpFile = stderr; - else xmlMemoryDumpFile = dump; - - xmlMemDisplay(xmlMemoryDumpFile); - - if (dump != NULL) fclose(dump); -#endif /* MEM_LIST */ } @@ -935,71 +394,55 @@ xmlMemoryDump(void) /** * xmlInitMemory: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. + * DEPRECATED: Alias for xmlInitParser. * - * Initialize the memory layer. - * - * Returns 0 on success + * Returns 0. */ int -xmlInitMemory(void) -{ - char *breakpoint; -#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(); - - breakpoint = getenv("XML_MEM_BREAKPOINT"); - if (breakpoint != NULL) { - sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); - } - breakpoint = getenv("XML_MEM_TRACE"); - if (breakpoint != NULL) { - sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); - } - -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "xmlInitMemory() Ok\n"); -#endif - return(0); +xmlInitMemory(void) { + xmlInitParser(); + return(0); +} + +/** + * xmlInitMemoryInternal: + * + * Initialize the memory layer. + */ +void +xmlInitMemoryInternal(void) { + xmlInitMutex(&xmlMemMutex); } /** * xmlCleanupMemory: * - * DEPRECATED: This function will be made private. Call xmlCleanupParser + * DEPRECATED: This function is a no-op. Call xmlCleanupParser * to free global state but see the warnings there. xmlCleanupParser * should be only called once at program exit. In most cases, you don't * have call cleanup functions at all. + */ +void +xmlCleanupMemory(void) { +} + +/** + * xmlCleanupMemoryInternal: * * 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"); +xmlCleanupMemoryInternal(void) { + /* + * Don't clean up mutex on Windows. Global state destructors can call + * malloc functions after xmlCleanupParser was called. If memory + * debugging is enabled, xmlMemMutex can be used after cleanup. + * + * See python/tests/thread2.py + */ +#if !defined(LIBXML_THREAD_ENABLED) || !defined(_WIN32) + xmlCleanupMutex(&xmlMemMutex); #endif } @@ -1021,10 +464,6 @@ xmlCleanupMemory(void) { 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) @@ -1038,10 +477,6 @@ xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlMallocAtomic = mallocFunc; xmlRealloc = reallocFunc; xmlMemStrdup = strdupFunc; -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "xmlMemSetup() Ok\n"); -#endif return(0); } @@ -1088,10 +523,6 @@ 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) @@ -1107,10 +538,6 @@ xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, xmlMallocAtomic = mallocAtomicFunc; xmlRealloc = reallocFunc; xmlMemStrdup = strdupFunc; -#ifdef DEBUG_MEMORY - xmlGenericError(xmlGenericErrorContext, - "xmlGcMemSetup() Ok\n"); -#endif return(0); } diff --git a/xmlmodule.c b/xmlmodule.c index 44eba066977..dd2fd7a5393 100644 --- a/xmlmodule.c +++ b/xmlmodule.c @@ -17,10 +17,12 @@ #include "libxml.h" #include +#include #include #include -#include -#include +#include + +#include "private/error.h" #ifdef LIBXML_MODULES_ENABLED @@ -39,27 +41,6 @@ static int xmlModulePlatformSymbol(void *handle, const char *name, void **result * * ************************************************************************/ -/** - * 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 @@ -80,10 +61,8 @@ xmlModuleOpen(const char *name, int options ATTRIBUTE_UNUSED) xmlModulePtr module; module = (xmlModulePtr) xmlMalloc(sizeof(xmlModule)); - if (module == NULL) { - xmlModuleErrMemory(NULL, "creating module"); + if (module == NULL) return (NULL); - } memset(module, 0, sizeof(xmlModule)); @@ -91,9 +70,6 @@ xmlModuleOpen(const char *name, int options ATTRIBUTE_UNUSED) 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); } @@ -120,23 +96,13 @@ xmlModuleSymbol(xmlModulePtr module, const char *name, void **symbol) { int rc = -1; - if ((NULL == module) || (symbol == NULL) || (name == 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"); + if ((NULL == module) || (symbol == NULL) || (name == NULL)) 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)); + if (rc == -1) return rc; - } return rc; } @@ -156,22 +122,13 @@ 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"); + if (NULL == module) 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); + if (rc != 0) return -2; - } rc = xmlModuleFree(module); return (rc); @@ -190,12 +147,8 @@ xmlModuleClose(xmlModulePtr module) 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"); + if (NULL == module) return -1; - } xmlFree(module->name); xmlFree(module); @@ -340,7 +293,7 @@ xmlModulePlatformClose(void *handle) static int xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) { -XML_IGNORE_PEDANTIC_WARNINGS +XML_IGNORE_FPTR_CAST_WARNINGS *symbol = GetProcAddress(handle, name); return (NULL == *symbol) ? -1 : 0; XML_POP_WARNINGS @@ -348,112 +301,4 @@ XML_POP_WARNINGS #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 */ - #endif /* LIBXML_MODULES_ENABLED */ diff --git a/xmlreader.c b/xmlreader.c index b3299cedfcc..3528d7d8f0c 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -39,9 +39,13 @@ #include #endif -#include "buf.h" - -#define MAX_ERR_MSG_SIZE 64000 +#include "private/buf.h" +#include "private/error.h" +#include "private/tree.h" +#include "private/parser.h" +#ifdef LIBXML_XINCLUDE_ENABLED +#include "private/xinclude.h" +#endif #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Keeping free objects can hide memory errors. */ @@ -50,48 +54,14 @@ #define MAX_FREE_NODES 100 #endif -/* - * The following VA_COPY was coded following an example in - * the Samba project. It may not be sufficient for some - * esoteric implementations of va_list but (hopefully) will - * be sufficient for libxml2. - */ -#ifndef VA_COPY - #ifdef HAVE_VA_COPY - #define VA_COPY(dest, src) va_copy(dest, src) +#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) #else - #ifdef HAVE___VA_COPY - #define VA_COPY(dest,src) __va_copy(dest, src) - #else - #ifndef VA_LIST_IS_ARRAY - #define VA_COPY(dest,src) (dest) = (src) - #else - #include - #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list)) - #endif - #endif + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) #endif #endif -/* #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 /************************************************************************ * * @@ -192,22 +162,9 @@ struct _xmlTextReader { #define NODE_IS_PRESERVED 0x2 #define NODE_IS_SPRESERVED 0x4 -/** - * CONSTSTR: - * - * Macro used to return an interned string - */ -#define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1) -#define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str)) - static int xmlTextReaderReadTree(xmlTextReaderPtr reader); static int xmlTextReaderNextTree(xmlTextReaderPtr reader); -/************************************************************************ - * * - * Our own version of the freeing routines as we recycle nodes * - * * - ************************************************************************/ /** * DICT_FREE: * @str: a string @@ -223,6 +180,65 @@ static int xmlTextReaderNextTree(xmlTextReaderPtr reader); static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur); static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur); +static void +xmlTextReaderErrMemory(xmlTextReaderPtr reader) { + if (reader->ctxt != NULL) + xmlCtxtErrMemory(reader->ctxt); + else + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_PARSER, NULL); + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; +} + +static xmlChar * +readerStrdup(xmlTextReaderPtr reader, const xmlChar *string) { + xmlChar *copy; + + if (string == NULL) + return(NULL); + + copy = xmlStrdup(string); + if (copy == NULL) + xmlTextReaderErrMemory(reader); + + return(copy); +} + +static const xmlChar * +constString(xmlTextReaderPtr reader, const xmlChar *string) { + const xmlChar *dictString; + + if (string == NULL) + return(NULL); + + dictString = xmlDictLookup(reader->dict, string, -1); + if (dictString == NULL) + xmlTextReaderErrMemory(reader); + + return(dictString); +} + +static const xmlChar * +constQString(xmlTextReaderPtr reader, const xmlChar *prefix, + const xmlChar *name) { + const xmlChar *dictString; + + if (name == NULL) + return(NULL); + + dictString = xmlDictQLookup(reader->dict, prefix, name); + if (dictString == NULL) + xmlTextReaderErrMemory(reader); + + return(dictString); +} + +/************************************************************************ + * * + * Our own version of the freeing routines as we recycle nodes * + * * + ************************************************************************/ + /** * xmlTextReaderFreeProp: * @reader: the xmlTextReaderPtr used @@ -246,7 +262,19 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children); - DICT_FREE(cur->name); + if (cur->id != NULL) { + /* + * Operating in streaming mode, attr is gonna disappear + */ + cur->id->attr = NULL; + if (cur->id->name != NULL) + DICT_FREE(cur->id->name); + cur->id->name = cur->name; + cur->name = NULL; + } else { + DICT_FREE(cur->name); + } + if ((reader != NULL) && (reader->ctxt != NULL) && (reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) { cur->next = reader->ctxt->freeAttrs; @@ -501,33 +529,34 @@ xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr 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"); +xmlTextReaderStructuredRelay(void *userData, const xmlError *error) +{ + xmlTextReaderPtr reader = (xmlTextReaderPtr) userData; + + if (reader->sErrorFunc != NULL) { + reader->sErrorFunc(reader->errorFuncArg, error); + } else if (reader->errorFunc != NULL) { + xmlParserSeverities severity; + + if ((error->domain == XML_FROM_VALID) || + (error->domain == XML_FROM_DTD)) { + if (error->level == XML_ERR_WARNING) + severity = XML_PARSER_SEVERITY_VALIDITY_WARNING; + else + severity = XML_PARSER_SEVERITY_VALIDITY_ERROR; + } else { + if (error->level == XML_ERR_WARNING) + severity = XML_PARSER_SEVERITY_WARNING; + else + severity = XML_PARSER_SEVERITY_ERROR; + } + + reader->errorFunc(reader->errorFuncArg, error->message, severity, + reader->ctxt); } } -#endif /** * xmlTextReaderEntPush: @@ -536,30 +565,23 @@ xmlTextReaderDebug(xmlTextReaderPtr reader) { * * Pushes a new entity reference node on top of the entities stack * - * Returns 0 in case of error, the index in the stack otherwise + * Returns -1 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); + size_t newSize = reader->entMax == 0 ? 10 : reader->entMax * 2; + xmlNodePtr *tmp; + + tmp = (xmlNodePtr *) xmlRealloc(reader->entTab, + newSize * sizeof(*tmp)); + if (tmp == NULL) { + xmlTextReaderErrMemory(reader); + return (-1); } + reader->entTab = tmp; + reader->entMax = newSize; } reader->entTab[reader->entNr] = value; reader->ent = value; @@ -605,9 +627,6 @@ xmlTextReaderStartElement(void *ctx, const xmlChar *fullname, 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) && @@ -631,9 +650,6 @@ 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); } @@ -668,9 +684,6 @@ xmlTextReaderStartElementNs(void *ctx, 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, @@ -702,9 +715,6 @@ xmlTextReaderEndElementNs(void *ctx, 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); } @@ -725,9 +735,6 @@ 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); } @@ -747,9 +754,6 @@ 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); } @@ -769,7 +773,6 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { xmlBufPtr inbuf; int val, s; xmlTextReaderState oldstate; - int alloc; if ((reader->input == NULL) || (reader->input->buffer == NULL)) return(-1); @@ -777,7 +780,6 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { oldstate = reader->state; reader->state = XML_TEXTREADER_NONE; inbuf = reader->input->buffer; - alloc = xmlBufGetAllocationScheme(inbuf); while (reader->state == XML_TEXTREADER_NONE) { if (xmlBufUse(inbuf) < reader->cur + CHUNK_SIZE) { @@ -786,22 +788,16 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { */ if (reader->mode != XML_TEXTREADER_MODE_EOF) { val = xmlParserInputBufferRead(reader->input, 4096); - if ((val == 0) && - (alloc == XML_BUFFER_ALLOC_IMMUTABLE)) { + if (val == 0) { if (xmlBufUse(inbuf) == reader->cur) { reader->mode = XML_TEXTREADER_MODE_EOF; - reader->state = oldstate; + break; } } 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; + xmlCtxtErrIO(reader->ctxt, reader->input->error, NULL); + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); } } else @@ -831,12 +827,13 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { break; } } + reader->state = oldstate; /* * Discard the consumed input when needed and possible */ if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) { - if (alloc != XML_BUFFER_ALLOC_IMMUTABLE) { + if (reader->input->readcallback != NULL) { if ((reader->cur >= 4096) && (xmlBufUse(inbuf) - reader->cur <= CHUNK_SIZE)) { val = xmlBufShrink(inbuf, reader->cur); @@ -867,7 +864,6 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { } } } - reader->state = oldstate; if (reader->ctxt->wellFormed == 0) { reader->mode = XML_TEXTREADER_MODE_EOF; return(-1); @@ -883,8 +879,8 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { * * Push the current node for validation */ -static void -xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { +static int +xmlTextReaderValidatePush(xmlTextReaderPtr reader) { xmlNodePtr node = reader->node; #ifdef LIBXML_VALID_ENABLED @@ -894,17 +890,24 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, node->name); } else { - /* TODO use the BuildQName interface */ + xmlChar buf[50]; xmlChar *qname; - qname = xmlStrdup(node->ns->prefix); - qname = xmlStrcat(qname, BAD_CAST ":"); - qname = xmlStrcat(qname, node->name); + qname = xmlBuildQName(node->name, node->ns->prefix, buf, 50); + if (qname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, qname); - if (qname != NULL) - xmlFree(qname); + if (qname != buf) + xmlFree(qname); } + /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + }*/ } #endif /* LIBXML_VALID_ENABLED */ #ifdef LIBXML_SCHEMAS_ENABLED @@ -912,7 +915,7 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { (reader->rngValidCtxt != NULL)) { int ret; - if (reader->rngFullNode != NULL) return; + if (reader->rngFullNode != NULL) return(0); ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt, reader->ctxt->myDoc, node); @@ -934,6 +937,8 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { reader->rngValidErrors++; } #endif + + return(0); } /** @@ -973,7 +978,7 @@ xmlTextReaderValidateCData(xmlTextReaderPtr reader, * * Pop the current node from validation */ -static void +static int xmlTextReaderValidatePop(xmlTextReaderPtr reader) { xmlNodePtr node = reader->node; @@ -984,17 +989,24 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, node->name); } else { - /* TODO use the BuildQName interface */ + xmlChar buf[50]; xmlChar *qname; - qname = xmlStrdup(node->ns->prefix); - qname = xmlStrcat(qname, BAD_CAST ":"); - qname = xmlStrcat(qname, node->name); + qname = xmlBuildQName(node->name, node->ns->prefix, buf, 50); + if (qname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, qname); - if (qname != NULL) - xmlFree(qname); + if (qname != buf) + xmlFree(qname); } + /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + }*/ } #endif /* LIBXML_VALID_ENABLED */ #ifdef LIBXML_SCHEMAS_ENABLED @@ -1005,7 +1017,7 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { if (reader->rngFullNode != NULL) { if (node == reader->rngFullNode) reader->rngFullNode = NULL; - return; + return(0); } ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt, reader->ctxt->myDoc, @@ -1014,6 +1026,8 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { reader->rngValidErrors++; } #endif + + return(0); } /** @@ -1024,7 +1038,7 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { * entity substitution is not activated. As a result the parser interface * must walk through the entity and do the validation calls */ -static void +static int xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { xmlNodePtr oldnode = reader->node; xmlNodePtr node = reader->node; @@ -1034,7 +1048,11 @@ xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { if ((node->children != NULL) && (node->children->type == XML_ENTITY_DECL) && (node->children->children != NULL)) { - xmlTextReaderEntPush(reader, node); + if (xmlTextReaderEntPush(reader, node) < 0) { + if (node == oldnode) + break; + goto skip_children; + } node = node->children->children; continue; } else { @@ -1048,7 +1066,8 @@ xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { #ifdef LIBXML_REGEXP_ENABLED } else if (node->type == XML_ELEMENT_NODE) { reader->node = node; - xmlTextReaderValidatePush(reader); + if (xmlTextReaderValidatePush(reader) < 0) + return(-1); } else if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { xmlTextReaderValidateCData(reader, node->content, @@ -1063,7 +1082,8 @@ xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { node = node->children; continue; } else if (node->type == XML_ELEMENT_NODE) { - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); } skip_children: if (node->next != NULL) { @@ -1084,7 +1104,8 @@ skip_children: } } reader->node = node; - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); } if ((node->type == XML_ENTITY_DECL) && (reader->ent != NULL) && (reader->ent->children == node)) { @@ -1099,6 +1120,8 @@ skip_children: } while ((node != NULL) && (node != oldnode)); } while ((node != NULL) && (node != oldnode)); reader->node = oldnode; + + return(0); } #endif /* LIBXML_REGEXP_ENABLED */ @@ -1141,7 +1164,8 @@ xmlTextReaderDoExpand(xmlTextReaderPtr reader) { if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL)) return(-1); do { - if (reader->ctxt->instate == XML_PARSER_EOF) return(1); + if (PARSER_STOPPED(reader->ctxt)) + return(1); if (xmlTextReaderGetSuccessor(reader->node) != NULL) return(1); @@ -1152,60 +1176,13 @@ xmlTextReaderDoExpand(xmlTextReaderPtr reader) { val = xmlTextReaderPushData(reader); if (val < 0){ reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); } } while(reader->mode != XML_TEXTREADER_MODE_EOF); return(1); } -/** - * xmlTextReaderCollectSiblings: - * @node: the first child - * - * Traverse depth-first through all sibling nodes and their children - * nodes and concatenate their content. This is an auxiliary function - * to xmlTextReaderReadString. - * - * Returns a string containing the content, or NULL in case of error. - */ -static xmlChar * -xmlTextReaderCollectSiblings(xmlNodePtr node) -{ - xmlBufferPtr buffer; - xmlChar *ret; - - if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) - return(NULL); - - buffer = xmlBufferCreate(); - if (buffer == NULL) - return NULL; - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - - for ( ; node != NULL; node = node->next) { - switch (node->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - xmlBufferCat(buffer, node->content); - break; - case XML_ELEMENT_NODE: { - xmlChar *tmp; - - tmp = xmlTextReaderCollectSiblings(node->children); - xmlBufferCat(buffer, tmp); - xmlFree(tmp); - break; - } - default: - break; - } - } - ret = buffer->content; - buffer->content = NULL; - xmlBufferFree(buffer); - return(ret); -} - /** * xmlTextReaderRead: * @reader: the xmlTextReaderPtr used @@ -1222,19 +1199,17 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { xmlTextReaderState oldstate = XML_TEXTREADER_START; xmlNodePtr oldnode = NULL; - if (reader == NULL) return(-1); + if (reader->state == XML_TEXTREADER_ERROR) + return(-1); + reader->curnode = NULL; if (reader->doc != NULL) return(xmlTextReaderReadTree(reader)); if (reader->ctxt == NULL) return(-1); -#ifdef DEBUG_READER - fprintf(stderr, "\nREAD "); - DUMP_READER -#endif if (reader->mode == XML_TEXTREADER_MODE_INITIAL) { reader->mode = XML_TEXTREADER_MODE_INTERACTIVE; /* @@ -1242,11 +1217,11 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { */ do { val = xmlTextReaderPushData(reader); - if (val < 0){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; - return(-1); - } + if (val < 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + } } while ((reader->ctxt->node == NULL) && ((reader->mode != XML_TEXTREADER_MODE_EOF) && (reader->state != XML_TEXTREADER_DONE))); @@ -1254,11 +1229,11 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { if (reader->ctxt->myDoc != NULL) { reader->node = reader->ctxt->myDoc->children; } - if (reader->node == NULL){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; + if (reader->node == NULL) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); - } + } reader->state = XML_TEXTREADER_ELEMENT; } else { if (reader->ctxt->myDoc != NULL) { @@ -1278,10 +1253,13 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { get_next_node: if (reader->node == NULL) { - if (reader->mode == XML_TEXTREADER_MODE_EOF) + if (reader->mode == XML_TEXTREADER_MODE_EOF) { return(0); - else + } else { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); + } } /* @@ -1303,13 +1281,14 @@ get_next_node: ((reader->ctxt->node == NULL) || (reader->ctxt->node == reader->node) || (reader->ctxt->node == reader->node->parent)) && - (reader->ctxt->instate != XML_PARSER_EOF)) { + (reader->ctxt->instate != XML_PARSER_EOF) && + (PARSER_STOPPED(reader->ctxt) == 0)) { val = xmlTextReaderPushData(reader); - if (val < 0){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; + if (val < 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); - } + } if (reader->node == NULL) goto node_end; } @@ -1339,7 +1318,8 @@ get_next_node: #ifdef LIBXML_REGEXP_ENABLED if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE)) - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); #endif /* LIBXML_REGEXP_ENABLED */ if ((reader->preserves > 0) && (reader->node->extra & NODE_IS_SPRESERVED)) @@ -1376,8 +1356,11 @@ get_next_node: goto node_found; } #ifdef LIBXML_REGEXP_ENABLED - if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node->type == XML_ELEMENT_NODE)) - xmlTextReaderValidatePop(reader); + if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && + (reader->node->type == XML_ELEMENT_NODE)) { + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); + } #endif /* LIBXML_REGEXP_ENABLED */ if ((reader->preserves > 0) && (reader->node->extra & NODE_IS_SPRESERVED)) @@ -1389,8 +1372,11 @@ get_next_node: if (reader->mode != XML_TEXTREADER_MODE_EOF) { val = xmlParseChunk(reader->ctxt, "", 0, 1); reader->state = XML_TEXTREADER_DONE; - if (val != 0) + if (val != 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); + } } reader->node = NULL; reader->depth = -1; @@ -1426,8 +1412,6 @@ get_next_node: 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 */ @@ -1444,6 +1428,7 @@ node_found: * Handle XInclude if asked for */ if ((reader->xinclude) && (reader->in_xinclude == 0) && + (reader->state != XML_TEXTREADER_BACKTRACK) && (reader->node != NULL) && (reader->node->type == XML_ELEMENT_NODE) && (reader->node->ns != NULL) && @@ -1451,15 +1436,29 @@ node_found: (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) { if (reader->xincctxt == NULL) { reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc); + if (reader->xincctxt == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } xmlXIncludeSetFlags(reader->xincctxt, reader->parserFlags & (~XML_PARSE_NOXINCNODE)); + xmlXIncludeSetStreamingMode(reader->xincctxt, 1); + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlXIncludeSetErrorHandler(reader->xincctxt, + xmlTextReaderStructuredRelay, reader); } /* * expand that node and process it */ if (xmlTextReaderExpand(reader) == NULL) - return -1; - xmlXIncludeProcessNode(reader->xincctxt, reader->node); + return(-1); + if (xmlXIncludeProcessNode(reader->xincctxt, reader->node) < 0) { + int err = xmlXIncludeGetLastError(reader->xincctxt); + + if (err == XML_ERR_NO_MEMORY) + xmlTextReaderErrMemory(reader); + return(-1); + } } if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) { reader->in_xinclude++; @@ -1479,14 +1478,16 @@ node_found: if ((reader->node->children != NULL) && (reader->node->children->type == XML_ENTITY_DECL) && (reader->node->children->children != NULL)) { - xmlTextReaderEntPush(reader, reader->node); + if (xmlTextReaderEntPush(reader, reader->node) < 0) + goto get_next_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); + if (xmlTextReaderValidateEntity(reader) < 0) + return(-1); #endif /* LIBXML_REGEXP_ENABLED */ } if ((reader->node != NULL) && @@ -1503,7 +1504,8 @@ node_found: if ((node->type == XML_ELEMENT_NODE) && ((reader->state != XML_TEXTREADER_END) && (reader->state != XML_TEXTREADER_BACKTRACK))) { - xmlTextReaderValidatePush(reader); + if (xmlTextReaderValidatePush(reader) < 0) + return(-1); } else if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { xmlTextReaderValidateCData(reader, node->content, @@ -1609,6 +1611,37 @@ xmlTextReaderNext(xmlTextReaderPtr reader) { } #ifdef LIBXML_WRITER_ENABLED +static void +xmlTextReaderDumpCopy(xmlTextReaderPtr reader, xmlOutputBufferPtr output, + xmlNodePtr node) { + if ((node->type == XML_DTD_NODE) || + (node->type == XML_ELEMENT_DECL) || + (node->type == XML_ATTRIBUTE_DECL) || + (node->type == XML_ENTITY_DECL)) + return; + + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + xmlNodeDumpOutput(output, node->doc, node, 0, 0, NULL); + } else { + xmlNodePtr copy; + + /* + * Create a copy to make sure that namespace declarations from + * ancestors are added. + */ + copy = xmlDocCopyNode(node, node->doc, 1); + if (copy == NULL) { + xmlTextReaderErrMemory(reader); + return; + } + + xmlNodeDumpOutput(output, copy->doc, copy, 0, 0, NULL); + + xmlFreeNode(copy); + } +} + /** * xmlTextReaderReadInnerXml: * @reader: the xmlTextReaderPtr used @@ -1620,47 +1653,36 @@ xmlTextReaderNext(xmlTextReaderPtr reader) { * string must be deallocated by the caller. */ xmlChar * -xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) { - xmlChar *resbuf; - xmlNodePtr node, cur_node; - xmlBufferPtr buff, buff2; - xmlDocPtr doc; + xmlOutputBufferPtr output; + xmlNodePtr cur; + xmlChar *ret; - if (xmlTextReaderExpand(reader) == NULL) { - return NULL; - } - doc = reader->node->doc; - buff = xmlBufferCreate(); - if (buff == NULL) - return NULL; - xmlBufferSetAllocationScheme(buff, XML_BUFFER_ALLOC_DOUBLEIT); - for (cur_node = reader->node->children; cur_node != NULL; - cur_node = cur_node->next) { - /* XXX: Why is the node copied? */ - node = xmlDocCopyNode(cur_node, doc, 1); - /* XXX: Why do we need a second buffer? */ - buff2 = xmlBufferCreate(); - xmlBufferSetAllocationScheme(buff2, XML_BUFFER_ALLOC_DOUBLEIT); - if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) { - xmlFreeNode(node); - xmlBufferFree(buff2); - xmlBufferFree(buff); - return NULL; - } - xmlBufferCat(buff, buff2->content); - xmlFreeNode(node); - xmlBufferFree(buff2); + if (xmlTextReaderExpand(reader) == NULL) + return(NULL); + + if (reader->node == NULL) + return(NULL); + + output = xmlAllocOutputBuffer(NULL); + if (output == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); } - resbuf = buff->content; - buff->content = NULL; - xmlBufferFree(buff); - return resbuf; + for (cur = reader->node->children; cur != NULL; cur = cur->next) + xmlTextReaderDumpCopy(reader, output, cur); + + if (output->error) + xmlCtxtErrIO(reader->ctxt, output->error, NULL); + + ret = xmlBufDetach(output->buffer); + xmlOutputBufferClose(output); + + return(ret); } -#endif -#ifdef LIBXML_WRITER_ENABLED /** * xmlTextReaderReadOuterXml: * @reader: the xmlTextReaderPtr used @@ -1672,38 +1694,33 @@ xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) * by the caller. */ xmlChar * -xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) { - xmlChar *resbuf; + xmlOutputBufferPtr output; xmlNodePtr node; - xmlBufferPtr buff; - xmlDocPtr doc; + xmlChar *ret; + + if (xmlTextReaderExpand(reader) == NULL) + return(NULL); - if (xmlTextReaderExpand(reader) == NULL) { - return NULL; - } node = reader->node; - doc = node->doc; - /* XXX: Why is the node copied? */ - if (node->type == XML_DTD_NODE) { - node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node); - } else { - node = xmlDocCopyNode(node, doc, 1); - } - buff = xmlBufferCreate(); - xmlBufferSetAllocationScheme(buff, XML_BUFFER_ALLOC_DOUBLEIT); - if (xmlNodeDump(buff, doc, node, 0, 0) == -1) { - xmlFreeNode(node); - xmlBufferFree(buff); - return NULL; + if (node == NULL) + return(NULL); + + output = xmlAllocOutputBuffer(NULL); + if (output == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); } - resbuf = buff->content; - buff->content = NULL; + xmlTextReaderDumpCopy(reader, output, node); + if (output->error) + xmlCtxtErrIO(reader->ctxt, output->error, NULL); - xmlFreeNode(node); - xmlBufferFree(buff); - return resbuf; + ret = xmlBufDetach(output->buffer); + xmlOutputBufferClose(output); + + return(ret); } #endif @@ -1720,29 +1737,73 @@ xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) xmlChar * xmlTextReaderReadString(xmlTextReaderPtr reader) { - xmlNodePtr node; + xmlNodePtr node, cur; + xmlBufPtr buf; + xmlChar *ret; if ((reader == NULL) || (reader->node == NULL)) return(NULL); node = (reader->curnode != NULL) ? reader->curnode : reader->node; switch (node->type) { - case XML_TEXT_NODE: - if (node->content != NULL) - return(xmlStrdup(node->content)); - break; - case XML_ELEMENT_NODE: - if (xmlTextReaderDoExpand(reader) != -1) { - return xmlTextReaderCollectSiblings(node->children); - } - break; - case XML_ATTRIBUTE_NODE: - TODO - break; - default: - break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + break; + case XML_ELEMENT_NODE: + if (xmlTextReaderDoExpand(reader) == -1) + return(NULL); + break; + case XML_ATTRIBUTE_NODE: + /* TODO */ + break; + default: + break; } - return(NULL); + + buf = xmlBufCreateSize(30); + if (buf == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); + } + xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + + cur = node; + while (cur != NULL) { + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + xmlBufCat(buf, cur->content); + break; + + case XML_ELEMENT_NODE: + if (cur->children != NULL) { + cur = cur->children; + continue; + } + break; + + default: + break; + } + + if (cur == node) + goto done; + + while (cur->next == NULL) { + cur = cur->parent; + if (cur == node) + goto done; + } + cur = cur->next; + } + +done: + ret = xmlBufDetach(buf); + if (ret == NULL) + xmlTextReaderErrMemory(reader); + + xmlBufFree(buf); + return(ret); } #if 0 @@ -1772,7 +1833,6 @@ xmlTextReaderReadBase64(xmlTextReaderPtr reader, if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) return(0); - TODO return(0); } @@ -1802,7 +1862,6 @@ xmlTextReaderReadBinHex(xmlTextReaderPtr reader, if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) return(0); - TODO return(0); } #endif @@ -2002,11 +2061,8 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { if (input == NULL) return(NULL); ret = xmlMalloc(sizeof(xmlTextReader)); - if (ret == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlTextReader)); ret->doc = NULL; ret->entTab = NULL; @@ -2016,8 +2072,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { ret->buffer = xmlBufCreateSize(100); if (ret->buffer == NULL) { xmlFree(ret); - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } /* no operation on a reader should require a huge buffer */ @@ -2027,8 +2081,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { if (ret->sax == NULL) { xmlBufFree(ret->buffer); xmlFree(ret); - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } xmlSAXVersion(ret->sax, 2); @@ -2074,8 +2126,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { } if (ret->ctxt == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); xmlBufFree(ret->buffer); xmlFree(ret->sax); xmlFree(ret); @@ -2089,7 +2139,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { /* * use the parser dictionary to allocate all elements and attributes names */ - ret->ctxt->docdict = 1; ret->dict = ret->ctxt->dict; #ifdef LIBXML_XINCLUDE_ENABLED ret->xinclude = 0; @@ -2113,7 +2162,6 @@ xmlTextReaderPtr xmlNewTextReaderFilename(const char *URI) { xmlParserInputBufferPtr input; xmlTextReaderPtr ret; - char *directory = NULL; input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE); if (input == NULL) @@ -2124,12 +2172,6 @@ xmlNewTextReaderFilename(const char *URI) { return(NULL); } ret->allocs |= XML_TEXTREADER_INPUT; - if (ret->ctxt->directory == NULL) - directory = xmlParserGetDirectory(URI); - if ((ret->ctxt->directory == NULL) && (directory != NULL)) - ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); - if (directory != NULL) - xmlFree(directory); return(ret); } @@ -2205,6 +2247,7 @@ xmlFreeTextReader(xmlTextReaderPtr reader) { * Methods for XmlTextReader * * * ************************************************************************/ + /** * xmlTextReaderClose: * @reader: the xmlTextReaderPtr used @@ -2285,7 +2328,7 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { ns = ns->next; } if (ns != NULL) - return(xmlStrdup(ns->href)); + return(readerStrdup(reader, ns->href)); cur = reader->node->properties; if (cur == NULL) @@ -2297,8 +2340,11 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { } /* TODO walk the DTD if present */ + if (cur->children == NULL) + return(NULL); ret = xmlNodeListGetString(reader->node->doc, cur->children, 1); - if (ret == NULL) return(xmlStrdup((xmlChar *)"")); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); } @@ -2315,9 +2361,10 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { xmlChar * xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar *prefix = NULL; - xmlChar *localname; + const xmlChar *localname; xmlNsPtr ns; xmlChar *ret = NULL; + int result; if ((reader == NULL) || (name == NULL)) return(NULL); @@ -2330,43 +2377,56 @@ xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { if (reader->node->type != XML_ELEMENT_NODE) return(NULL); - localname = xmlSplitQName2(name, &prefix); + localname = xmlSplitQName4(name, &prefix); if (localname == NULL) { - /* - * Namespace default decl - */ - if (xmlStrEqual(name, BAD_CAST "xmlns")) { - ns = reader->node->nsDef; - while (ns != NULL) { - if (ns->prefix == NULL) { - return(xmlStrdup(ns->href)); - } - ns = ns->next; - } - return NULL; - } - return(xmlGetNoNsProp(reader->node, name)); - } + xmlTextReaderErrMemory(reader); + return(NULL); + } + if (prefix == NULL) { + /* + * Namespace default decl + */ + if (xmlStrEqual(name, BAD_CAST "xmlns")) { + ns = reader->node->nsDef; + while (ns != NULL) { + if (ns->prefix == NULL) { + return(readerStrdup(reader, ns->href)); + } + ns = ns->next; + } + return NULL; + } + + result = xmlNodeGetAttrValue(reader->node, name, NULL, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + return(ret); + } /* * Namespace default decl */ if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { - ns = reader->node->nsDef; - while (ns != NULL) { - if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { - ret = xmlStrdup(ns->href); - break; - } - ns = ns->next; - } + ns = reader->node->nsDef; + while (ns != NULL) { + if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { + ret = readerStrdup(reader, ns->href); + break; + } + ns = ns->next; + } } else { - ns = xmlSearchNs(reader->node->doc, reader->node, prefix); - if (ns != NULL) - ret = xmlGetNsProp(reader->node, localname, ns->href); - } + result = xmlSearchNsSafe(reader->node, prefix, &ns); + if (result < 0) + xmlTextReaderErrMemory(reader); + if (ns != NULL) { + result = xmlNodeGetAttrValue(reader->node, localname, ns->href, + &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + } + } - xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(ret); @@ -2387,8 +2447,10 @@ xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar * xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, const xmlChar *namespaceURI) { + xmlChar *ret = NULL; xmlChar *prefix = NULL; xmlNsPtr ns; + int result; if ((reader == NULL) || (localName == NULL)) return(NULL); @@ -2402,21 +2464,25 @@ xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, return(NULL); if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) { - if (! xmlStrEqual(localName, BAD_CAST "xmlns")) { - prefix = BAD_CAST localName; - } - ns = reader->node->nsDef; - while (ns != NULL) { - if ((prefix == NULL && ns->prefix == NULL) || - ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) { - return xmlStrdup(ns->href); - } - ns = ns->next; - } - return NULL; + if (! xmlStrEqual(localName, BAD_CAST "xmlns")) { + prefix = BAD_CAST localName; + } + ns = reader->node->nsDef; + while (ns != NULL) { + if ((prefix == NULL && ns->prefix == NULL) || + ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) { + return readerStrdup(reader, ns->href); + } + ns = ns->next; + } + return NULL; } - return(xmlGetNsProp(reader->node, localName, namespaceURI)); + result = xmlNodeGetAttrValue(reader->node, localName, namespaceURI, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + + return(ret); } /** @@ -2465,7 +2531,6 @@ xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { * - by the layer which allocated it. * - by the layer to which would have been returned to. */ - TODO return(NULL); } return(ret); @@ -2485,16 +2550,21 @@ xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { xmlChar * xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) { xmlNsPtr ns; + int result; if (reader == NULL) return(NULL); if (reader->node == NULL) return(NULL); - ns = xmlSearchNs(reader->node->doc, reader->node, prefix); + result = xmlSearchNsSafe(reader->node, prefix, &ns); + if (result < 0) { + xmlTextReaderErrMemory(reader); + return(NULL); + } if (ns == NULL) return(NULL); - return(xmlStrdup(ns->href)); + return(readerStrdup(reader, ns->href)); } /** @@ -2560,7 +2630,7 @@ xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) { int xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar *prefix = NULL; - xmlChar *localname; + const xmlChar *localname; xmlNsPtr ns; xmlAttrPtr prop; @@ -2573,8 +2643,12 @@ xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { if (reader->node->type != XML_ELEMENT_NODE) return(0); - localname = xmlSplitQName2(name, &prefix); + localname = xmlSplitQName4(name, &prefix); if (localname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } + if (prefix == NULL) { /* * Namespace default decl */ @@ -2636,15 +2710,11 @@ xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { prop = prop->next; } not_found: - if (localname != NULL) - xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(0); found: - if (localname != NULL) - xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(1); @@ -2831,12 +2901,24 @@ xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { if (reader->faketext == NULL) { reader->faketext = xmlNewDocText(reader->node->doc, ns->href); + if (reader->faketext == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } } else { if ((reader->faketext->content != NULL) && (reader->faketext->content != (xmlChar *) &(reader->faketext->properties))) xmlFree(reader->faketext->content); - reader->faketext->content = xmlStrdup(ns->href); + if (ns->href == NULL) { + reader->faketext->content = NULL; + } else { + reader->faketext->content = xmlStrdup(ns->href); + if (reader->faketext->content == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } + } } reader->curnode = reader->faketext; } else { @@ -2858,20 +2940,17 @@ xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { */ const xmlChar * xmlTextReaderConstEncoding(xmlTextReaderPtr reader) { - xmlDocPtr doc = NULL; + const xmlChar *encoding = 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); + return(NULL); - if (doc->encoding == NULL) - return(NULL); - else - return(CONSTSTR(doc->encoding)); + if (reader->ctxt != NULL) + encoding = xmlGetActualEncoding(reader->ctxt); + else if (reader->doc != NULL) + encoding = reader->doc->encoding; + + return(constString(reader, encoding)); } @@ -3045,14 +3124,14 @@ xmlTextReaderLocalName(xmlTextReaderPtr reader) { if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) - return(xmlStrdup(BAD_CAST "xmlns")); + return(readerStrdup(reader, BAD_CAST "xmlns")); else - return(xmlStrdup(ns->prefix)); + return(readerStrdup(reader, ns->prefix)); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(xmlTextReaderName(reader)); - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); } /** @@ -3076,7 +3155,7 @@ xmlTextReaderConstLocalName(xmlTextReaderPtr reader) { if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) - return(CONSTSTR(BAD_CAST "xmlns")); + return(constString(reader, BAD_CAST "xmlns")); else return(ns->prefix); } @@ -3111,41 +3190,41 @@ xmlTextReaderName(xmlTextReaderPtr reader) { case XML_ATTRIBUTE_NODE: if ((node->ns == NULL) || (node->ns->prefix == NULL)) - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); - ret = xmlStrdup(node->ns->prefix); - ret = xmlStrcat(ret, BAD_CAST ":"); - ret = xmlStrcat(ret, node->name); + ret = xmlBuildQName(node->name, node->ns->prefix, NULL, 0); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); case XML_TEXT_NODE: - return(xmlStrdup(BAD_CAST "#text")); + return(readerStrdup(reader, BAD_CAST "#text")); case XML_CDATA_SECTION_NODE: - return(xmlStrdup(BAD_CAST "#cdata-section")); + return(readerStrdup(reader, BAD_CAST "#cdata-section")); case XML_ENTITY_NODE: case XML_ENTITY_REF_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_PI_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_COMMENT_NODE: - return(xmlStrdup(BAD_CAST "#comment")); + return(readerStrdup(reader, BAD_CAST "#comment")); case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: - return(xmlStrdup(BAD_CAST "#document")); + return(readerStrdup(reader, BAD_CAST "#document")); case XML_DOCUMENT_FRAG_NODE: - return(xmlStrdup(BAD_CAST "#document-fragment")); + return(readerStrdup(reader, BAD_CAST "#document-fragment")); case XML_NOTATION_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_NAMESPACE_DECL: { xmlNsPtr ns = (xmlNsPtr) node; - ret = xmlStrdup(BAD_CAST "xmlns"); if (ns->prefix == NULL) - return(ret); - ret = xmlStrcat(ret, BAD_CAST ":"); - ret = xmlStrcat(ret, ns->prefix); + return(readerStrdup(reader, BAD_CAST "xmlns")); + ret = xmlBuildQName(ns->prefix, BAD_CAST "xmlns", NULL, 0); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); } @@ -3184,34 +3263,34 @@ xmlTextReaderConstName(xmlTextReaderPtr reader) { if ((node->ns == NULL) || (node->ns->prefix == NULL)) return(node->name); - return(CONSTQSTR(node->ns->prefix, node->name)); + return(constQString(reader, node->ns->prefix, node->name)); case XML_TEXT_NODE: - return(CONSTSTR(BAD_CAST "#text")); + return(constString(reader, BAD_CAST "#text")); case XML_CDATA_SECTION_NODE: - return(CONSTSTR(BAD_CAST "#cdata-section")); + return(constString(reader, BAD_CAST "#cdata-section")); case XML_ENTITY_NODE: case XML_ENTITY_REF_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_PI_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_COMMENT_NODE: - return(CONSTSTR(BAD_CAST "#comment")); + return(constString(reader, BAD_CAST "#comment")); case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: - return(CONSTSTR(BAD_CAST "#document")); + return(constString(reader, BAD_CAST "#document")); case XML_DOCUMENT_FRAG_NODE: - return(CONSTSTR(BAD_CAST "#document-fragment")); + return(constString(reader, BAD_CAST "#document-fragment")); case XML_NOTATION_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_NAMESPACE_DECL: { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) - return(CONSTSTR(BAD_CAST "xmlns")); - return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix)); + return(constString(reader, BAD_CAST "xmlns")); + return(constQString(reader, BAD_CAST "xmlns", ns->prefix)); } case XML_ELEMENT_DECL: @@ -3246,13 +3325,13 @@ xmlTextReaderPrefix(xmlTextReaderPtr reader) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) return(NULL); - return(xmlStrdup(BAD_CAST "xmlns")); + return(readerStrdup(reader, BAD_CAST "xmlns")); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if ((node->ns != NULL) && (node->ns->prefix != NULL)) - return(xmlStrdup(node->ns->prefix)); + return(readerStrdup(reader, node->ns->prefix)); return(NULL); } @@ -3278,13 +3357,13 @@ xmlTextReaderConstPrefix(xmlTextReaderPtr reader) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) return(NULL); - return(CONSTSTR(BAD_CAST "xmlns")); + return(constString(reader, BAD_CAST "xmlns")); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if ((node->ns != NULL) && (node->ns->prefix != NULL)) - return(CONSTSTR(node->ns->prefix)); + return(constString(reader, node->ns->prefix)); return(NULL); } @@ -3307,12 +3386,12 @@ xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { else node = reader->node; if (node->type == XML_NAMESPACE_DECL) - return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/")); + return(readerStrdup(reader, BAD_CAST "http://www.w3.org/2000/xmlns/")); if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if (node->ns != NULL) - return(xmlStrdup(node->ns->href)); + return(readerStrdup(reader, node->ns->href)); return(NULL); } @@ -3335,12 +3414,12 @@ xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { else node = reader->node; if (node->type == XML_NAMESPACE_DECL) - return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/")); + return(constString(reader, BAD_CAST "http://www.w3.org/2000/xmlns/")); if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if (node->ns != NULL) - return(CONSTSTR(node->ns->href)); + return(constString(reader, node->ns->href)); return(NULL); } @@ -3355,9 +3434,16 @@ xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { */ xmlChar * xmlTextReaderBaseUri(xmlTextReaderPtr reader) { + xmlChar *ret = NULL; + int result; + if ((reader == NULL) || (reader->node == NULL)) return(NULL); - return(xmlNodeGetBase(NULL, reader->node)); + result = xmlNodeGetBaseSafe(NULL, reader->node, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + + return(ret); } /** @@ -3373,13 +3459,16 @@ const xmlChar * xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) { xmlChar *tmp; const xmlChar *ret; + int result; if ((reader == NULL) || (reader->node == NULL)) return(NULL); - tmp = xmlNodeGetBase(NULL, reader->node); + result = xmlNodeGetBaseSafe(NULL, reader->node, &tmp); + if (result < 0) + xmlTextReaderErrMemory(reader); if (tmp == NULL) return(NULL); - ret = CONSTSTR(tmp); + ret = constString(reader, tmp); xmlFree(tmp); return(ret); } @@ -3492,23 +3581,26 @@ xmlTextReaderValue(xmlTextReaderPtr reader) { switch (node->type) { case XML_NAMESPACE_DECL: - return(xmlStrdup(((xmlNsPtr) node)->href)); + return(readerStrdup(reader, ((xmlNsPtr) node)->href)); case XML_ATTRIBUTE_NODE:{ xmlAttrPtr attr = (xmlAttrPtr) node; + xmlDocPtr doc = NULL; + xmlChar *ret; + if (attr->children == NULL) + return(NULL); if (attr->parent != NULL) - return (xmlNodeListGetString - (attr->parent->doc, attr->children, 1)); - else - return (xmlNodeListGetString(NULL, attr->children, 1)); - break; + doc = attr->parent->doc; + ret = xmlNodeListGetString(doc, attr->children, 1); + if (ret == NULL) + xmlTextReaderErrMemory(reader); + return(ret); } case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: - if (node->content != NULL) - return (xmlStrdup(node->content)); + return(readerStrdup(reader, node->content)); default: break; } @@ -3550,11 +3642,8 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { else { if (reader->buffer == NULL) { reader->buffer = xmlBufCreateSize(100); - if (reader->buffer == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); + if (reader->buffer == NULL) return (NULL); - } xmlBufSetAllocationScheme(reader->buffer, XML_BUFFER_ALLOC_DOUBLEIT); } else @@ -3562,12 +3651,12 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { xmlBufGetNodeContent(reader->buffer, node); ret = xmlBufContent(reader->buffer); if (ret == NULL) { + xmlTextReaderErrMemory(reader); /* error on the buffer best to reallocate */ xmlBufFree(reader->buffer); reader->buffer = xmlBufCreateSize(100); xmlBufSetAllocationScheme(reader->buffer, XML_BUFFER_ALLOC_DOUBLEIT); - ret = BAD_CAST ""; } return(ret); } @@ -3613,7 +3702,7 @@ xmlTextReaderQuoteChar(xmlTextReaderPtr reader) { if (reader == NULL) return(-1); /* TODO maybe lookup the attribute value for " first */ - return((int) '"'); + return('"'); } /** @@ -3654,7 +3743,7 @@ xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) { tmp = xmlNodeGetLang(reader->node); if (tmp == NULL) return(NULL); - ret = CONSTSTR(tmp); + ret = constString(reader, tmp); xmlFree(tmp); return(ret); } @@ -3674,7 +3763,7 @@ const xmlChar * xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) { if (reader == NULL) return(NULL); - return(CONSTSTR(str)); + return(constString(reader, str)); } /** @@ -3729,18 +3818,21 @@ xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) { if (ctxt->loadsubset == 0) { if (reader->mode != XML_TEXTREADER_MODE_INITIAL) return(-1); - ctxt->loadsubset = XML_DETECT_IDS; + ctxt->options |= XML_PARSE_DTDLOAD; + ctxt->loadsubset |= XML_DETECT_IDS; } } else { - ctxt->loadsubset = 0; + ctxt->options &= ~XML_PARSE_DTDLOAD; + ctxt->loadsubset &= ~XML_DETECT_IDS; } return(0); case XML_PARSER_DEFAULTATTRS: if (value != 0) { + ctxt->options |= XML_PARSE_DTDATTR; ctxt->loadsubset |= XML_COMPLETE_ATTRS; } else { - if (ctxt->loadsubset & XML_COMPLETE_ATTRS) - ctxt->loadsubset -= XML_COMPLETE_ATTRS; + ctxt->options &= ~XML_PARSE_DTDATTR; + ctxt->loadsubset &= ~XML_COMPLETE_ATTRS; } return(0); case XML_PARSER_VALIDATE: @@ -3875,10 +3967,7 @@ xmlTextReaderPreserve(xmlTextReaderPtr reader) { if (reader == NULL) return(NULL); - if (reader->curnode != NULL) - cur = reader->curnode; - else - cur = reader->node; + cur = reader->node; if (cur == NULL) return(NULL); @@ -3928,7 +4017,7 @@ xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax * sizeof(reader->patternTab[0])); if (reader->patternTab == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); + xmlTextReaderErrMemory(reader); return (-1); } } @@ -3939,7 +4028,7 @@ xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, reader->patternMax * sizeof(reader->patternTab[0])); if (tmp == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + xmlTextReaderErrMemory(reader); reader->patternMax /= 2; return (-1); } @@ -3976,80 +4065,6 @@ xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { } #ifdef LIBXML_SCHEMAS_ENABLED -static char *xmlTextReaderBuildMessage(const char *msg, va_list ap) LIBXML_ATTR_FORMAT(1,0); - -static void XMLCDECL -xmlTextReaderValidityError(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void XMLCDECL -xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void XMLCDECL -xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void XMLCDECL -xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -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 @@ -4096,17 +4111,9 @@ xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) { reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema); if (reader->rngValidCtxt == NULL) return(-1); - if (reader->errorFunc != NULL) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->rngValidErrors = 0; reader->rngFullNode = NULL; reader->validate = XML_TEXTREADER_VALIDATE_RNG; @@ -4238,17 +4245,9 @@ xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) { xmlTextReaderLocator, (void *) reader); - if (reader->errorFunc != NULL) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->xsdValidErrors = 0; reader->validate = XML_TEXTREADER_VALIDATE_XSD; return(0); @@ -4308,21 +4307,14 @@ xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader, /* Parse the schema and create validation environment. */ pctxt = xmlRelaxNGNewParserCtxt(rng); - if (reader->errorFunc != NULL) { - xmlRelaxNGSetParserErrors(pctxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetParserStructuredErrors(pctxt, + xmlTextReaderStructuredRelay, reader); reader->rngSchemas = xmlRelaxNGParse(pctxt); xmlRelaxNGFreeParserCtxt(pctxt); if (reader->rngSchemas == NULL) return(-1); + reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas); if (reader->rngValidCtxt == NULL) { xmlRelaxNGFree(reader->rngSchemas); @@ -4340,17 +4332,9 @@ xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader, * TODO: In case the user provides the validation context we * could make this redirection optional. */ - if (reader->errorFunc != NULL) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->rngValidErrors = 0; reader->rngFullNode = NULL; reader->validate = XML_TEXTREADER_VALIDATE_RNG; @@ -4413,12 +4397,9 @@ xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader, xmlSchemaParserCtxtPtr pctxt; /* Parse the schema and create validation environment. */ pctxt = xmlSchemaNewParserCtxt(xsd); - if (reader->errorFunc != NULL) { - xmlSchemaSetParserErrors(pctxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetParserStructuredErrors(pctxt, + xmlTextReaderStructuredRelay, reader); reader->xsdSchemas = xmlSchemaParse(pctxt); xmlSchemaFreeParserCtxt(pctxt); if (reader->xsdSchemas == NULL) @@ -4461,17 +4442,9 @@ xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader, * TODO: In case the user provides the validation context we * could make this redirection optional. */ - if (reader->errorFunc != NULL) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->xsdValidErrors = 0; reader->validate = XML_TEXTREADER_VALIDATE_XSD; return(0); @@ -4610,7 +4583,7 @@ xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) { if (doc->version == NULL) return(NULL); else - return(CONSTSTR(doc->version)); + return(constString(reader, doc->version)); } /** @@ -4644,43 +4617,6 @@ xmlTextReaderStandalone(xmlTextReaderPtr reader) { * * ************************************************************************/ -/* helper to build a xmlMalloc'ed string from a format and va_list */ -static char * -xmlTextReaderBuildMessage(const char *msg, va_list ap) { - int size = 0; - int chars; - char *larger; - char *str = NULL; - va_list aq; - - while (1) { - VA_COPY(aq, ap); - chars = vsnprintf(str, size, msg, aq); - va_end(aq); - if (chars < 0) { - xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n"); - if (str) - xmlFree(str); - return NULL; - } - if ((chars < size) || (size == MAX_ERR_MSG_SIZE)) - break; - if (chars < MAX_ERR_MSG_SIZE) - size = chars + 1; - else - size = MAX_ERR_MSG_SIZE; - if ((larger = (char *) xmlRealloc(str, size)) == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); - if (str) - xmlFree(str); - return NULL; - } - str = larger; - } - - return str; -} - /** * xmlTextReaderLocatorLineNumber: * @locator: the xmlTextReaderLocatorPtr used @@ -4754,105 +4690,14 @@ xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) { return ret; } -static void -xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity, - char *str) -{ - xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt; - - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private; - - if (str != NULL) { - if (reader->errorFunc) - reader->errorFunc(reader->errorFuncArg, str, severity, - (xmlTextReaderLocatorPtr) ctx); - xmlFree(str); - } -} - -static void -xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error) -{ - xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt; - - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private; - - if (error && reader->sErrorFunc) { - reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error); - } -} - -static void XMLCDECL LIBXML_ATTR_FORMAT(2,3) -xmlTextReaderError(void *ctxt, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_ERROR, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); - -} - -static void XMLCDECL LIBXML_ATTR_FORMAT(2,3) -xmlTextReaderWarning(void *ctxt, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_WARNING, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); -} - -static void 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 * + * DEPRECATED: Use xmlTextReaderSetStructuredErrorHandler. + * * Register a callback function that will be called on error and warnings. * * If @f is NULL, the default error and warning handlers are restored. @@ -4862,53 +4707,35 @@ xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, xmlTextReaderErrorFunc f, void *arg) { if (f != NULL) { - reader->ctxt->sax->error = xmlTextReaderError; - reader->ctxt->sax->serror = NULL; - reader->ctxt->vctxt.error = xmlTextReaderValidityError; - reader->ctxt->sax->warning = xmlTextReaderWarning; - reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; reader->errorFunc = f; reader->sErrorFunc = NULL; reader->errorFuncArg = arg; + xmlCtxtSetErrorHandler(reader->ctxt, + xmlTextReaderStructuredRelay, reader); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); } #endif } else { /* restore defaults */ - reader->ctxt->sax->error = xmlParserError; - reader->ctxt->vctxt.error = xmlParserValidityError; - reader->ctxt->sax->warning = xmlParserWarning; - reader->ctxt->vctxt.warning = xmlParserValidityWarning; reader->errorFunc = NULL; reader->sErrorFunc = NULL; reader->errorFuncArg = NULL; + xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + NULL); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + NULL); } #endif } @@ -4929,52 +4756,35 @@ xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, xmlStructuredErrorFunc f, void *arg) { if (f != NULL) { - reader->ctxt->sax->error = NULL; - reader->ctxt->sax->serror = xmlTextReaderStructuredError; - reader->ctxt->vctxt.error = xmlTextReaderValidityError; - reader->ctxt->sax->warning = xmlTextReaderWarning; - reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; reader->sErrorFunc = f; reader->errorFunc = NULL; reader->errorFuncArg = arg; + xmlCtxtSetErrorHandler(reader->ctxt, + xmlTextReaderStructuredRelay, reader); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); + xmlTextReaderStructuredRelay, reader); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); + xmlTextReaderStructuredRelay, reader); } #endif } else { /* restore defaults */ - reader->ctxt->sax->error = xmlParserError; - reader->ctxt->sax->serror = NULL; - reader->ctxt->vctxt.error = xmlParserValidityError; - reader->ctxt->sax->warning = xmlParserWarning; - reader->ctxt->vctxt.warning = xmlParserValidityWarning; reader->errorFunc = NULL; reader->sErrorFunc = NULL; reader->errorFuncArg = NULL; + xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + NULL); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + NULL); } #endif } @@ -5074,8 +4884,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (reader->buffer == NULL) reader->buffer = xmlBufCreateSize(100); if (reader->buffer == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); return (-1); } /* no operation on a reader should require a huge buffer */ @@ -5084,8 +4892,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (reader->sax == NULL) reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); if (reader->sax == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); return (-1); } xmlSAXVersion(reader->sax, 2); @@ -5132,13 +4938,15 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, reader->base = 0; reader->cur = 0; } + if (reader->ctxt == NULL) { + return (-1); + } } else { xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf; - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; xmlCtxtReset(reader->ctxt); - buf = xmlAllocParserInputBuffer(enc); + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (buf == NULL) return(-1); inputStream = xmlNewInputStream(reader->ctxt); if (inputStream == NULL) { @@ -5157,11 +4965,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, inputPush(reader->ctxt, inputStream); reader->cur = 0; } - if (reader->ctxt == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); - return (-1); - } } if (reader->dict != NULL) { if (reader->ctxt->dict != NULL) { @@ -5183,7 +4986,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, /* * use the parser dictionary to allocate all elements and attributes names */ - reader->ctxt->docdict = 1; reader->ctxt->parseMode = XML_PARSE_READER; #ifdef LIBXML_XINCLUDE_ENABLED @@ -5194,6 +4996,8 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (options & XML_PARSE_XINCLUDE) { reader->xinclude = 1; reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1); + if (reader->xinclude_name == NULL) + return(-1); options -= XML_PARSE_XINCLUDE; } else reader->xinclude = 0; @@ -5217,23 +5021,50 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, reader->validate = XML_TEXTREADER_VALIDATE_DTD; xmlCtxtUseOptions(reader->ctxt, options); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) - xmlSwitchToEncoding(reader->ctxt, hdlr); - } + if (encoding != NULL) + xmlSwitchEncodingName(reader->ctxt, encoding); if ((URL != NULL) && (reader->ctxt->input != NULL) && - (reader->ctxt->input->filename == NULL)) + (reader->ctxt->input->filename == NULL)) { reader->ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + if (reader->ctxt->input->filename == NULL) + return(-1); + } reader->doc = NULL; return (0); } +/** + * xmlTextReaderSetMaxAmplification: + * @reader: an XML reader + * @maxAmpl: maximum amplification factor + * + * Set the maximum amplification factor. See xmlCtxtSetMaxAmplification. + */ +void +xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, unsigned maxAmpl) +{ + xmlCtxtSetMaxAmplification(reader->ctxt, maxAmpl); +} + +/** + * xmlTextReaderGetLastError: + * @reader: an XML reader + * + * Available since 2.13.0. + * + * Returns the last error. + */ +const xmlError * +xmlTextReaderGetLastError(xmlTextReaderPtr reader) +{ + if (reader == NULL) + return(NULL); + return(&reader->ctxt->lastError); +} + /** * xmlTextReaderByteConsumed: * @reader: an XML reader @@ -5273,8 +5104,6 @@ xmlReaderWalker(xmlDocPtr doc) ret = xmlMalloc(sizeof(xmlTextReader)); if (ret == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } memset(ret, 0, sizeof(xmlTextReader)); @@ -5337,7 +5166,10 @@ xmlReaderForFile(const char *filename, const char *encoding, int options) reader = xmlNewTextReaderFilename(filename); if (reader == NULL) return (NULL); - xmlTextReaderSetup(reader, NULL, NULL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, NULL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); } @@ -5361,8 +5193,7 @@ xmlReaderForMemory(const char *buffer, int size, const char *URL, xmlTextReaderPtr reader; xmlParserInputBufferPtr buf; - buf = xmlParserInputBufferCreateStatic(buffer, size, - XML_CHAR_ENCODING_NONE); + buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); if (buf == NULL) { return (NULL); } @@ -5372,7 +5203,10 @@ xmlReaderForMemory(const char *buffer, int size, const char *URL, return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); } @@ -5409,7 +5243,10 @@ xmlReaderForFd(int fd, const char *URL, const char *encoding, int options) return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); } @@ -5451,7 +5288,10 @@ xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); } @@ -5588,7 +5428,7 @@ xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size, if (buffer == NULL) return (-1); - input = xmlParserInputBufferCreateStatic(buffer, size, + input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); if (input == NULL) { return (-1); diff --git a/xmlregexp.c b/xmlregexp.c index a2a36c49918..31e3d1a6229 100644 --- a/xmlregexp.c +++ b/xmlregexp.c @@ -19,8 +19,6 @@ #ifdef LIBXML_REGEXP_ENABLED -/* #define DEBUG_ERR */ - #include #include #include @@ -31,15 +29,13 @@ #include #include +#include "private/error.h" +#include "private/regexp.h" + #ifndef SIZE_MAX #define SIZE_MAX ((size_t) -1) #endif -/* #define DEBUG_REGEXP_GRAPH */ -/* #define DEBUG_REGEXP_EXEC */ -/* #define DEBUG_PUSH */ -/* #define DEBUG_COMPACTION */ - #define MAX_PUSH 10000000 #ifdef ERROR @@ -52,7 +48,6 @@ #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 '|' /* @@ -61,16 +56,6 @@ */ #define PREV (ctxt->cur[-1]) -/** - * TODO: - * - * macro to flag unimplemented blocks - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - /************************************************************************ * * * Datatypes and structures * @@ -361,8 +346,6 @@ 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 * @@ -375,17 +358,12 @@ void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); * Handle an out of memory condition */ static void -xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt, const char *extra) +xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt) { - const char *regexp = NULL; - if (ctxt != NULL) { - regexp = (const char *) ctxt->string; - ctxt->error = XML_ERR_NO_MEMORY; - } - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - regexp, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + if (ctxt != NULL) + ctxt->error = XML_ERR_NO_MEMORY; + + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_REGEXP, NULL); } /** @@ -399,16 +377,20 @@ xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra) { const char *regexp = NULL; int idx = 0; + int res; if (ctxt != NULL) { regexp = (const char *) ctxt->string; idx = ctxt->cur - ctxt->string; ctxt->error = XML_REGEXP_COMPILE_ERROR; } - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, - XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, NULL, 0, extra, - regexp, NULL, idx, 0, - "failed to compile: %s\n", extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, + XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, + NULL, 0, extra, regexp, NULL, idx, 0, + "failed to compile: %s\n", extra); + if (res < 0) + xmlRegexpErrMemory(ctxt); } /************************************************************************ @@ -435,7 +417,8 @@ xmlRegCalloc2(size_t dim1, size_t dim2, size_t elemSize) { void *ret; /* Check for overflow */ - if (dim1 > SIZE_MAX / dim2 / elemSize) + if ((dim2 == 0) || (elemSize == 0) || + (dim1 > SIZE_MAX / dim2 / elemSize)) return (NULL); totalSize = dim1 * dim2 * elemSize; ret = xmlMalloc(totalSize); @@ -458,7 +441,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegexp)); @@ -472,7 +455,11 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { ret->determinist = ctxt->determinist; ret->flags = ctxt->flags; if (ret->determinist == -1) { - xmlRegexpIsDeterminist(ret); + if (xmlRegexpIsDeterminist(ret) < 0) { + xmlRegexpErrMemory(ctxt); + xmlFree(ret); + return(NULL); + } } if ((ret->determinist != 0) && @@ -499,7 +486,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { stateRemap = xmlMalloc(ret->nbStates * sizeof(int)); if (stateRemap == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); xmlFree(ret); return(NULL); } @@ -511,19 +498,16 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { 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"); + xmlRegexpErrMemory(ctxt); xmlFree(stateRemap); xmlFree(ret); return(NULL); } stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int)); if (stringRemap == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); xmlFree(stringMap); xmlFree(stateRemap); xmlFree(ret); @@ -563,9 +547,6 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { return(NULL); } } -#ifdef DEBUG_COMPACTION - printf("Final: %d atoms\n", nbatoms); -#endif transitions = (int *) xmlRegCalloc2(nbstates + 1, nbatoms + 1, sizeof(int)); if (transitions == NULL) { @@ -598,14 +579,14 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { for (j = 0;j < state->nbTrans;j++) { trans = &(state->trans[j]); - if ((trans->to == -1) || (trans->atom == NULL)) + if ((trans->to < 0) || (trans->atom == NULL)) continue; atomno = stringRemap[trans->atom->no]; if ((trans->atom->data != NULL) && (transdata == NULL)) { transdata = (void **) xmlRegCalloc2(nbstates, nbatoms, sizeof(void *)); if (transdata == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); break; } } @@ -619,11 +600,6 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { 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); @@ -648,18 +624,6 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { } } 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 */ @@ -713,8 +677,13 @@ xmlRegNewParserCtxt(const xmlChar *string) { if (ret == NULL) return(NULL); memset(ret, 0, sizeof(xmlRegParserCtxt)); - if (string != NULL) + if (string != NULL) { ret->string = xmlStrdup(string); + if (ret->string == NULL) { + xmlFree(ret); + return(NULL); + } + } ret->cur = ret->string; ret->neg = 0; ret->negs = 0; @@ -742,7 +711,7 @@ xmlRegNewRange(xmlRegParserCtxtPtr ctxt, ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating range"); + xmlRegexpErrMemory(ctxt); return(NULL); } ret->neg = neg; @@ -790,7 +759,7 @@ xmlRegCopyRange(xmlRegParserCtxtPtr ctxt, xmlRegRangePtr range) { if (range->blockName != NULL) { ret->blockName = xmlStrdup(range->blockName); if (ret->blockName == NULL) { - xmlRegexpErrMemory(ctxt, "allocating range"); + xmlRegexpErrMemory(ctxt); xmlRegFreeRange(ret); return(NULL); } @@ -813,7 +782,7 @@ xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) { ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating atom"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegAtom)); @@ -865,7 +834,7 @@ xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "copying atom"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegAtom)); @@ -879,7 +848,7 @@ xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { ret->ranges = (xmlRegRangePtr *) xmlMalloc(sizeof(xmlRegRangePtr) * atom->nbRanges); if (ret->ranges == NULL) { - xmlRegexpErrMemory(ctxt, "copying atom"); + xmlRegexpErrMemory(ctxt); goto error; } for (i = 0;i < atom->nbRanges;i++) { @@ -902,7 +871,7 @@ xmlRegNewState(xmlRegParserCtxtPtr ctxt) { ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating state"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegState)); @@ -1189,55 +1158,13 @@ xmlRegPrintState(FILE *output, xmlRegStatePtr state) { } } -#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 +static xmlRegRangePtr xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, int neg, xmlRegAtomType type, int start, int end, xmlChar *blockName) { @@ -1245,20 +1172,20 @@ xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, if (atom == NULL) { ERROR("add range: atom is NULL"); - return; + return(NULL); } if (atom->type != XML_REGEXP_RANGES) { ERROR("add range: atom is not ranges"); - return; + return(NULL); } if (atom->maxRanges == 0) { atom->maxRanges = 4; atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges * sizeof(xmlRegRangePtr)); if (atom->ranges == NULL) { - xmlRegexpErrMemory(ctxt, "adding ranges"); + xmlRegexpErrMemory(ctxt); atom->maxRanges = 0; - return; + return(NULL); } } else if (atom->nbRanges >= atom->maxRanges) { xmlRegRangePtr *tmp; @@ -1266,18 +1193,19 @@ xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges * sizeof(xmlRegRangePtr)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding ranges"); + xmlRegexpErrMemory(ctxt); atom->maxRanges /= 2; - return; + return(NULL); } atom->ranges = tmp; } range = xmlRegNewRange(ctxt, neg, type, start, end); if (range == NULL) - return; + return(NULL); range->blockName = blockName; atom->ranges[atom->nbRanges++] = range; + return(range); } static int @@ -1287,7 +1215,7 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) { ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters * sizeof(xmlRegCounter)); if (ctxt->counters == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); + xmlRegexpErrMemory(ctxt); ctxt->maxCounters = 0; return(-1); } @@ -1297,7 +1225,7 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) { tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters * sizeof(xmlRegCounter)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); + xmlRegexpErrMemory(ctxt); ctxt->maxCounters /= 2; return(-1); } @@ -1314,26 +1242,17 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { 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) { + if (ctxt->nbAtoms >= ctxt->maxAtoms) { + size_t newSize = ctxt->maxAtoms ? ctxt->maxAtoms * 2 : 4; xmlRegAtomPtr *tmp; - ctxt->maxAtoms *= 2; - tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms * - sizeof(xmlRegAtomPtr)); + + tmp = xmlRealloc(ctxt->atoms, newSize * sizeof(xmlRegAtomPtr)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); - ctxt->maxAtoms /= 2; + xmlRegexpErrMemory(ctxt); return(-1); } ctxt->atoms = tmp; + ctxt->maxAtoms = newSize; } atom->no = ctxt->nbAtoms; ctxt->atoms[ctxt->nbAtoms++] = atom; @@ -1348,7 +1267,7 @@ xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target, target->transTo = (int *) xmlMalloc(target->maxTransTo * sizeof(int)); if (target->transTo == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); target->maxTransTo = 0; return; } @@ -1358,7 +1277,7 @@ xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target, tmp = (int *) xmlRealloc(target->transTo, target->maxTransTo * sizeof(int)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); target->maxTransTo /= 2; return; } @@ -1395,10 +1314,6 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, (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; } } @@ -1408,7 +1323,7 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans * sizeof(xmlRegTrans)); if (state->trans == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); state->maxTrans = 0; return; } @@ -1418,25 +1333,12 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans * sizeof(xmlRegTrans)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); state->maxTrans /= 2; return; } 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; @@ -1447,33 +1349,31 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, 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) { +static xmlRegStatePtr +xmlRegStatePush(xmlRegParserCtxtPtr ctxt) { + xmlRegStatePtr state; + + if (ctxt->nbStates >= ctxt->maxStates) { + size_t newSize = ctxt->maxStates ? ctxt->maxStates * 2 : 4; xmlRegStatePtr *tmp; - ctxt->maxStates *= 2; - tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates * - sizeof(xmlRegStatePtr)); + + tmp = xmlRealloc(ctxt->states, newSize * sizeof(tmp[0])); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding state"); - ctxt->maxStates /= 2; - return(-1); + xmlRegexpErrMemory(ctxt); + return(NULL); } ctxt->states = tmp; + ctxt->maxStates = newSize; } + + state = xmlRegNewState(ctxt); + if (state == NULL) + return(NULL); + state->no = ctxt->nbStates; ctxt->states[ctxt->nbStates++] = state; - return(0); + + return(state); } /** @@ -1484,19 +1384,21 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) { * @lax: * */ -static void +static int xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, xmlRegStatePtr to, int lax) { if (to == NULL) { - to = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, to); + to = xmlRegStatePush(ctxt); + if (to == NULL) + return(-1); 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); + return(0); } /** @@ -1506,15 +1408,17 @@ xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt, * @to: the target state or NULL for building a new one * */ -static void +static int xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, xmlRegStatePtr to) { if (to == NULL) { - to = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, to); + to = xmlRegStatePush(ctxt); + if (to == NULL) + return(-1); ctxt->state = to; } xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1); + return(0); } /** @@ -1525,15 +1429,17 @@ xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt, * counter: the counter for that transition * */ -static void +static int xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, xmlRegStatePtr to, int counter) { if (to == NULL) { - to = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, to); + to = xmlRegStatePush(ctxt); + if (to == NULL) + return(-1); ctxt->state = to; } xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1); + return(0); } /** @@ -1544,15 +1450,17 @@ xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt, * counter: the counter for that transition * */ -static void +static int xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, xmlRegStatePtr to, int counter) { if (to == NULL) { - to = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, to); + to = xmlRegStatePush(ctxt); + if (to == NULL) + return(-1); ctxt->state = to; } xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter); + return(0); } /** @@ -1579,9 +1487,6 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, * 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)) { /* @@ -1591,8 +1496,9 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, #ifdef DV } else if ((to == NULL) && (atom->quant != XML_REGEXP_QUANT_RANGE) && (atom->quant != XML_REGEXP_QUANT_ONCE)) { - to = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, to); + to = xmlRegStatePush(ctxt, to); + if (to == NULL) + return(-1); ctxt->state = to; xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to); #endif @@ -1632,8 +1538,9 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, if (to != NULL) { newstate = to; } else { - newstate = xmlRegNewState(ctxt); - xmlRegStatePush(ctxt, newstate); + newstate = xmlRegStatePush(ctxt); + if (newstate == NULL) + return(-1); } /* @@ -1661,10 +1568,14 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, copy->max = 0; if (xmlFAGenerateTransitions(ctxt, atom->start, NULL, copy) - < 0) + < 0) { + xmlRegFreeAtom(copy); return(-1); + } inter = ctxt->state; counter = xmlRegGetCounter(ctxt); + if (counter < 0) + return(-1); ctxt->counters[counter].min = atom->min - 1; ctxt->counters[counter].max = atom->max - 1; /* count the number of times we see it again */ @@ -1683,6 +1594,8 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, * epsilon transition. */ counter = xmlRegGetCounter(ctxt); + if (counter < 0) + return(-1); ctxt->counters[counter].min = atom->min - 1; ctxt->counters[counter].max = atom->max - 1; /* allow a way out based on the count */ @@ -1705,6 +1618,8 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, default: break; } + if (xmlRegAtomPush(ctxt, atom) < 0) + return(-1); return(0); } if ((atom->min == 0) && (atom->max == 0) && @@ -1713,12 +1628,9 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, * we can discard the atom and generate an epsilon transition instead */ if (to == NULL) { - to = xmlRegNewState(ctxt); - if (to != NULL) - xmlRegStatePush(ctxt, to); - else { + to = xmlRegStatePush(ctxt); + if (to == NULL) return(-1); - } } xmlFAGenerateEpsilonTransition(ctxt, from, to); ctxt->state = to; @@ -1726,12 +1638,9 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, return(0); } if (to == NULL) { - to = xmlRegNewState(ctxt); - if (to != NULL) - xmlRegStatePush(ctxt, to); - else { + to = xmlRegStatePush(ctxt); + if (to == NULL) return(-1); - } } end = to; if ((atom->quant == XML_REGEXP_QUANT_MULT) || @@ -1743,18 +1652,12 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, */ xmlRegStatePtr tmp; - tmp = xmlRegNewState(ctxt); - if (tmp != NULL) - xmlRegStatePush(ctxt, tmp); - else { + tmp = xmlRegStatePush(ctxt); + if (tmp == NULL) return(-1); - } xmlFAGenerateEpsilonTransition(ctxt, tmp, to); to = tmp; } - if (xmlRegAtomPush(ctxt, atom) < 0) { - return(-1); - } if ((atom->quant == XML_REGEXP_QUANT_RANGE) && (atom->min == 0) && (atom->max > 0)) { nullable = 1; @@ -1785,6 +1688,8 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, default: break; } + if (xmlRegAtomPush(ctxt, atom) < 0) + return(-1); return(0); } @@ -1803,9 +1708,6 @@ xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr, xmlRegStatePtr from; xmlRegStatePtr to; -#ifdef DEBUG_REGEXP_GRAPH - printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr); -#endif from = ctxt->states[fromnr]; if (from == NULL) return; @@ -1818,56 +1720,67 @@ xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr, 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) + xmlRegTransPtr t1 = &to->trans[transnr]; + int tcounter; + + if (t1->to < 0) continue; - if (to->trans[transnr].atom == NULL) { + if (t1->counter >= 0) { + /* assert(counter < 0); */ + tcounter = t1->counter; + } else { + tcounter = counter; + } + if (t1->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); + if (t1->to != fromnr) { + if (t1->count >= 0) { + xmlRegStateAddTrans(ctxt, from, NULL, ctxt->states[t1->to], + -1, t1->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); - } + xmlFAReduceEpsilonTransitions(ctxt, fromnr, t1->to, + tcounter); } } } 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); - } + xmlRegStateAddTrans(ctxt, from, t1->atom, + ctxt->states[t1->to], tcounter, -1); } } +} + +/** + * xmlFAFinishReduceEpsilonTransitions: + * @ctxt: a regexp parser context + * @fromnr: the from state + * @tonr: the to state + * @counter: should that transition be associated to a counted + * + */ +static void +xmlFAFinishReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int tonr) { + int transnr; + xmlRegStatePtr to; + + to = ctxt->states[tonr]; + if (to == NULL) + return; + if ((to->mark == XML_REGEXP_MARK_START) || + (to->mark == XML_REGEXP_MARK_NORMAL)) + return; + to->mark = XML_REGEXP_MARK_NORMAL; + for (transnr = 0;transnr < to->nbTrans;transnr++) { + xmlRegTransPtr t1 = &to->trans[transnr]; + if ((t1->to >= 0) && (t1->atom == NULL)) + xmlFAFinishReduceEpsilonTransitions(ctxt, t1->to); + } } /** @@ -1914,23 +1827,11 @@ xmlFAEliminateSimpleEpsilonTransitions(xmlRegParserCtxtPtr ctxt) { 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], @@ -1972,9 +1873,6 @@ xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr 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; } @@ -2003,28 +1901,16 @@ xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) { (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); + xmlFAFinishReduceEpsilonTransitions(ctxt, newto); state->mark = XML_REGEXP_MARK_NORMAL; -#ifdef DEBUG_REGEXP_GRAPH - } else { - printf("Found counted transition %d on %d\n", - transnr, statenr); -#endif } } } @@ -2098,9 +1984,6 @@ xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) { 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; } @@ -2626,7 +2509,7 @@ not_determinist: */ static int xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, - int to, xmlRegAtomPtr atom) { + int fromnr, int tonr, xmlRegAtomPtr atom) { int ret = 1; int res; int transnr, nbTrans; @@ -2651,22 +2534,23 @@ xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, /* * check transitions conflicting with the one looked at */ + if ((t1->to < 0) || (t1->to == fromnr)) + continue; if (t1->atom == NULL) { - if (t1->to < 0) - continue; state->markd = XML_REGEXP_MARK_VISITED; res = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to], - to, atom); + fromnr, tonr, atom); if (res == 0) { ret = 0; /* t1->nd = 1; */ } continue; } - if (t1->to != to) - continue; if (xmlFACompareAtoms(t1->atom, atom, deep)) { - ret = 0; + /* Treat equal transitions as deterministic. */ + if ((t1->to != tonr) || + (!xmlFAEqualAtoms(t1->atom, atom, deep))) + ret = 0; /* mark the transition as non-deterministic */ t1->nd = 1; } @@ -2715,10 +2599,6 @@ xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) { int ret = 1; int deep = 1; -#ifdef DEBUG_REGEXP_GRAPH - printf("xmlFAComputesDeterminism\n"); - xmlRegPrintCtxt(stdout, ctxt); -#endif if (ctxt->determinist != -1) return(ctxt->determinist); @@ -2744,11 +2624,11 @@ xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) { /* t1->nd = 1; */ continue; } - if (t1->to == -1) /* eliminated */ + if (t1->to < 0) /* eliminated */ continue; for (i = 0;i < transnr;i++) { t2 = &(state->trans[i]); - if (t2->to == -1) /* eliminated */ + if (t2->to < 0) /* eliminated */ continue; if (t2->atom != NULL) { if (t1->to == t2->to) { @@ -2786,11 +2666,11 @@ xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) { if (t1->atom == NULL) { continue; } - if (t1->to == -1) /* eliminated */ + if (t1->to < 0) /* eliminated */ continue; for (i = 0;i < transnr;i++) { t2 = &(state->trans[i]); - if (t2->to == -1) /* eliminated */ + if (t2->to < 0) /* eliminated */ continue; if (t2->atom != NULL) { /* @@ -2798,29 +2678,39 @@ xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) { * find transitions which indicate a conflict */ if (xmlFACompareAtoms(t1->atom, t2->atom, 1)) { - ret = 0; + /* + * Treat equal counter transitions that couldn't be + * eliminated as deterministic. + */ + if ((t1->to != t2->to) || + (t1->counter == t2->counter) || + (!xmlFAEqualAtoms(t1->atom, t2->atom, deep))) + ret = 0; /* mark the transitions as non-deterministic ones */ t1->nd = 1; t2->nd = 1; last = t1; } - } else if (t1->to != -1) { + } else { + int res; + /* * 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); - xmlFAFinishRecurseDeterminism(ctxt, ctxt->states[t1->to]); + res = xmlFARecurseDeterminism(ctxt, ctxt->states[t2->to], + statenr, t1->to, t1->atom); + xmlFAFinishRecurseDeterminism(ctxt, ctxt->states[t2->to]); /* don't shortcut the computation so all non deterministic transition get marked down if (ret == 0) return(0); */ - if (ret == 0) { + if (res == 0) { t1->nd = 1; /* t2->nd = 1; */ last = t1; + ret = 0; } } } @@ -3139,33 +3029,11 @@ xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) { * * ************************************************************************/ -#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) { + exec->status = XML_REGEXP_INTERNAL_LIMIT; return; } exec->nbPush++; @@ -3176,8 +3044,8 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks * sizeof(xmlRegExecRollback)); if (exec->rollbacks == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); exec->maxRollbacks = 0; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } memset(exec->rollbacks, 0, @@ -3190,8 +3058,8 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks, exec->maxRollbacks * sizeof(xmlRegExecRollback)); if (tmp == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); exec->maxRollbacks /= 2; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } exec->rollbacks = tmp; @@ -3206,8 +3074,7 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { exec->rollbacks[exec->nbRollbacks].counts = (int *) xmlMalloc(exec->comp->nbCounters * sizeof(int)); if (exec->rollbacks[exec->nbRollbacks].counts == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); - exec->status = -5; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } } @@ -3219,11 +3086,10 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { static void xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) { + if (exec->status != XML_REGEXP_OK) + return; if (exec->nbRollbacks <= 0) { - exec->status = -1; -#ifdef DEBUG_REGEXP_EXEC - printf("rollback failed on empty stack\n"); -#endif + exec->status = XML_REGEXP_NOT_FOUND; return; } exec->nbRollbacks--; @@ -3233,7 +3099,7 @@ xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) { if (exec->comp->nbCounters > 0) { if (exec->rollbacks[exec->nbRollbacks].counts == NULL) { fprintf(stderr, "exec save: allocation failed"); - exec->status = -6; + exec->status = XML_REGEXP_INTERNAL_ERROR; return; } if (exec->counts) { @@ -3241,11 +3107,6 @@ xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) { exec->comp->nbCounters * sizeof(int)); } } - -#ifdef DEBUG_REGEXP_EXEC - printf("restored "); - xmlFARegDebugExec(exec); -#endif } /************************************************************************ @@ -3267,7 +3128,7 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { exec->maxRollbacks = 0; exec->nbRollbacks = 0; exec->rollbacks = NULL; - exec->status = 0; + exec->status = XML_REGEXP_OK; exec->comp = comp; exec->state = comp->states[0]; exec->transno = 0; @@ -3277,13 +3138,12 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { if (comp->nbCounters > 0) { exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int)); if (exec->counts == NULL) { - xmlRegexpErrMemory(NULL, "running regexp"); - return(-1); + return(XML_REGEXP_OUT_OF_MEMORY); } memset(exec->counts, 0, comp->nbCounters * sizeof(int)); } else exec->counts = NULL; - while ((exec->status == 0) && (exec->state != NULL) && + while ((exec->status == XML_REGEXP_OK) && (exec->state != NULL) && ((exec->inputString[exec->index] != 0) || ((exec->state != NULL) && (exec->state->type != XML_REGEXP_FINAL_STATE)))) { @@ -3327,7 +3187,7 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { xmlRegCounterPtr counter; if (exec->counts == NULL) { - exec->status = -1; + exec->status = XML_REGEXP_INTERNAL_ERROR; goto error; } /* @@ -3336,19 +3196,21 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { 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; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } else if (exec->inputString[exec->index] != 0) { - codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len); + len = 4; + codepoint = xmlGetUTF8Char(&exec->inputString[exec->index], + &len); + if (codepoint < 0) { + exec->status = XML_REGEXP_INVALID_UTF8; + goto error; + } ret = xmlRegCheckCharacter(atom, codepoint); if ((ret == 1) && (atom->min >= 0) && (atom->max > 0)) { xmlRegStatePtr to = comp->states[trans->to]; @@ -3365,7 +3227,7 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { if ((exec->counts == NULL) || (exec->comp == NULL) || (exec->comp->counters == NULL)) { - exec->status = -1; + exec->status = XML_REGEXP_INTERNAL_ERROR; goto error; } counter = &exec->comp->counters[trans->counter]; @@ -3375,11 +3237,10 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { /* Save before incrementing */ if (exec->state->nbTrans > exec->transno + 1) { xmlFARegExecSave(exec); + if (exec->status != XML_REGEXP_OK) + goto error; } if (trans->counter >= 0) { -#ifdef DEBUG_REGEXP_EXEC - printf("Increasing count %d\n", trans->counter); -#endif exec->counts[trans->counter]++; } exec->transcount = 1; @@ -3408,11 +3269,18 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { exec->transno = -1; /* trick */ exec->state = to; xmlFARegExecSave(exec); + if (exec->status != XML_REGEXP_OK) + goto error; exec->transno = transno; exec->state = state; } - codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), - len); + len = 4; + codepoint = xmlGetUTF8Char( + &exec->inputString[exec->index], &len); + if (codepoint < 0) { + exec->status = XML_REGEXP_INVALID_UTF8; + goto error; + } ret = xmlRegCheckCharacter(atom, codepoint); exec->transcount++; } while (ret == 1); @@ -3430,12 +3298,9 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { } if (trans->counter >= 0) { if (exec->counts == NULL) { - exec->status = -1; + exec->status = XML_REGEXP_INTERNAL_ERROR; 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)) { @@ -3458,15 +3323,9 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { 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 (exec->status != XML_REGEXP_OK) + goto error; } if (trans->counter >= 0) { xmlRegCounterPtr counter; @@ -3475,32 +3334,22 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { if ((exec->counts == NULL) || (exec->comp == NULL) || (exec->comp->counters == NULL)) { - exec->status = -1; + exec->status = XML_REGEXP_INTERNAL_ERROR; 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; + exec->status = XML_REGEXP_INTERNAL_ERROR; 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) { @@ -3508,7 +3357,7 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { } goto progress; } else if (ret < 0) { - exec->status = -4; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } } @@ -3518,10 +3367,6 @@ 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: @@ -3539,16 +3384,13 @@ error: xmlFree(exec->rollbacks); } if (exec->state == NULL) - return(-1); + return(XML_REGEXP_INTERNAL_ERROR); if (exec->counts != NULL) xmlFree(exec->counts); - if (exec->status == 0) + if (exec->status == XML_REGEXP_OK) return(1); - if (exec->status == -1) { - if (exec->nbPush > MAX_PUSH) - return(-1); + if (exec->status == XML_REGEXP_NOT_FOUND) return(0); - } return(exec->status); } @@ -3557,9 +3399,6 @@ error: * Progressive interface to the verifier one atom at a time * * * ************************************************************************/ -#ifdef DEBUG_ERR -static void testerr(xmlRegExecCtxtPtr exec); -#endif /** * xmlRegNewExecCtxt: @@ -3581,10 +3420,8 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { if ((comp->compact == NULL) && (comp->states == NULL)) return(NULL); exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt)); - if (exec == NULL) { - xmlRegexpErrMemory(NULL, "creating execution context"); + if (exec == NULL) return(NULL); - } memset(exec, 0, sizeof(xmlRegExecCtxt)); exec->inputString = NULL; exec->index = 0; @@ -3592,7 +3429,7 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { exec->maxRollbacks = 0; exec->nbRollbacks = 0; exec->rollbacks = NULL; - exec->status = 0; + exec->status = XML_REGEXP_OK; exec->comp = comp; if (comp->compact == NULL) exec->state = comp->states[0]; @@ -3608,7 +3445,6 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int) * 2); if (exec->counts == NULL) { - xmlRegexpErrMemory(NULL, "creating execution context"); xmlFree(exec); return(NULL); } @@ -3664,19 +3500,32 @@ xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) { xmlFree(exec); } +static int +xmlRegExecSetErrString(xmlRegExecCtxtPtr exec, const xmlChar *value) { + if (exec->errString != NULL) + xmlFree(exec->errString); + if (value == NULL) { + exec->errString = NULL; + } else { + exec->errString = xmlStrdup(value); + if (exec->errString == NULL) { + exec->status = XML_REGEXP_OUT_OF_MEMORY; + return(-1); + } + } + return(0); +} + static void xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, void *data) { -#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; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } } else if (exec->inputStackNr + 1 >= exec->inputStackMax) { @@ -3686,13 +3535,21 @@ xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack, exec->inputStackMax * sizeof(xmlRegInputToken)); if (tmp == NULL) { - xmlRegexpErrMemory(NULL, "pushing input string"); exec->inputStackMax /= 2; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } exec->inputStack = tmp; } - exec->inputStack[exec->inputStackNr].value = xmlStrdup(value); + if (value == NULL) { + exec->inputStack[exec->inputStackNr].value = NULL; + } else { + exec->inputStack[exec->inputStackNr].value = xmlStrdup(value); + if (exec->inputStack[exec->inputStackNr].value == NULL) { + exec->status = XML_REGEXP_OUT_OF_MEMORY; + return; + } + } exec->inputStack[exec->inputStackNr].data = data; exec->inputStackNr++; exec->inputStack[exec->inputStackNr].value = NULL; @@ -3782,10 +3639,6 @@ xmlRegCompactPushString(xmlRegExecCtxtPtr exec, return(0); } -#ifdef DEBUG_PUSH - printf("value pushed: %s\n", value); -#endif - /* * Examine all outside transitions from current state */ @@ -3799,9 +3652,6 @@ xmlRegCompactPushString(xmlRegExecCtxtPtr exec, 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; @@ -3817,19 +3667,11 @@ xmlRegCompactPushString(xmlRegExecCtxtPtr exec, * 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); + exec->status = XML_REGEXP_NOT_FOUND; + xmlRegExecSetErrString(exec, value); + return(exec->status); } /** @@ -3857,7 +3699,7 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, return(-1); if (exec->comp == NULL) return(-1); - if (exec->status != 0) + if (exec->status != XML_REGEXP_OK) return(exec->status); if (exec->comp->compact != NULL) @@ -3869,9 +3711,6 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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 @@ -3880,12 +3719,9 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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) && + while ((exec->status == XML_REGEXP_OK) && ((value != NULL) || ((final == 1) && (exec->state->type != XML_REGEXP_FINAL_STATE)))) { @@ -3913,9 +3749,6 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, ret = 0; -#ifdef DEBUG_PUSH - printf("testing all lax %d\n", trans->count); -#endif /* * Check all counted transitions from the current state */ @@ -3951,9 +3784,6 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, ret = 1; -#ifdef DEBUG_PUSH - printf("testing all %d\n", trans->count); -#endif /* * Check all counted transitions from the current state */ @@ -3978,14 +3808,10 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } else if (value != NULL) { ret = xmlRegStrEqualWildcard(atom->valuep, value); @@ -4027,9 +3853,6 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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 @@ -4084,22 +3907,12 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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)) { @@ -4107,9 +3920,8 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, * entering a sink state, save the current state as error * state. */ - if (exec->errString != NULL) - xmlFree(exec->errString); - exec->errString = xmlStrdup(value); + if (xmlRegExecSetErrString(exec, value) < 0) + break; exec->errState = exec->state; memcpy(exec->errCounts, exec->counts, exec->comp->nbCounters * sizeof(int)); @@ -4122,27 +3934,18 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, 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; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } } @@ -4155,9 +3958,8 @@ rollback: if ((progress) && (exec->state != NULL) && (exec->state->type != XML_REGEXP_SINK_STATE)) { progress = 0; - if (exec->errString != NULL) - xmlFree(exec->errString); - exec->errString = xmlStrdup(value); + if (xmlRegExecSetErrString(exec, value) < 0) + break; exec->errState = exec->state; if (exec->comp->nbCounters) memcpy(exec->errCounts, exec->counts, @@ -4169,12 +3971,10 @@ rollback: */ exec->determinist = 0; xmlFARegExecRollBack(exec); - if ((exec->inputStack != NULL ) && (exec->status == 0)) { + if ((exec->inputStack != NULL ) && + (exec->status == XML_REGEXP_OK)) { value = exec->inputStack[exec->index].value; data = exec->inputStack[exec->index].data; -#ifdef DEBUG_PUSH - printf("value loaded: %s\n", value); -#endif } } continue; @@ -4182,14 +3982,9 @@ progress: progress = 1; continue; } - if (exec->status == 0) { + if (exec->status == XML_REGEXP_OK) { return(exec->state->type == XML_REGEXP_FINAL_STATE); } -#ifdef DEBUG_ERR - if (exec->status < 0) { - testerr(exec); - } -#endif return(exec->status); } @@ -4233,7 +4028,7 @@ xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value, return(-1); if (exec->comp == NULL) return(-1); - if (exec->status != 0) + if (exec->status != XML_REGEXP_OK) return(exec->status); if (value2 == NULL) @@ -4245,7 +4040,7 @@ xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value, if (150 < lenn + lenp + 2) { str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); if (str == NULL) { - exec->status = -1; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return(-1); } } else { @@ -4362,10 +4157,8 @@ xmlRegExecGetValues(xmlRegExecCtxtPtr exec, int err, continue; if (trans->count == REGEXP_ALL_LAX_COUNTER) { /* this should not be reached but ... */ - TODO; } else if (trans->count == REGEXP_ALL_COUNTER) { /* this should not be reached but ... */ - TODO; } else if (trans->counter >= 0) { xmlRegCounterPtr counter = NULL; int count; @@ -4474,7 +4267,7 @@ xmlRegExecErrInfo(xmlRegExecCtxtPtr exec, const xmlChar **string, if (exec == NULL) return(-1); if (string != NULL) { - if (exec->status != 0) + if (exec->status != XML_REGEXP_OK) *string = exec->errString; else *string = NULL; @@ -4482,17 +4275,6 @@ xmlRegExecErrInfo(xmlRegExecCtxtPtr exec, const xmlChar **string, 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) { @@ -4503,10 +4285,10 @@ xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) { if (exec == NULL) return(-1); - if (exec->status != 0) + if (exec->status != XML_REGEXP_OK) return(exec->status); - while ((exec->status == 0) && + while ((exec->status == XML_REGEXP_OK) && ((exec->inputString[exec->index] != 0) || (exec->state->type != XML_REGEXP_FINAL_STATE))) { @@ -4535,14 +4317,10 @@ xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) { 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; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } else if (exec->inputString[exec->index] != 0) { codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len); @@ -4612,20 +4390,11 @@ xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) { * 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) { @@ -4633,7 +4402,7 @@ xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) { } goto progress; } else if (ret < 0) { - exec->status = -4; + exec->status = XML_REGEXP_INTERNAL_ERROR; break; } } @@ -4668,7 +4437,12 @@ xmlFAIsChar(xmlRegParserCtxtPtr ctxt) { int cur; int len; - cur = CUR_SCHAR(ctxt->cur, len); + len = 4; + cur = xmlGetUTF8Char(ctxt->cur, &len); + if (cur < 0) { + ERROR("Invalid UTF-8"); + return(0); + } if ((cur == '.') || (cur == '\\') || (cur == '?') || (cur == '*') || (cur == '+') || (cur == '(') || (cur == ')') || (cur == '|') || (cur == 0x5B) || @@ -4886,17 +4660,24 @@ xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) { } type = XML_REGEXP_BLOCK_NAME; blockName = xmlStrndup(start, ctxt->cur - start); + if (blockName == NULL) + xmlRegexpErrMemory(ctxt); } else { ERROR("Unknown char property"); return; } if (ctxt->atom == NULL) { ctxt->atom = xmlRegNewAtom(ctxt, type); - if (ctxt->atom != NULL) - ctxt->atom->valuep = blockName; + if (ctxt->atom == NULL) { + xmlFree(blockName); + return; + } + ctxt->atom->valuep = blockName; } else if (ctxt->atom->type == XML_REGEXP_RANGES) { - xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, - type, 0, 0, blockName); + if (xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + type, 0, 0, blockName) == NULL) { + xmlFree(blockName); + } } } @@ -5151,7 +4932,12 @@ xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) { end = start; len = 1; } else if ((cur != 0x5B) && (cur != 0x5D)) { - end = start = CUR_SCHAR(ctxt->cur, len); + len = 4; + end = start = xmlGetUTF8Char(ctxt->cur, &len); + if (start < 0) { + ERROR("Invalid UTF-8"); + return; + } } else { ERROR("Expecting a char range"); return; @@ -5190,7 +4976,12 @@ xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) { } len = 1; } else if ((cur != '\0') && (cur != 0x5B) && (cur != 0x5D)) { - end = CUR_SCHAR(ctxt->cur, len); + len = 4; + end = xmlGetUTF8Char(ctxt->cur, &len); + if (end < 0) { + ERROR("Invalid UTF-8"); + return; + } } else { ERROR("Expecting the end of a char range"); return; @@ -5405,7 +5196,12 @@ xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) { ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL); if (ctxt->atom == NULL) return(-1); - codepoint = CUR_SCHAR(ctxt->cur, len); + len = 4; + codepoint = xmlGetUTF8Char(ctxt->cur, &len); + if (codepoint < 0) { + ERROR("Invalid UTF-8"); + return(-1); + } ctxt->atom->codepoint = codepoint; NEXTL(len); return(1); @@ -5500,8 +5296,12 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr to) { xmlFAGenerateEpsilonTransition(ctxt, previous, to); } else { if (xmlFAGenerateTransitions(ctxt, previous, - (CUR=='|' || CUR==')' || CUR==0) ? to : NULL, ctxt->atom) < 0) + (CUR=='|' || CUR==')' || CUR==0) ? to : NULL, + ctxt->atom) < 0) { + xmlRegFreeAtom(ctxt->atom); + ctxt->atom = NULL; return(-1); + } previous = ctxt->state; ctxt->atom = NULL; } @@ -5510,8 +5310,11 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr to) { if (ret != 0) { if (xmlFAGenerateTransitions(ctxt, previous, (CUR=='|' || CUR==')' || CUR==0) ? to : NULL, - ctxt->atom) < 0) - return(-1); + ctxt->atom) < 0) { + xmlRegFreeAtom(ctxt->atom); + ctxt->atom = NULL; + return(-1); + } previous = ctxt->state; ctxt->atom = NULL; } @@ -5535,9 +5338,6 @@ xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top) { 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 != '|') { @@ -5612,27 +5412,30 @@ xmlRegexpPrint(FILE *output, xmlRegexpPtr regexp) { */ xmlRegexpPtr xmlRegexpCompile(const xmlChar *regexp) { - xmlRegexpPtr ret; + xmlRegexpPtr ret = NULL; xmlRegParserCtxtPtr ctxt; + if (regexp == NULL) + return(NULL); + ctxt = xmlRegNewParserCtxt(regexp); if (ctxt == NULL) return(NULL); /* initialize the parser */ + ctxt->state = xmlRegStatePush(ctxt); + if (ctxt->state == NULL) + goto error; + ctxt->start = ctxt->state; 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); - } + if (ctxt->error != 0) + goto error; ctxt->end = ctxt->state; ctxt->start->type = XML_REGEXP_START_STATE; ctxt->end->type = XML_REGEXP_FINAL_STATE; @@ -5641,11 +5444,11 @@ xmlRegexpCompile(const xmlChar *regexp) { xmlFAEliminateEpsilonTransitions(ctxt); - if (ctxt->error != 0) { - xmlRegFreeParserCtxt(ctxt); - return(NULL); - } + if (ctxt->error != 0) + goto error; ret = xmlRegEpxFromParse(ctxt); + +error: xmlRegFreeParserCtxt(ctxt); return(ret); } @@ -5770,18 +5573,15 @@ xmlNewAutomata(void) { return(NULL); /* initialize the parser */ - ctxt->end = NULL; - ctxt->start = ctxt->state = xmlRegNewState(ctxt); - if (ctxt->start == NULL) { + ctxt->state = xmlRegStatePush(ctxt); + if (ctxt->state == NULL) { xmlFreeAutomata(ctxt); return(NULL); } + ctxt->start = ctxt->state; + ctxt->end = 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); @@ -5873,6 +5673,11 @@ xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from, return(NULL); atom->data = data; atom->valuep = xmlStrdup(token); + if (atom->valuep == NULL) { + xmlRegFreeAtom(atom); + xmlRegexpErrMemory(am); + return(NULL); + } if (xmlFAGenerateTransitions(am, from, to, atom) < 0) { xmlRegFreeAtom(atom); @@ -6044,6 +5849,8 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, return(NULL); if ((token2 == NULL) || (*token2 == 0)) { atom->valuep = xmlStrdup(token); + if (atom->valuep == NULL) + goto error; } else { int lenn, lenp; xmlChar *str; @@ -6052,10 +5859,8 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, lenp = strlen((char *) token); str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); - if (str == NULL) { - xmlRegFreeAtom(atom); - return(NULL); - } + if (str == NULL) + goto error; memcpy(&str[0], token, lenp); str[lenp] = '|'; memcpy(&str[lenp + 1], token2, lenn); @@ -6074,16 +5879,20 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, * associate a counter to the transition. */ counter = xmlRegGetCounter(am); + if (counter < 0) + goto error; am->counters[counter].min = min; am->counters[counter].max = max; /* xmlFAGenerateTransitions(am, from, to, atom); */ if (to == NULL) { - to = xmlRegNewState(am); - xmlRegStatePush(am, to); + to = xmlRegStatePush(am); + if (to == NULL) + goto error; } xmlRegStateAddTrans(am, from, atom, to, counter, -1); - xmlRegAtomPush(am, atom); + if (xmlRegAtomPush(am, atom) < 0) + goto error; am->state = to; if (to == NULL) @@ -6093,6 +5902,10 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, if (min == 0) xmlFAGenerateEpsilonTransition(am, from, to); return(to); + +error: + xmlRegFreeAtom(atom); + return(NULL); } /** @@ -6129,6 +5942,8 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, if (atom == NULL) return(NULL); atom->valuep = xmlStrdup(token); + if (atom->valuep == NULL) + goto error; atom->data = data; if (min == 0) atom->min = 1; @@ -6140,16 +5955,20 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, * associate a counter to the transition. */ counter = xmlRegGetCounter(am); + if (counter < 0) + goto error; am->counters[counter].min = min; am->counters[counter].max = max; /* xmlFAGenerateTransitions(am, from, to, atom); */ if (to == NULL) { - to = xmlRegNewState(am); - xmlRegStatePush(am, to); + to = xmlRegStatePush(am); + if (to == NULL) + goto error; } xmlRegStateAddTrans(am, from, atom, to, counter, -1); - xmlRegAtomPush(am, atom); + if (xmlRegAtomPush(am, atom) < 0) + goto error; am->state = to; if (to == NULL) @@ -6159,6 +5978,10 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, if (min == 0) xmlFAGenerateEpsilonTransition(am, from, to); return(to); + +error: + xmlRegFreeAtom(atom); + return(NULL); } /** @@ -6199,6 +6022,8 @@ xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, return(NULL); if ((token2 == NULL) || (*token2 == 0)) { atom->valuep = xmlStrdup(token); + if (atom->valuep == NULL) + goto error; } else { int lenn, lenp; xmlChar *str; @@ -6207,10 +6032,8 @@ xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, lenp = strlen((char *) token); str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); - if (str == NULL) { - xmlRegFreeAtom(atom); - return(NULL); - } + if (str == NULL) + goto error; memcpy(&str[0], token, lenp); str[lenp] = '|'; memcpy(&str[lenp + 1], token2, lenn); @@ -6226,18 +6049,26 @@ xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, * associate a counter to the transition. */ counter = xmlRegGetCounter(am); + if (counter < 0) + goto error; am->counters[counter].min = 1; am->counters[counter].max = 1; /* xmlFAGenerateTransitions(am, from, to, atom); */ if (to == NULL) { - to = xmlRegNewState(am); - xmlRegStatePush(am, to); + to = xmlRegStatePush(am); + if (to == NULL) + goto error; } xmlRegStateAddTrans(am, from, atom, to, counter, -1); - xmlRegAtomPush(am, atom); + if (xmlRegAtomPush(am, atom) < 0) + goto error; am->state = to; return(to); + +error: + xmlRegFreeAtom(atom); + return(NULL); } @@ -6285,18 +6116,26 @@ xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, * associate a counter to the transition. */ counter = xmlRegGetCounter(am); + if (counter < 0) + goto error; am->counters[counter].min = 1; am->counters[counter].max = 1; /* xmlFAGenerateTransitions(am, from, to, atom); */ if (to == NULL) { - to = xmlRegNewState(am); - xmlRegStatePush(am, to); + to = xmlRegStatePush(am); + if (to == NULL) + goto error; } xmlRegStateAddTrans(am, from, atom, to, counter, -1); - xmlRegAtomPush(am, atom); + if (xmlRegAtomPush(am, atom) < 0) + goto error; am->state = to; return(to); + +error: + xmlRegFreeAtom(atom); + return(NULL); } /** @@ -6309,13 +6148,9 @@ xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, */ xmlAutomataStatePtr xmlAutomataNewState(xmlAutomataPtr am) { - xmlAutomataStatePtr to; - if (am == NULL) return(NULL); - to = xmlRegNewState(am); - xmlRegStatePush(am, to); - return(to); + return(xmlRegStatePush(am)); } /** @@ -6454,6 +6289,8 @@ xmlAutomataCompile(xmlAutomataPtr am) { if ((am == NULL) || (am->error != 0)) return(NULL); xmlFAEliminateEpsilonTransitions(am); + if (am->error != 0) + return(NULL); /* xmlFAComputesDeterminism(am); */ ret = xmlRegEpxFromParse(am); @@ -6572,8 +6409,6 @@ xmlExpFreeCtxt(xmlExpCtxtPtr ctxt) { ************************************************************************/ #define MAX_NODES 10000 -/* #define DEBUG_DERIV */ - /* * TODO: * - Wildcards @@ -7248,14 +7083,8 @@ xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str) 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; } @@ -7263,9 +7092,6 @@ xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str) 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); @@ -7280,23 +7106,14 @@ xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str) 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); @@ -7312,9 +7129,6 @@ xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *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) @@ -7331,14 +7145,8 @@ xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str) 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)); } @@ -7447,17 +7255,11 @@ xmlExpDivide(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub, *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); } @@ -7483,25 +7285,16 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { * 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); @@ -7512,9 +7305,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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); @@ -7528,36 +7318,21 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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) && @@ -7565,32 +7340,17 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { (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("Complex 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 @@ -7602,25 +7362,15 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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 @@ -7651,9 +7401,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { /* 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); @@ -7676,15 +7423,9 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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) { @@ -7695,17 +7436,11 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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; @@ -7715,9 +7450,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { } } 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); } @@ -7733,30 +7465,18 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { * 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 { @@ -7765,9 +7485,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { } } 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; @@ -7777,9 +7494,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { } } else { if (exp->exp_max < sub->exp_max) { -#ifdef DEBUG_DERIV - printf("loops max mismatch => forbidden\n"); -#endif xmlExpFree(ctxt, tmp); return(forbiddenExp); } @@ -7790,9 +7504,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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); @@ -7807,9 +7518,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr 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) @@ -7821,9 +7529,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { 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); @@ -7835,9 +7540,6 @@ xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { } } -#ifdef DEBUG_DERIV - printf("Fallback to derivative\n"); -#endif if (IS_NILLABLE(sub)) { if (!(IS_NILLABLE(exp))) return(forbiddenExp); @@ -7935,15 +7637,9 @@ xmlExpExpDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { * 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 longer sequences than exp : can't subsume\n"); -#endif return(forbiddenExp); } return(xmlExpExpDeriveInt(ctxt, exp, sub)); @@ -7975,22 +7671,12 @@ xmlExpSubsume(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { * 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 longer sequences 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) diff --git a/xmlsave.c b/xmlsave.c index 9b42c66cac9..16b71d0a50a 100644 --- a/xmlsave.c +++ b/xmlsave.c @@ -9,6 +9,8 @@ #define IN_LIBXML #include "libxml.h" +#include +#include #include #include #include @@ -19,61 +21,15 @@ #include -#include "buf.h" -#include "enc.h" -#include "save.h" - -/************************************************************************ - * * - * 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); -} +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" +#include "private/io.h" +#include "private/save.h" #ifdef LIBXML_OUTPUT_ENABLED -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml" struct _xmlSaveCtxt { void *_private; @@ -105,9 +61,11 @@ struct _xmlSaveCtxt { * Handle an out of memory condition */ static void -xmlSaveErrMemory(const char *extra) +xmlSaveErrMemory(xmlOutputBufferPtr out) { - __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); + if (out != NULL) + out->error = XML_ERR_NO_MEMORY; + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL); } /** @@ -119,9 +77,23 @@ xmlSaveErrMemory(const char *extra) * Handle an out of memory condition */ static void -xmlSaveErr(int code, xmlNodePtr node, const char *extra) +xmlSaveErr(xmlOutputBufferPtr out, int code, xmlNodePtr node, + const char *extra) { const char *msg = NULL; + int res; + + /* Don't overwrite memory errors */ + if ((out != NULL) && (out->error == XML_ERR_NO_MEMORY)) + return; + + if (code == XML_ERR_NO_MEMORY) { + xmlSaveErrMemory(out); + return; + } + + if (out != NULL) + out->error = code; switch(code) { case XML_SAVE_NOT_UTF8: @@ -139,7 +111,13 @@ xmlSaveErr(int code, xmlNodePtr node, const char *extra) default: msg = "unexpected error number\n"; } - __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, node, + XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + msg, extra); + if (res < 0) + xmlSaveErrMemory(out); } /************************************************************************ @@ -240,79 +218,52 @@ xmlEscapeEntities(unsigned char* out, int *outlen, *out++ = ';'; in++; continue; + } else if (*in == 0xD) { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + *out++ = 'D'; + *out++ = ';'; + in++; } else if (((*in >= 0x20) && (*in < 0x80)) || - (*in == '\n') || (*in == '\t')) { + (*in == 0xA) || (*in == 0x9)) { /* * default case, just copy ! */ *out++ = *in++; continue; - } else if (*in >= 0x80) { - /* - * We assume we have UTF-8 input. - */ + } else if (*in < 0x80) { + /* invalid control char */ + if (outend - out < 8) break; + out = xmlSerializeHexCharRef(out, 0xFFFD); + in++; + } else { + int len; + if (outend - out < 11) break; - if (*in < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL); - in++; - goto error; - } else if (*in < 0xE0) { - if (inend - in < 2) break; - val = (in[0]) & 0x1F; - val <<= 6; - val |= (in[1]) & 0x3F; - in += 2; - } else if (*in < 0xF0) { - if (inend - in < 3) break; - val = (in[0]) & 0x0F; - val <<= 6; - val |= (in[1]) & 0x3F; - val <<= 6; - val |= (in[2]) & 0x3F; - in += 3; - } else if (*in < 0xF8) { - if (inend - in < 4) break; - val = (in[0]) & 0x07; - val <<= 6; - val |= (in[1]) & 0x3F; - val <<= 6; - val |= (in[2]) & 0x3F; - val <<= 6; - val |= (in[3]) & 0x3F; - in += 4; - } else { - xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); - in++; - goto error; - } - if (!IS_CHAR(val)) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); - in++; - goto error; - } + len = inend - in; + val = xmlGetUTF8Char(in, &len); + + if (val < 0) { + val = 0xFFFD; + in++; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + in += len; + } /* * We could do multiple things here. Just save as a char ref */ out = xmlSerializeHexCharRef(out, val); - } else if (IS_BYTE_CHAR(*in)) { - if (outend - out < 6) break; - out = xmlSerializeHexCharRef(out, *in++); - } else { - xmlGenericError(xmlGenericErrorContext, - "xmlEscapeEntities : char out of range\n"); - in++; - goto error; } } *outlen = out - outstart; *inlen = in - base; return(0); -error: - *outlen = out - outstart; - *inlen = in - base; - return(-1); } /************************************************************************ @@ -382,15 +333,18 @@ xmlNewSaveCtxt(const char *encoding, int options) ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); if (ret == NULL) { - xmlSaveErrMemory("creating saving context"); + xmlSaveErrMemory(NULL); return ( NULL ); } memset(ret, 0, sizeof(xmlSaveCtxt)); if (encoding != NULL) { - ret->handler = xmlFindCharEncodingHandler(encoding); - if (ret->handler == NULL) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, + &ret->handler); + if (res != XML_ERR_OK) { + xmlSaveErr(NULL, res, NULL, encoding); xmlFreeSaveCtxt(ret); return(NULL); } @@ -439,14 +393,13 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) while (children != NULL) { switch (children->type) { case XML_TEXT_NODE: - xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc, - attr, children->content); + xmlBufAttrSerializeTxtContent(buf, attr->doc, + children->content); break; case XML_ENTITY_REF_NODE: - xmlBufAdd(buf->buffer, BAD_CAST "&", 1); - xmlBufAdd(buf->buffer, children->name, - xmlStrlen(children->name)); - xmlBufAdd(buf->buffer, BAD_CAST ";", 1); + xmlOutputBufferWrite(buf, 1, "&"); + xmlOutputBufferWriteString(buf, (const char *) children->name); + xmlOutputBufferWrite(buf, 1, ";"); break; default: /* should not happen unless we have a badly built tree */ @@ -456,6 +409,46 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) } } +/** + * xmlBufDumpNotationDecl: + * @buf: the XML buffer output + * @nota: A notation declaration + * + * This will dump the content the notation declaration as an XML DTD definition + */ +static void +xmlBufDumpNotationDecl(xmlOutputBufferPtr buf, xmlNotationPtr nota) { + xmlOutputBufferWrite(buf, 11, "name); + + if (nota->PublicID != NULL) { + xmlOutputBufferWrite(buf, 8, " PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, nota->PublicID); + if (nota->SystemID != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + } else { + xmlOutputBufferWrite(buf, 8, " SYSTEM "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + + xmlOutputBufferWrite(buf, 3, " >\n"); +} + +/** + * xmlBufDumpNotationDeclScan: + * @nota: A notation declaration + * @buf: the XML buffer output + * + * This is called with the hash scan function, and just reverses args + */ +static void +xmlBufDumpNotationDeclScan(void *nota, void *buf, + const xmlChar *name ATTRIBUTE_UNUSED) { + xmlBufDumpNotationDecl((xmlOutputBufferPtr) buf, (xmlNotationPtr) nota); +} + /** * xmlBufDumpNotationTable: * @buf: an xmlBufPtr output @@ -463,20 +456,106 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) * * This will dump the content of the notation table as an XML DTD definition */ -void -xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +static void +xmlBufDumpNotationTable(xmlOutputBufferPtr buf, xmlNotationTablePtr table) { + xmlHashScan(table, xmlBufDumpNotationDeclScan, buf); +} + +/** + * xmlBufDumpElementOccur: + * @buf: output buffer + * @cur: element table + * + * Dump the occurrence operator of an element. + */ +static void +xmlBufDumpElementOccur(xmlOutputBufferPtr buf, xmlElementContentPtr cur) { + switch (cur->ocur) { + case XML_ELEMENT_CONTENT_ONCE: + break; + case XML_ELEMENT_CONTENT_OPT: + xmlOutputBufferWrite(buf, 1, "?"); + break; + case XML_ELEMENT_CONTENT_MULT: + xmlOutputBufferWrite(buf, 1, "*"); + break; + case XML_ELEMENT_CONTENT_PLUS: + xmlOutputBufferWrite(buf, 1, "+"); + break; } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpNotationTable(buffer, table); - xmlBufMergeBuffer(buf, buffer); +} + +/** + * xmlBufDumpElementContent: + * @buf: output buffer + * @content: element table + * + * This will dump the content of the element table as an XML DTD definition + */ +static void +xmlBufDumpElementContent(xmlOutputBufferPtr buf, + xmlElementContentPtr content) { + xmlElementContentPtr cur; + + if (content == NULL) return; + + xmlOutputBufferWrite(buf, 1, "("); + cur = content; + + do { + if (cur == NULL) return; + + switch (cur->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlOutputBufferWrite(buf, 7, "#PCDATA"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (cur->prefix != NULL) { + xmlOutputBufferWriteString(buf, + (const char *) cur->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *) cur->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + case XML_ELEMENT_CONTENT_OR: + if ((cur != content) && + (cur->parent != NULL) && + ((cur->type != cur->parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlOutputBufferWrite(buf, 1, "("); + cur = cur->c1; + continue; + } + + while (cur != content) { + xmlElementContentPtr parent = cur->parent; + + if (parent == NULL) return; + + if (((cur->type == XML_ELEMENT_CONTENT_OR) || + (cur->type == XML_ELEMENT_CONTENT_SEQ)) && + ((cur->type != parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlOutputBufferWrite(buf, 1, ")"); + xmlBufDumpElementOccur(buf, cur); + + if (cur == parent->c1) { + if (parent->type == XML_ELEMENT_CONTENT_SEQ) + xmlOutputBufferWrite(buf, 3, " , "); + else if (parent->type == XML_ELEMENT_CONTENT_OR) + xmlOutputBufferWrite(buf, 3, " | "); + + cur = parent->c2; + break; + } + + cur = parent; + } + } while (cur != content); + + xmlOutputBufferWrite(buf, 1, ")"); + xmlBufDumpElementOccur(buf, content); } /** @@ -487,44 +566,174 @@ xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) { * This will dump the content of the element declaration as an XML * DTD definition */ -void -xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +static void +xmlBufDumpElementDecl(xmlOutputBufferPtr buf, xmlElementPtr elem) { + xmlOutputBufferWrite(buf, 10, "prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) elem->prefix); + xmlOutputBufferWrite(buf, 1, ":"); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpElementDecl(buffer, elem); - xmlBufMergeBuffer(buf, buffer); + xmlOutputBufferWriteString(buf, (const char *) elem->name); + xmlOutputBufferWrite(buf, 1, " "); + + switch (elem->etype) { + case XML_ELEMENT_TYPE_EMPTY: + xmlOutputBufferWrite(buf, 5, "EMPTY"); + break; + case XML_ELEMENT_TYPE_ANY: + xmlOutputBufferWrite(buf, 3, "ANY"); + break; + case XML_ELEMENT_TYPE_MIXED: + case XML_ELEMENT_TYPE_ELEMENT: + xmlBufDumpElementContent(buf, elem->content); + break; + default: + /* assert(0); */ + break; + } + + xmlOutputBufferWrite(buf, 2, ">\n"); } +/** + * xmlBufDumpEnumeration: + * @buf: output buffer + * @enum: An enumeration + * + * This will dump the content of the enumeration + */ +static void +xmlBufDumpEnumeration(xmlOutputBufferPtr buf, xmlEnumerationPtr cur) { + while (cur != NULL) { + xmlOutputBufferWriteString(buf, (const char *) cur->name); + if (cur->next != NULL) + xmlOutputBufferWrite(buf, 3, " | "); + + cur = cur->next; + } + + xmlOutputBufferWrite(buf, 1, ")"); +} /** * xmlBufDumpAttributeDecl: - * @buf: an xmlBufPtr output + * @buf: output buffer * @attr: An attribute declaration * * This will dump the content of the attribute declaration as an XML * DTD definition */ -void -xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +static void +xmlBufDumpAttributeDecl(xmlOutputBufferPtr buf, xmlAttributePtr attr) { + xmlOutputBufferWrite(buf, 10, "elem); + xmlOutputBufferWrite(buf, 1, " "); + if (attr->prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) attr->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *) attr->name); + + switch (attr->atype) { + case XML_ATTRIBUTE_CDATA: + xmlOutputBufferWrite(buf, 6, " CDATA"); + break; + case XML_ATTRIBUTE_ID: + xmlOutputBufferWrite(buf, 3, " ID"); + break; + case XML_ATTRIBUTE_IDREF: + xmlOutputBufferWrite(buf, 6, " IDREF"); + break; + case XML_ATTRIBUTE_IDREFS: + xmlOutputBufferWrite(buf, 7, " IDREFS"); + break; + case XML_ATTRIBUTE_ENTITY: + xmlOutputBufferWrite(buf, 7, " ENTITY"); + break; + case XML_ATTRIBUTE_ENTITIES: + xmlOutputBufferWrite(buf, 9, " ENTITIES"); + break; + case XML_ATTRIBUTE_NMTOKEN: + xmlOutputBufferWrite(buf, 8, " NMTOKEN"); + break; + case XML_ATTRIBUTE_NMTOKENS: + xmlOutputBufferWrite(buf, 9, " NMTOKENS"); + break; + case XML_ATTRIBUTE_ENUMERATION: + xmlOutputBufferWrite(buf, 2, " ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + case XML_ATTRIBUTE_NOTATION: + xmlOutputBufferWrite(buf, 11, " NOTATION ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + default: + /* assert(0); */ + break; + } + + switch (attr->def) { + case XML_ATTRIBUTE_NONE: + break; + case XML_ATTRIBUTE_REQUIRED: + xmlOutputBufferWrite(buf, 10, " #REQUIRED"); + break; + case XML_ATTRIBUTE_IMPLIED: + xmlOutputBufferWrite(buf, 9, " #IMPLIED"); + break; + case XML_ATTRIBUTE_FIXED: + xmlOutputBufferWrite(buf, 7, " #FIXED"); + break; + default: + /* assert(0); */ + break; + } + + if (attr->defaultValue != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, attr->defaultValue); + } + + xmlOutputBufferWrite(buf, 2, ">\n"); +} + +/** + * xmlBufDumpEntityContent: + * @buf: output buffer + * @content: entity content. + * + * This will dump the quoted string value, taking care of the special + * treatment required by % + */ +static void +xmlBufDumpEntityContent(xmlOutputBufferPtr buf, const xmlChar *content) { + if (xmlStrchr(content, '%')) { + const char * base, *cur; + + xmlOutputBufferWrite(buf, 1, "\""); + base = cur = (const char *) content; + while (*cur != 0) { + if (*cur == '"') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } else if (*cur == '%') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, "%"); + cur++; + base = cur; + } else { + cur++; + } + } + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 1, "\""); + } else { + xmlOutputBufferWriteQuotedString(buf, content); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpAttributeDecl(buffer, attr); - xmlBufMergeBuffer(buf, buffer); } /** @@ -534,20 +743,48 @@ xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) { * * This will dump the content of the entity table as an XML DTD definition */ -void -xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +static void +xmlBufDumpEntityDecl(xmlOutputBufferPtr buf, xmlEntityPtr ent) { + if ((ent->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) + xmlOutputBufferWrite(buf, 11, "name); + xmlOutputBufferWrite(buf, 1, " "); + + if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + if (ent->ExternalID != NULL) { + xmlOutputBufferWrite(buf, 7, "PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, ent->ExternalID); + xmlOutputBufferWrite(buf, 1, " "); + } else { + xmlOutputBufferWrite(buf, 7, "SYSTEM "); + } + xmlOutputBufferWriteQuotedString(buf, ent->SystemID); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpEntityDecl(buffer, ent); - xmlBufMergeBuffer(buf, buffer); + + if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { + if (ent->content != NULL) { /* Should be true ! */ + xmlOutputBufferWrite(buf, 7, " NDATA "); + if (ent->orig != NULL) + xmlOutputBufferWriteString(buf, (const char *) ent->orig); + else + xmlOutputBufferWriteString(buf, (const char *) ent->content); + } + } + + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (ent->etype == XML_INTERNAL_PARAMETER_ENTITY)) { + if (ent->orig != NULL) + xmlOutputBufferWriteQuotedString(buf, ent->orig); + else + xmlBufDumpEntityContent(buf, ent->content); + } + + xmlOutputBufferWrite(buf, 2, ">\n"); } /************************************************************************ @@ -560,18 +797,21 @@ static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) { xmlOutputBufferPtr buf = ctxt->buf; if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) { - buf->encoder = xmlFindCharEncodingHandler((const char *)encoding); - if (buf->encoder == NULL) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, - (const char *)encoding); - return(-1); - } + xmlCharEncodingHandler *handler; + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) { + xmlSaveErr(buf, res, NULL, encoding); + return(-1); + } buf->conv = xmlBufCreate(); if (buf->conv == NULL) { - xmlCharEncCloseFunc(buf->encoder); - xmlSaveErrMemory("creating encoding buffer"); + xmlCharEncCloseFunc(handler); + xmlSaveErrMemory(buf); return(-1); } + buf->encoder = handler; /* * initialize the state, e.g. if outputting a BOM */ @@ -595,7 +835,6 @@ static void xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur); #endif static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur); -void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur); /** @@ -631,7 +870,8 @@ xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra) * If @ctxt is supplied, @buf should be its buffer. */ static void -xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) { +xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNsPtr cur, + xmlSaveCtxtPtr ctxt) { if ((cur == NULL) || (buf == NULL)) return; if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) @@ -648,24 +888,12 @@ xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) { xmlOutputBufferWriteString(buf, (const char *)cur->prefix); } else xmlOutputBufferWrite(buf, 5, "xmlns"); - xmlOutputBufferWrite(buf, 1, "="); - xmlBufWriteQuotedString(buf->buffer, cur->href); + xmlOutputBufferWrite(buf, 2, "=\""); + xmlBufAttrSerializeTxtContent(buf, doc, cur->href); + xmlOutputBufferWrite(buf, 1, "\""); } } -/** - * xmlNsDumpOutputCtxt - * @ctxt: the save context - * @cur: a namespace - * - * Dump a local Namespace definition to a save context. - * Should be called in the context of attribute dumps. - */ -static void -xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { - xmlNsDumpOutput(ctxt->buf, cur, ctxt); -} - /** * xmlNsListDumpOutputCtxt * @ctxt: the save context @@ -675,9 +903,9 @@ xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { * Should be called in the context of attribute dumps. */ static void -xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { +xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlDocPtr doc, xmlNsPtr cur) { while (cur != NULL) { - xmlNsDumpOutput(ctxt->buf, cur, ctxt); + xmlNsDumpOutput(ctxt->buf, doc, cur, ctxt); cur = cur->next; } } @@ -693,7 +921,7 @@ xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { while (cur != NULL) { - xmlNsDumpOutput(buf, cur, NULL); + xmlNsDumpOutput(buf, NULL, cur, NULL); cur = cur->next; } } @@ -719,12 +947,12 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { xmlOutputBufferWriteString(buf, (const char *)dtd->name); if (dtd->ExternalID != NULL) { xmlOutputBufferWrite(buf, 8, " PUBLIC "); - xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID); + xmlOutputBufferWriteQuotedString(buf, dtd->ExternalID); xmlOutputBufferWrite(buf, 1, " "); - xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); + xmlOutputBufferWriteQuotedString(buf, dtd->SystemID); } else if (dtd->SystemID != NULL) { xmlOutputBufferWrite(buf, 8, " SYSTEM "); - xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); + xmlOutputBufferWriteQuotedString(buf, dtd->SystemID); } if ((dtd->entities == NULL) && (dtd->elements == NULL) && (dtd->attributes == NULL) && (dtd->notations == NULL) && @@ -739,8 +967,7 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { */ if ((dtd->notations != NULL) && ((dtd->doc == NULL) || (dtd->doc->intSubset == dtd))) { - xmlBufDumpNotationTable(buf->buffer, - (xmlNotationTablePtr) dtd->notations); + xmlBufDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations); } format = ctxt->format; level = ctxt->level; @@ -778,7 +1005,19 @@ xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 2, "=\""); - xmlAttrSerializeContent(buf, cur); +#ifdef LIBXML_HTML_ENABLED + if ((ctxt->options & XML_SAVE_XHTML) && + (cur->ns == NULL) && + ((cur->children == NULL) || + (cur->children->content == NULL) || + (cur->children->content[0] == 0)) && + (htmlIsBooleanAttr(cur->name))) { + xmlOutputBufferWriteString(buf, (const char *) cur->name); + } else +#endif + { + xmlAttrSerializeContent(buf, cur); + } xmlOutputBufferWrite(buf, 1, "\""); } @@ -882,15 +1121,15 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break; case XML_ELEMENT_DECL: - xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + xmlBufDumpElementDecl(buf, (xmlElementPtr) cur); break; case XML_ATTRIBUTE_DECL: - xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + xmlBufDumpAttributeDecl(buf, (xmlAttributePtr) cur); break; case XML_ENTITY_DECL: - xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + xmlBufDumpEntityDecl(buf, (xmlEntityPtr) cur); break; case XML_ELEMENT_NODE: @@ -918,7 +1157,7 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) - xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); + xmlNsListDumpOutputCtxt(ctxt, cur->doc, cur->nsDef); for (attr = cur->properties; attr != NULL; attr = attr->next) xmlAttrDumpOutput(ctxt, attr); @@ -1058,7 +1297,7 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break; case XML_NAMESPACE_DECL: - xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); + xmlNsDumpOutput(buf, NULL, (xmlNsPtr) cur, ctxt); break; default: @@ -1207,12 +1446,12 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { if ((ctxt->options & XML_SAVE_NO_DECL) == 0) { xmlOutputBufferWrite(buf, 14, "version != NULL) - xmlBufWriteQuotedString(buf->buffer, cur->version); + xmlOutputBufferWriteQuotedString(buf, cur->version); else xmlOutputBufferWrite(buf, 5, "\"1.0\""); if (encoding != NULL) { xmlOutputBufferWrite(buf, 10, " encoding="); - xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding); + xmlOutputBufferWriteQuotedString(buf, (xmlChar *) encoding); } switch (cur->standalone) { case 0: @@ -1292,7 +1531,7 @@ xhtmlIsEmpty(xmlNodePtr node) { return(0); if (node->children != NULL) return(0); - switch (node->name[0]) { + switch (node->name ? node->name[0] : 0) { case 'a': if (xmlStrEqual(node->name, BAD_CAST "area")) return(1); @@ -1372,17 +1611,6 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) xml_lang = cur; - else if ((cur->ns == NULL) && - ((cur->children == NULL) || - (cur->children->content == NULL) || - (cur->children->content[0] == 0)) && - (htmlIsBooleanAttr(cur->name))) { - if (cur->children != NULL) - xmlFreeNode(cur->children); - cur->children = xmlNewDocText(cur->doc, cur->name); - if (cur->children != NULL) - cur->children->parent = (xmlNodePtr) cur; - } xmlAttrDumpOutput(ctxt, cur); cur = cur->next; } @@ -1433,14 +1661,18 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { */ static void xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { - int format = ctxt->format, addmeta; - xmlNodePtr tmp, root, unformattedNode = NULL; + int format = ctxt->format, addmeta, oldoptions; + xmlNodePtr tmp, root, unformattedNode = NULL, parent; xmlChar *start, *end; xmlOutputBufferPtr buf = ctxt->buf; if (cur == NULL) return; + oldoptions = ctxt->options; + ctxt->options |= XML_SAVE_XHTML; + root = cur; + parent = cur->parent; while (1) { switch (cur->type) { case XML_DOCUMENT_NODE: @@ -1449,7 +1681,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break; case XML_NAMESPACE_DECL: - xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); + xmlNsDumpOutput(buf, NULL, (xmlNsPtr) cur, ctxt); break; case XML_DTD_NODE: @@ -1457,22 +1689,24 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break; case XML_DOCUMENT_FRAG_NODE: - if (cur->children) { + /* Always validate cur->parent when descending. */ + if ((cur->parent == parent) && (cur->children != NULL)) { + parent = cur; cur = cur->children; continue; } break; case XML_ELEMENT_DECL: - xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + xmlBufDumpElementDecl(buf, (xmlElementPtr) cur); break; case XML_ATTRIBUTE_DECL: - xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + xmlBufDumpAttributeDecl(buf, (xmlAttributePtr) cur); break; case XML_ENTITY_DECL: - xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + xmlBufDumpEntityDecl(buf, (xmlEntityPtr) cur); break; case XML_ELEMENT_NODE: @@ -1484,6 +1718,16 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { ctxt->indent_nr : ctxt->level), ctxt->indent); + /* + * Some users like lxml are known to pass nodes with a corrupted + * tree structure. Fall back to a recursive call to handle this + * case. + */ + if ((cur->parent != parent) && (cur->children != NULL)) { + xhtmlNodeDumpOutput(ctxt, cur); + break; + } + xmlOutputBufferWrite(buf, 1, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); @@ -1492,7 +1736,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) - xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); + xmlNsListDumpOutputCtxt(ctxt, cur->doc, cur->nsDef); if ((xmlStrEqual(cur->name, BAD_CAST "html") && (cur->ns == NULL) && (cur->nsDef == NULL))) { /* @@ -1504,10 +1748,10 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { if (cur->properties != NULL) xhtmlAttrListDumpOutput(ctxt, cur->properties); - if ((cur->parent != NULL) && - (cur->parent->parent == (xmlNodePtr) cur->doc) && + if ((parent != NULL) && + (parent->parent == (xmlNodePtr) cur->doc) && xmlStrEqual(cur->name, BAD_CAST"head") && - xmlStrEqual(cur->parent->name, BAD_CAST"html")) { + xmlStrEqual(parent->name, BAD_CAST"html")) { tmp = cur->children; while (tmp != NULL) { @@ -1613,6 +1857,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); if (ctxt->level >= 0) ctxt->level++; + parent = cur; cur = cur->children; continue; } @@ -1707,13 +1952,9 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break; } - /* - * The parent should never be NULL here but we want to handle - * corrupted documents gracefully. - */ - if (cur->parent == NULL) - return; - cur = cur->parent; + cur = parent; + /* cur->parent was validated when descending. */ + parent = cur->parent; if (cur->type == XML_ELEMENT_NODE) { if (ctxt->level > 0) ctxt->level--; @@ -1740,6 +1981,8 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } } } + + ctxt->options = oldoptions; } #endif @@ -1890,7 +2133,7 @@ xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc) /** * xmlSaveTree: * @ctxt: a document saving context - * @node: the top node of the subtree to save + * @cur: 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 @@ -1921,6 +2164,40 @@ xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) return(ret); } +/** + * xmlSaveNotationDecl: + * @ctxt: save context + * @cur: notation + * + * Serialize a notation declaration. + * + * Return 0 on succes, -1 on error. + */ +int +xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur) { + if (ctxt == NULL) + return(-1); + xmlBufDumpNotationDecl(ctxt->buf, cur); + return(0); +} + +/** + * xmlSaveNotationTable: + * @ctxt: save context + * @cur: notation table + * + * Serialize notation declarations of a document. + * + * Return 0 on succes, -1 on error. + */ +int +xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur) { + if (ctxt == NULL) + return(-1); + xmlBufDumpNotationTable(ctxt->buf, cur); + return(0); +} + /** * xmlSaveFlush: * @ctxt: a document saving context @@ -1958,6 +2235,30 @@ xmlSaveClose(xmlSaveCtxtPtr ctxt) return(ret); } +/** + * xmlSaveFinish: + * @ctxt: a document saving context + * + * Close a document saving context, i.e. make sure that all bytes have + * been output and free the associated data. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors code. + */ +int +xmlSaveFinish(xmlSaveCtxtPtr ctxt) +{ + int ret; + + if (ctxt == NULL) + return(XML_ERR_INTERNAL_ERROR); + xmlSaveFlush(ctxt); + ret = ctxt->buf->error; + xmlFreeSaveCtxt(ctxt); + return(ret); +} + /** * xmlSaveSetEscape: * @ctxt: a document saving context @@ -2000,63 +2301,62 @@ xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) /** * xmlBufAttrSerializeTxtContent: - * @buf: and xmlBufPtr output + * @buf: output buffer * @doc: the document - * @attr: the attribute node * @string: the text content * * Serialize text attribute values to an xmlBufPtr */ void -xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string) +xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc, + const xmlChar *string) { - xmlChar *base, *cur; + const xmlChar *base, *cur; if (string == NULL) return; - base = cur = (xmlChar *) string; + base = cur = string; while (*cur != 0) { if (*cur == '\n') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST " ", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, " "); cur++; base = cur; } else if (*cur == '\r') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST " ", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, " "); cur++; base = cur; } else if (*cur == '\t') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST " ", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, " "); cur++; base = cur; } else if (*cur == '"') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST """, 6); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 6, """); cur++; base = cur; } else if (*cur == '<') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST "<", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, "<"); cur++; base = cur; } else if (*cur == '>') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST ">", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, ">"); cur++; base = cur; } else if (*cur == '&') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST "&", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, "&"); cur++; base = cur; } else if ((*cur >= 0x80) && (cur[1] != 0) && @@ -2065,61 +2365,34 @@ xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, * We assume we have UTF-8 content. */ unsigned char tmp[12]; - int val = 0, l = 1; + int val = 0, l = 4; if (base != cur) - xmlBufAdd(buf, base, cur - base); - if (*cur < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); - xmlSerializeHexCharRef(tmp, *cur); - xmlBufAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } else if (*cur < 0xE0) { - val = (cur[0]) & 0x1F; - val <<= 6; - val |= (cur[1]) & 0x3F; - l = 2; - } else if ((*cur < 0xF0) && (cur [2] != 0)) { - val = (cur[0]) & 0x0F; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - l = 3; - } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) { - val = (cur[0]) & 0x07; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - val <<= 6; - val |= (cur[3]) & 0x3F; - l = 4; - } - if ((l == 1) || (!IS_CHAR(val))) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); - xmlSerializeHexCharRef(tmp, *cur); - xmlBufAdd(buf, (xmlChar *) tmp, -1); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + + val = xmlGetUTF8Char(cur, &l); + if (val < 0) { + val = 0xFFFD; cur++; - base = cur; - continue; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + cur += l; } + /* * We could do multiple things here. Just save * as a char ref */ xmlSerializeHexCharRef(tmp, val); - xmlBufAdd(buf, (xmlChar *) tmp, -1); - cur += l; + xmlOutputBufferWriteString(buf, (const char *) tmp); base = cur; } else { cur++; } } if (base != cur) - xmlBufAdd(buf, base, cur - base); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); } /** @@ -2133,17 +2406,19 @@ xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, */ void xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string) + xmlAttrPtr attr ATTRIBUTE_UNUSED, + const xmlChar *string) { - xmlBufPtr buffer; + xmlOutputBufferPtr out; if ((buf == NULL) || (string == NULL)) return; - buffer = xmlBufFromBuffer(buf); - if (buffer == NULL) - return; - xmlBufAttrSerializeTxtContent(buffer, doc, attr, string); - xmlBufBackToBuffer(buffer); + out = xmlOutputBufferCreateBuffer(buf, NULL); + xmlBufAttrSerializeTxtContent(out, doc, string); + xmlOutputBufferFlush(out); + if ((out == NULL) || (out->error)) + xmlFree(xmlBufferDetach(buf)); + xmlOutputBufferClose(out); } /** @@ -2171,6 +2446,10 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, if ((buf == NULL) || (cur == NULL)) return(-1); + if (level < 0) + level = 0; + else if (level > 100) + level = 100; buffer = xmlBufFromBuffer(buf); if (buffer == NULL) return(-1); @@ -2178,7 +2457,7 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, xmlBufBackToBuffer(buffer); if (ret > INT_MAX) return(-1); - return((int) ret); + return(ret); } /** @@ -2202,30 +2481,22 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format) { size_t use; - int ret; + size_t ret; xmlOutputBufferPtr outbuf; int oldalloc; xmlInitParser(); if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDump : node == NULL\n"); -#endif - return (-1); + return ((size_t) -1); } if (buf == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDump : buf == NULL\n"); -#endif - return (-1); + return ((size_t) -1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (outbuf == NULL) { - xmlSaveErrMemory("creating buffer"); - return (-1); + xmlSaveErrMemory(NULL); + return ((size_t) -1); } memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); outbuf->buffer = buf; @@ -2240,8 +2511,11 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); xmlBufSetAllocationScheme(buf, oldalloc); + if (outbuf->error) + ret = (size_t) -1; + else + ret = xmlBufUse(buf) - use; xmlFree(outbuf); - ret = xmlBufUse(buf) - use; return (ret); } @@ -2261,29 +2535,17 @@ xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) 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)) { #ifdef LIBXML_HTML_ENABLED + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) htmlNodeDumpOutput(outbuf, doc, cur, NULL); -#else - xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); + else #endif /* LIBXML_HTML_ENABLED */ - } else xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); xmlOutputBufferClose(outbuf); } @@ -2317,10 +2579,17 @@ xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int is_xhtml = 0; #endif + (void) doc; + xmlInitParser(); if ((buf == NULL) || (cur == NULL)) return; + if (level < 0) + level = 0; + else if (level > 100) + level = 100; + if (encoding == NULL) encoding = "UTF-8"; @@ -2396,16 +2665,19 @@ xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, if (txt_encoding == NULL) txt_encoding = (const char *) out_doc->encoding; if (txt_encoding != NULL) { - conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); - if ( conv_hdlr == NULL ) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, - txt_encoding); + int res; + + res = xmlOpenCharEncodingHandler(txt_encoding, /* output */ 1, + &conv_hdlr); + if (res != XML_ERR_OK) { + xmlSaveErr(NULL, res, NULL, txt_encoding); return; } } if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { - xmlSaveErrMemory("creating buffer"); + xmlSaveErrMemory(NULL); + xmlCharEncCloseFunc(conv_hdlr); return; } @@ -2418,21 +2690,18 @@ xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, out_doc); xmlOutputBufferFlush(out_buff); - if (out_buff->conv != NULL) { - *doc_txt_len = xmlBufUse(out_buff->conv); - *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len); - } else { - *doc_txt_len = xmlBufUse(out_buff->buffer); - *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len); - } - (void)xmlOutputBufferClose(out_buff); - if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { - *doc_txt_len = 0; - xmlSaveErrMemory("creating output"); + if (!out_buff->error) { + if (out_buff->conv != NULL) { + *doc_txt_len = xmlBufUse(out_buff->conv); + *doc_txt_ptr = xmlBufDetach(out_buff->conv); + } else { + *doc_txt_len = xmlBufUse(out_buff->buffer); + *doc_txt_ptr = xmlBufDetach(out_buff->buffer); + } } - return; + xmlOutputBufferClose(out_buff); } /** @@ -2509,17 +2778,15 @@ xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { 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) { + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) { xmlFree((char *) cur->encoding); cur->encoding = NULL; encoding = NULL; @@ -2655,10 +2922,11 @@ xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, encoding = (const char *) cur->encoding; if (encoding != NULL) { + int res; - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - return(-1); + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) + return(-1); } #ifdef LIBXML_ZLIB_ENABLED diff --git a/xmlschemas.c b/xmlschemas.c index f31d3d1f618..48b4e328ab8 100644 --- a/xmlschemas.c +++ b/xmlschemas.c @@ -76,28 +76,11 @@ #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 */ +#include "private/error.h" +#include "private/string.h" /* #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 @@ -113,10 +96,6 @@ #endif #define UNBOUNDED (1 << 30) -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); #define XML_SCHEMAS_NO_NAMESPACE (const xmlChar *) "##" @@ -305,10 +284,20 @@ static const xmlChar *xmlNamespaceNs = (const xmlChar *) #define WXS_SCHEMA(ctx) (ctx)->schema #define WXS_ADD_LOCAL(ctx, item) \ - xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->locals), 10, item) + do { \ + if (xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->locals), 10, item) < 0) { \ + xmlFree(item); \ + item = NULL; \ + } \ + } while (0) #define WXS_ADD_GLOBAL(ctx, item) \ - xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->globals), 5, item) + do { \ + if (xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->globals), 5, item) < 0) { \ + xmlFree(item); \ + item = NULL; \ + } \ + } while (0) #define WXS_ADD_PENDING(ctx, item) \ xmlSchemaAddItemSize(&((ctx)->constructor->pending), 10, item) @@ -1905,22 +1894,6 @@ xmlSchemaFormatFacetEnumSet(xmlSchemaAbstractCtxtPtr actxt, * * ************************************************************************/ -#if 0 -static void -xmlSchemaErrMemory(const char *msg) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL, - msg); -} -#endif - -static void -xmlSchemaPSimpleErr(const char *msg) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL, - msg); -} - /** * xmlSchemaPErrMemory: * @node: a context node @@ -1929,13 +1902,66 @@ xmlSchemaPSimpleErr(const char *msg) * Handle an out of memory condition */ static void -xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt) { - if (ctxt != NULL) + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + + if (ctxt != NULL) { ctxt->nberrors++; - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, - extra); + ctxt->err = XML_ERR_NO_MEMORY; + channel = ctxt->error; + schannel = ctxt->serror; + data = ctxt->errCtxt; + } + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_SCHEMASP, NULL); +} + +static void LIBXML_ATTR_FORMAT(11,12) +xmlSchemaPErrFull(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, + xmlErrorLevel level, const char *file, int line, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int col, const char *msg, ...) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + int res; + va_list ap; + + if (ctxt != NULL) { + /* Don't overwrite memory errors */ + if (ctxt->err == XML_ERR_NO_MEMORY) + return; + + if (level == XML_ERR_WARNING) { + channel = ctxt->warning; + } else { + ctxt->nberrors++; + ctxt->err = code; + channel = ctxt->error; + } + data = ctxt->errCtxt; + schannel = ctxt->serror; + } + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_SCHEMASP, code, level, file, line, + (const char *) str1, + (const char *) str2, + (const char *) str3, + 0, col, msg, ap); + va_end(ap); + + if (res < 0) + xmlSchemaPErrMemory(ctxt); } /** @@ -1950,24 +1976,11 @@ xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, * Handle a parser error */ static void LIBXML_ATTR_FORMAT(4,0) -xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, +xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, const char *msg, const xmlChar * str1, const xmlChar * str2) { - xmlGenericErrorFunc channel = NULL; - xmlStructuredErrorFunc schannel = NULL; - void *data = NULL; - - if (ctxt != NULL) { - ctxt->nberrors++; - ctxt->err = error; - channel = ctxt->error; - data = ctxt->errCtxt; - schannel = ctxt->serror; - } - __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + xmlSchemaPErrFull(ctxt, node, code, XML_ERR_ERROR, NULL, 0, + str1, str2, NULL, 0, msg, str1, str2); } /** @@ -2012,29 +2025,15 @@ xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, * Handle a parser error */ static void LIBXML_ATTR_FORMAT(7,0) -xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, +xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, const xmlChar * strData1, const xmlChar * strData2, const xmlChar * strData3, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3, const xmlChar * str4, const xmlChar * str5) { - - xmlGenericErrorFunc channel = NULL; - xmlStructuredErrorFunc schannel = NULL; - void *data = NULL; - - if (ctxt != NULL) { - ctxt->nberrors++; - ctxt->err = error; - channel = ctxt->error; - data = ctxt->errCtxt; - schannel = ctxt->serror; - } - __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) strData1, (const char *) strData2, - (const char *) strData3, 0, 0, msg, str1, str2, - str3, str4, str5); + xmlSchemaPErrFull(ctxt, node, code, XML_ERR_ERROR, NULL, 0, + strData1, strData2, strData3, 0, + msg, str1, str2, str3, str4, str5); } /************************************************************************ @@ -2051,23 +2050,66 @@ xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, * Handle an out of memory condition */ static void -xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + if (ctxt != NULL) { ctxt->nberrors++; - ctxt->err = XML_SCHEMAV_INTERNAL; + ctxt->err = XML_ERR_NO_MEMORY; + channel = ctxt->error; + schannel = ctxt->serror; + data = ctxt->errCtxt; } - __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, - extra); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_SCHEMASV, NULL); } -static void LIBXML_ATTR_FORMAT(2,0) -xmlSchemaPSimpleInternalErr(xmlNodePtr node, - const char *msg, const xmlChar *str) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_SCHEMAP_INTERNAL, node, - msg, (const char *) str); +static void LIBXML_ATTR_FORMAT(11,12) +xmlSchemaVErrFull(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int code, + xmlErrorLevel level, const char *file, int line, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int col, const char *msg, ...) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + int res; + va_list ap; + + if (ctxt != NULL) { + /* Don't overwrite memory errors */ + if (ctxt->err == XML_ERR_NO_MEMORY) + return; + + if (level == XML_ERR_WARNING) { + channel = ctxt->warning; + } else { + ctxt->nberrors++; + ctxt->err = code; + channel = ctxt->error; + } + data = ctxt->errCtxt; + schannel = ctxt->serror; + } + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_SCHEMASV, code, level, file, line, + (const char *) str1, + (const char *) str2, + (const char *) str3, + 0, col, msg, ap); + va_end(ap); + + if (res < 0) + xmlSchemaVErrMemory(ctxt); } #define WXS_ERROR_TYPE_ERROR 1 @@ -2090,28 +2132,15 @@ xmlSchemaPSimpleInternalErr(xmlNodePtr node, static void LIBXML_ATTR_FORMAT(6,0) xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, xmlErrorLevel errorLevel, - int error, xmlNodePtr node, int line, const char *msg, + int code, xmlNodePtr node, int line, const char *msg, const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, const xmlChar *str4) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - void *data = NULL; - if (ctxt != NULL) { if (ctxt->type == XML_SCHEMA_CTXT_VALIDATOR) { xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctxt; const char *file = NULL; int col = 0; - if (errorLevel != XML_ERR_WARNING) { - vctxt->nberrors++; - vctxt->err = error; - channel = vctxt->error; - } else { - channel = vctxt->warning; - } - schannel = vctxt->serror; - data = vctxt->errCtxt; /* * Error node. If we specify a line number, then @@ -2130,8 +2159,14 @@ xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, (vctxt->parserCtxt != NULL) && (vctxt->parserCtxt->input != NULL)) { file = vctxt->parserCtxt->input->filename; - line = vctxt->parserCtxt->input->line; - col = vctxt->parserCtxt->input->col; + if (vctxt->inode != NULL) { + line = vctxt->inode->nodeLine; + col = 0; + } else { + /* This is inaccurate. */ + line = vctxt->parserCtxt->input->line; + col = vctxt->parserCtxt->input->col; + } } } else { /* @@ -2162,30 +2197,15 @@ xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, if ((file == NULL) && (vctxt->filename != NULL)) file = vctxt->filename; - __xmlRaiseError(schannel, channel, data, ctxt, - node, XML_FROM_SCHEMASV, - error, errorLevel, file, line, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, col, msg, str1, str2, str3, str4); - + xmlSchemaVErrFull(vctxt, node, code, errorLevel, + file, line, str1, str2, str3, col, + msg, str1, str2, str3, str4); } else if (ctxt->type == XML_SCHEMA_CTXT_PARSER) { xmlSchemaParserCtxtPtr pctxt = (xmlSchemaParserCtxtPtr) ctxt; - if (errorLevel != XML_ERR_WARNING) { - pctxt->nberrors++; - pctxt->err = error; - channel = pctxt->error; - } else { - channel = pctxt->warning; - } - schannel = pctxt->serror; - data = pctxt->errCtxt; - __xmlRaiseError(schannel, channel, data, ctxt, - node, XML_FROM_SCHEMASP, error, - errorLevel, NULL, 0, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3, str4); - } else { - TODO + + xmlSchemaPErrFull(pctxt, node, code, errorLevel, + NULL, 0, str1, str2, str3, 0, + msg, str1, str2, str3, str4); } } } @@ -2306,7 +2326,7 @@ xmlSchemaFormatNodeForError(xmlChar ** msg, */ *msg = xmlStrdup(BAD_CAST ""); } else { - TODO + /* TODO */ return (NULL); } @@ -3323,7 +3343,7 @@ xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt) ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating schema", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchema)); @@ -3370,7 +3390,7 @@ xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating annotation", node); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAnnot)); @@ -3385,8 +3405,7 @@ xmlSchemaItemListCreate(void) ret = xmlMalloc(sizeof(xmlSchemaItemList)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating an item list structure", NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaItemList)); @@ -3407,23 +3426,17 @@ xmlSchemaItemListClear(xmlSchemaItemListPtr list) 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; + if (list->sizeItems <= list->nbItems) { + void **tmp; + size_t newSize = list->sizeItems == 0 ? 20 : list->sizeItems * 2; + + tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *)); + if (tmp == NULL) { + xmlSchemaPErrMemory(NULL); return(-1); } + list->items = tmp; + list->sizeItems = newSize; } list->items[list->nbItems++] = item; return(0); @@ -3440,19 +3453,22 @@ xmlSchemaItemListAddSize(xmlSchemaItemListPtr list, list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->sizeItems = initialSize; } else if (list->sizeItems <= list->nbItems) { + void **tmp; + list->sizeItems *= 2; - list->items = (void **) xmlRealloc(list->items, + tmp = (void **) xmlRealloc(list->items, list->sizeItems * sizeof(void *)); - if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); - list->sizeItems = 0; + if (tmp == NULL) { + xmlSchemaPErrMemory(NULL); + list->sizeItems /= 2; return(-1); } + list->items = tmp; } list->items[list->nbItems++] = item; return(0); @@ -3461,23 +3477,17 @@ xmlSchemaItemListAddSize(xmlSchemaItemListPtr list, 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; + if (list->sizeItems <= list->nbItems) { + void **tmp; + size_t newSize = list->sizeItems == 0 ? 20 : list->sizeItems * 2; + + tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *)); + if (tmp == NULL) { + xmlSchemaPErrMemory(NULL); return(-1); } + list->items = tmp; + list->sizeItems = newSize; } /* * Just append if the index is greater/equal than the item count. @@ -3507,7 +3517,7 @@ xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list, list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->sizeItems = initialSize; @@ -3516,7 +3526,7 @@ xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list, list->items = (void **) xmlRealloc(list->items, list->sizeItems * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); + xmlSchemaPErrMemory(NULL); list->sizeItems = 0; return(-1); } @@ -3541,11 +3551,8 @@ static int xmlSchemaItemListRemove(xmlSchemaItemListPtr list, int idx) { int i; - if ((list->items == NULL) || (idx >= list->nbItems)) { - xmlSchemaPSimpleErr("Internal error: xmlSchemaItemListRemove, " - "index error.\n"); + if ((list->items == NULL) || (idx >= list->nbItems)) return(-1); - } if (list->nbItems == 1) { /* TODO: Really free the list? */ @@ -3637,7 +3644,7 @@ xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt, size = sizeof(xmlSchemaImport); ret = (xmlSchemaBucketPtr) xmlMalloc(size); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema bucket", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, size); @@ -3645,12 +3652,12 @@ xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt, ret->type = type; ret->globals = xmlSchemaItemListCreate(); if (ret->globals == NULL) { - xmlFree(ret); + xmlSchemaBucketFree(ret); return(NULL); } ret->locals = xmlSchemaItemListCreate(); if (ret->locals == NULL) { - xmlFree(ret); + xmlSchemaBucketFree(ret); return(NULL); } /* @@ -3739,7 +3746,10 @@ xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt, return(NULL); } } - xmlSchemaItemListAdd(mainSchema->includes, ret); + if (xmlSchemaItemListAdd(mainSchema->includes, ret) < 0) { + xmlSchemaBucketFree(ret); + return(NULL); + } } /* * Add to list of all buckets; this is used for lookup @@ -3758,8 +3768,7 @@ xmlSchemaAddItemSize(xmlSchemaItemListPtr *list, int initialSize, void *item) if (*list == NULL) return(-1); } - xmlSchemaItemListAddSize(*list, initialSize, item); - return(0); + return(xmlSchemaItemListAddSize(*list, initialSize, item)); } /** @@ -3797,6 +3806,8 @@ xmlSchemaFreeNotation(xmlSchemaNotationPtr nota) { if (nota == NULL) return; + if (nota->annot != NULL) + xmlSchemaFreeAnnot(nota->annot); xmlFree(nota); } @@ -4161,13 +4172,8 @@ xmlSchemaComponentListFree(xmlSchemaItemListPtr list) case XML_SCHEMA_EXTRA_QNAMEREF: xmlSchemaFreeQNameRef((xmlSchemaQNameRefPtr) item); break; - default: { + default: /* TODO: This should never be hit. */ - xmlSchemaPSimpleInternalErr(NULL, - "Internal error: xmlSchemaComponentListFree, " - "unexpected component type '%s'\n", - (const xmlChar *) WXS_ITEM_TYPE_NAME(item)); - } break; } } @@ -4186,9 +4192,6 @@ xmlSchemaFree(xmlSchemaPtr schema) { if (schema == NULL) return; - /* @volatiles is not used anymore :-/ */ - if (schema->volatiles != NULL) - TODO /* * Note that those slots are not responsible for freeing * schema components anymore; this will now be done by @@ -4606,83 +4609,6 @@ xmlSchemaDump(FILE * output, xmlSchemaPtr schema) xmlHashScanFull(schema->elemDecl, 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 */ /************************************************************************ @@ -4757,6 +4683,8 @@ xmlSchemaGetNodeContent(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) val = xmlStrdup((xmlChar *)""); ret = xmlDictLookup(ctxt->dict, val, -1); xmlFree(val); + if (ret == NULL) + xmlSchemaPErrMemory(ctxt); return(ret); } @@ -4836,15 +4764,6 @@ xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, 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); } @@ -4883,15 +4802,6 @@ xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name, } 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); } @@ -4917,15 +4827,6 @@ xmlSchemaGetAttributeDecl(xmlSchemaPtr schema, const xmlChar * name, 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); } @@ -4957,15 +4858,6 @@ exit: 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); } @@ -4992,15 +4884,6 @@ xmlSchemaGetGroup(xmlSchemaPtr schema, const xmlChar * name, } 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); } @@ -5060,7 +4943,7 @@ xmlSchemaGetNamedComponent(xmlSchemaPtr schema, return ((xmlSchemaBasicItemPtr) xmlSchemaGetElem(schema, name, targetNs)); default: - TODO + /* TODO */ return (NULL); } } @@ -5214,7 +5097,7 @@ xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "add annotation", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaNotation)); @@ -5251,7 +5134,7 @@ xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttribute)); @@ -5291,7 +5174,7 @@ xmlSchemaAddAttributeUse(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaAttributeUsePtr) xmlMalloc(sizeof(xmlSchemaAttributeUse)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating attribute", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeUse)); @@ -5320,8 +5203,7 @@ xmlSchemaAddRedef(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaRedefPtr) xmlMalloc(sizeof(xmlSchemaRedef)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating redefinition info", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaRedef)); @@ -5365,7 +5247,7 @@ xmlSchemaAddAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating attribute group", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeGroup)); @@ -5414,7 +5296,7 @@ xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating element", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaElement)); @@ -5456,7 +5338,7 @@ xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating type", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaType)); @@ -5492,8 +5374,7 @@ xmlSchemaNewQNameRef(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaQNameRefPtr) xmlMalloc(sizeof(xmlSchemaQNameRef)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating QName reference item", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } ret->node = NULL; @@ -5517,8 +5398,7 @@ xmlSchemaAddAttributeUseProhib(xmlSchemaParserCtxtPtr pctxt) ret = (xmlSchemaAttributeUseProhibPtr) xmlMalloc(sizeof(xmlSchemaAttributeUseProhib)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating attribute use prohibition", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeUseProhib)); @@ -5554,8 +5434,7 @@ xmlSchemaAddModelGroup(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaModelGroupPtr) xmlMalloc(sizeof(xmlSchemaModelGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating model group component", - NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaModelGroup)); @@ -5590,14 +5469,10 @@ xmlSchemaAddParticle(xmlSchemaParserCtxtPtr ctxt, 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); + xmlSchemaPErrMemory(ctxt); return (NULL); } ret->type = XML_SCHEMA_TYPE_PARTICLE; @@ -5643,7 +5518,7 @@ xmlSchemaAddModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaModelGroupDefPtr) xmlMalloc(sizeof(xmlSchemaModelGroupDef)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "adding group", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaModelGroupDef)); @@ -5682,7 +5557,7 @@ xmlSchemaNewWildcardNsConstraint(xmlSchemaParserCtxtPtr ctxt) ret = (xmlSchemaWildcardNsPtr) xmlMalloc(sizeof(xmlSchemaWildcardNs)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "creating wildcard namespace constraint", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } ret->value = NULL; @@ -5702,8 +5577,7 @@ xmlSchemaAddIDC(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret = (xmlSchemaIDCPtr) xmlMalloc(sizeof(xmlSchemaIDC)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, - "allocating an identity-constraint definition", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaIDC)); @@ -5743,7 +5617,7 @@ xmlSchemaAddWildcard(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "adding wildcard", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaWildcard)); @@ -5784,8 +5658,7 @@ xmlSchemaSubstGroupAdd(xmlSchemaParserCtxtPtr pctxt, /* Create a new substitution group. */ ret = (xmlSchemaSubstGroupPtr) xmlMalloc(sizeof(xmlSchemaSubstGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating a substitution group container", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, sizeof(xmlSchemaSubstGroup)); @@ -6025,8 +5898,8 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) * NOTE: the IDness might have already be declared in the DTD */ if (attr->atype != XML_ATTRIBUTE_ID) { - xmlIDPtr res; xmlChar *strip; + int res; /* * TODO: Use xmlSchemaStrip here; it's not exported at this @@ -6037,8 +5910,10 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) xmlFree((xmlChar *) value); value = strip; } - res = xmlAddID(NULL, attr->doc, value, attr); - if (res == NULL) { + res = xmlAddIDSafe(attr, value); + if (res < 0) { + xmlSchemaPErrMemory(ctxt); + } else if (res == 0) { ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; xmlSchemaPSimpleTypeErr(ctxt, XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, @@ -6046,8 +5921,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) xmlSchemaGetBuiltInType(XML_SCHEMAS_ID), NULL, NULL, "Duplicate value '%s' of simple " "type 'xs:ID'", value, NULL); - } else - attr->atype = XML_ATTRIBUTE_ID; + } } } else if (ret > 0) { ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; @@ -6100,6 +5974,8 @@ xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, if (attr == NULL) return (def); val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (val == NULL) + return (def); if (xmlStrEqual(val, (const xmlChar *) "unbounded")) { if (max != UNBOUNDED) { @@ -6174,6 +6050,8 @@ xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, if (attr == NULL) return (def); val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (val == NULL) + return (def); cur = val; while (IS_BLANK_CH(*cur)) cur++; @@ -6732,7 +6610,7 @@ xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, facet = xmlSchemaNewFacet(); if (facet == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating facet", node); + xmlSchemaPErrMemory(ctxt); return (NULL); } facet->node = node; @@ -6846,6 +6724,8 @@ xmlSchemaParseWildcardNs(xmlSchemaParserCtxtPtr ctxt, */ attr = xmlSchemaGetPropNode(node, "namespace"); ns = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (ns == NULL) + return (-1); if ((attr == NULL) || (xmlStrEqual(ns, BAD_CAST "##any"))) wildc->any = 1; else if (xmlStrEqual(ns, BAD_CAST "##other")) { @@ -8140,8 +8020,7 @@ xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, nsArray = (const xmlChar **) xmlMalloc( (count * 2 + 1) * sizeof(const xmlChar *)); if (nsArray == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a namespace array", - NULL); + xmlSchemaPErrMemory(ctxt); xmlFree(nsList); return (-1); } @@ -8184,7 +8063,7 @@ xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, return (annot); \ } \ cur = item->annot; \ - if (cur->next != NULL) { \ + while (cur->next != NULL) { \ cur = cur->next; \ } \ cur->next = annot; @@ -8328,9 +8207,7 @@ xmlSchemaParseIDCSelectorAndField(xmlSchemaParserCtxtPtr ctxt, */ item = (xmlSchemaIDCSelectPtr) xmlMalloc(sizeof(xmlSchemaIDCSelect)); if (item == NULL) { - xmlSchemaPErrMemory(ctxt, - "allocating a 'selector' of an identity-constraint definition", - NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(item, 0, sizeof(xmlSchemaIDCSelect)); @@ -8994,6 +8871,8 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlSchemaQNameRefPtr ref; cur = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (cur == NULL) + return (-1); type->base = cur; do { while (IS_BLANK_CH(*cur)) @@ -9004,6 +8883,10 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if (end == cur) break; tmp = xmlStrndup(cur, end - cur); + if (tmp == NULL) { + xmlSchemaPErrMemory(ctxt); + return (-1); + } if (xmlSchemaPValAttrNodeQNameValue(ctxt, schema, NULL, attr, BAD_CAST tmp, &nsName, &localName) == 0) { /* @@ -9012,8 +8895,8 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (link == NULL) { - xmlSchemaPErrMemory(ctxt, "xmlSchemaParseUnion, " - "allocating a type link", NULL); + xmlSchemaPErrMemory(ctxt); + FREE_AND_NULL(tmp) return (-1); } link->type = NULL; @@ -9946,7 +9829,7 @@ xmlSchemaSchemaRelationCreate(void) ret = (xmlSchemaSchemaRelationPtr) xmlMalloc(sizeof(xmlSchemaSchemaRelation)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema relation", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, sizeof(xmlSchemaSchemaRelation)); @@ -10003,23 +9886,20 @@ xmlSchemaConstructionCtxtCreate(xmlDictPtr dict) ret = (xmlSchemaConstructionCtxtPtr) xmlMalloc(sizeof(xmlSchemaConstructionCtxt)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating schema construction context", NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaConstructionCtxt)); ret->buckets = xmlSchemaItemListCreate(); if (ret->buckets == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating list of schema buckets", NULL); + xmlSchemaPErrMemory(NULL); xmlFree(ret); return (NULL); } ret->pending = xmlSchemaItemListCreate(); if (ret->pending == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating list of pending global components", NULL); + xmlSchemaPErrMemory(NULL); xmlSchemaConstructionCtxtFree(ret); return (NULL); } @@ -10035,8 +9915,7 @@ xmlSchemaParserCtxtCreate(void) ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema parser context", - NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaParserCtxt)); @@ -10621,10 +10500,13 @@ doc_load: parserCtxt = xmlNewParserCtxt(); if (parserCtxt == NULL) { - xmlSchemaPErrMemory(NULL, "xmlSchemaGetDoc, " - "allocating a parser context", NULL); + xmlSchemaPErrMemory(NULL); goto exit_failure; } + + if (pctxt->serror != NULL) + xmlCtxtSetErrorHandler(parserCtxt, pctxt->serror, pctxt->errCtxt); + if ((pctxt->dict != NULL) && (parserCtxt->dict != NULL)) { /* * TODO: Do we have to burden the schema parser dict with all @@ -10660,7 +10542,7 @@ doc_load: * TODO: (2.2) is not supported. */ if (doc == NULL) { - xmlErrorPtr lerr; + const xmlError *lerr; lerr = xmlGetLastError(); /* * Check if this a parser error, or if the document could @@ -11149,17 +11031,6 @@ xmlSchemaParseIncludeOrRedefine(xmlSchemaParserCtxtPtr pctxt, * 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; } } @@ -11796,7 +11667,7 @@ xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, facetLink = (xmlSchemaFacetLinkPtr) xmlMalloc(sizeof(xmlSchemaFacetLink)); if (facetLink == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a facet link", NULL); + xmlSchemaPErrMemory(ctxt); xmlFree(facetLink); return (NULL); } @@ -13240,15 +13111,10 @@ xmlSchemaBuildContentModel(xmlSchemaTypePtr type, (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); + xmlSchemaPErrMemory(ctxt); return; } ctxt->state = xmlAutomataGetInitState(ctxt->am); @@ -13270,11 +13136,6 @@ xmlSchemaBuildContentModel(xmlSchemaTypePtr type, 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); @@ -13345,8 +13206,19 @@ xmlSchemaResolveElementReferences(xmlSchemaElementPtr elemDecl, * declaration `resolved` to by the `actual value` * of the substitutionGroup [attribute], if present" */ - if (elemDecl->subtypes == NULL) - elemDecl->subtypes = substHead->subtypes; + if (elemDecl->subtypes == NULL) { + if (substHead->subtypes == NULL) { + /* + * This can happen with self-referencing substitution + * groups. The cycle will be detected later, but we have + * to set subtypes to avoid null-pointer dereferences. + */ + elemDecl->subtypes = xmlSchemaGetBuiltInType( + XML_SCHEMAS_ANYTYPE); + } else { + elemDecl->subtypes = substHead->subtypes; + } + } } } /* @@ -13424,7 +13296,7 @@ xmlSchemaResolveUnionMemberTypes(xmlSchemaParserCtxtPtr ctxt, while (memberType != NULL) { link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (link == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a type link", NULL); + xmlSchemaPErrMemory(ctxt); return (-1); } link->type = memberType; @@ -14536,6 +14408,7 @@ xmlSchemaFixupTypeAttributeUses(xmlSchemaParserCtxtPtr pctxt, { PERROR_INT("xmlSchemaFixupTypeAttributeUses", "failed to expand attributes"); + return(-1); } if (pctxt->attrProhibs->nbItems != 0) prohibs = pctxt->attrProhibs; @@ -14546,6 +14419,7 @@ xmlSchemaFixupTypeAttributeUses(xmlSchemaParserCtxtPtr pctxt, { PERROR_INT("xmlSchemaFixupTypeAttributeUses", "failed to expand attributes"); + return(-1); } } } @@ -17863,8 +17737,7 @@ xmlSchemaDeriveAndValidateFacets(xmlSchemaParserCtxtPtr pctxt, link = (xmlSchemaFacetLinkPtr) xmlMalloc(sizeof(xmlSchemaFacetLink)); if (link == NULL) { - xmlSchemaPErrMemory(pctxt, - "deriving facets, creating a facet link", NULL); + xmlSchemaPErrMemory(pctxt); return (-1); } link->facet = cur->facet; @@ -17917,8 +17790,7 @@ xmlSchemaFinishMemberTypeDefinitionsProperty(xmlSchemaParserCtxtPtr pctxt, newLink = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (newLink == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating a type link", - NULL); + xmlSchemaPErrMemory(pctxt); return (-1); } newLink->type = subLink->type; @@ -18125,59 +17997,6 @@ xmlSchemaFixupSimpleTypeStageOne(xmlSchemaParserCtxtPtr pctxt, 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 */ @@ -18260,17 +18079,11 @@ xmlSchemaFixupSimpleTypeStageTwo(xmlSchemaParserCtxtPtr pctxt, 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); } @@ -18608,7 +18421,7 @@ xmlSchemaFixupComplexType(xmlSchemaParserCtxtPtr pctxt, "allowed to appear inside other model groups", NULL, NULL); - } else if (! dummySequence) { + } else if ((!dummySequence) && (baseType->subtypes != NULL)) { xmlSchemaTreeItemPtr effectiveContent = (xmlSchemaTreeItemPtr) type->subtypes; /* @@ -18692,9 +18505,6 @@ xmlSchemaFixupComplexType(xmlSchemaParserCtxtPtr pctxt, res = xmlSchemaCheckCTComponent(pctxt, type); HFAILURE HERROR -#ifdef DEBUG_TYPE - xmlSchemaDebugFixedType(pctxt, type); -#endif if (olderrs != pctxt->nberrors) return(pctxt->err); else @@ -18702,16 +18512,10 @@ xmlSchemaFixupComplexType(xmlSchemaParserCtxtPtr pctxt, 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); } @@ -18866,7 +18670,7 @@ xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, PERROR_INT("xmlSchemaCheckFacet", "value was not computed"); } - TODO + /* TODO */ } break; } @@ -19946,7 +19750,8 @@ xmlSchemaCheckElemSubstGroup(xmlSchemaParserCtxtPtr ctxt, /* * The set of all {derivation method}s involved in the derivation */ - while ((type != NULL) && (type != headType)) { + while ((type != NULL) && (type != headType) && + (type != type->baseType)) { if ((WXS_IS_EXTENSION(type)) && ((methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0)) methSet |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION; @@ -21432,7 +21237,8 @@ xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt) * the API; i.e. not automatically by the validated instance document. */ - xmlSchemaInitTypes(); + if (xmlSchemaInitTypes() < 0) + return (NULL); if (ctxt == NULL) return (NULL); @@ -21452,7 +21258,7 @@ xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt) if (ctxt->constructor == NULL) { ctxt->constructor = xmlSchemaConstructionCtxtCreate(ctxt->dict); if (ctxt->constructor == NULL) - return(NULL); + goto exit_failure; /* Take ownership of the constructor to be able to free it. */ ctxt->ownsConstructor = 1; } @@ -21541,6 +21347,8 @@ exit_failure: * @warn: the warning callback * @ctx: contextual data for the callbacks * + * DEPRECATED: Use xmlSchemaSetParserStructuredErrors. + * * Set the callback functions used to handle errors for a validation context */ void @@ -21861,7 +21669,6 @@ xmlSchemaAssembleByXSI(xmlSchemaValidCtxtPtr vctxt) { const xmlChar *cur, *end; const xmlChar *nsname = NULL, *location; - int count = 0; int ret = 0; xmlSchemaAttrInfoPtr iattr; @@ -21896,7 +21703,7 @@ xmlSchemaAssembleByXSI(xmlSchemaValidCtxtPtr vctxt) end++; if (end == cur) break; - count++; /* TODO: Don't use the schema's dict. */ + /* TODO: Don't use the schema's dict. */ nsname = xmlDictLookup(vctxt->schema->dict, cur, end - cur); cur = end; } @@ -21923,7 +21730,7 @@ xmlSchemaAssembleByXSI(xmlSchemaValidCtxtPtr vctxt) } break; } - count++; /* TODO: Don't use the schema's dict. */ + /* TODO: Don't use the schema's dict. */ location = xmlDictLookup(vctxt->schema->dict, cur, end - cur); cur = end; ret = xmlSchemaAssembleByLocation(vctxt, vctxt->schema, @@ -22118,9 +21925,7 @@ xmlSchemaAugmentIDC(void *payload, void *data, aidc = (xmlSchemaIDCAugPtr) xmlMalloc(sizeof(xmlSchemaIDCAug)); if (aidc == NULL) { - xmlSchemaVErrMemory(vctxt, - "xmlSchemaAugmentIDC: allocating an augmented IDC definition", - NULL); + xmlSchemaVErrMemory(vctxt); return; } aidc->keyrefDepth = -1; @@ -22172,8 +21977,7 @@ xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef) ret = (xmlSchemaPSVIIDCBindingPtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCBinding)); if (ret == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating a PSVI IDC binding item", NULL); + xmlSchemaVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaPSVIIDCBinding)); @@ -22203,8 +22007,7 @@ xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(20 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (vctxt->idcNodes == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the IDC node table item list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } vctxt->sizeIdcNodes = 20; @@ -22214,8 +22017,7 @@ xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, xmlRealloc(vctxt->idcNodes, vctxt->sizeIdcNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (vctxt->idcNodes == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the IDC node table item list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } } @@ -22244,8 +22046,7 @@ xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc(40 * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (vctxt->idcKeys == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the IDC key storage list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } vctxt->sizeIdcKeys = 40; @@ -22255,8 +22056,7 @@ xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, xmlRealloc(vctxt->idcKeys, vctxt->sizeIdcKeys * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (vctxt->idcKeys == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the IDC key storage list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } } @@ -22283,8 +22083,7 @@ xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind, bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (bind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of IDC node-table items", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } else if (bind->sizeNodes <= bind->nbNodes) { @@ -22293,8 +22092,7 @@ xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind, xmlRealloc(bind->nodeTable, bind->sizeNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (bind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating an array of IDC node-table items", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } @@ -22554,8 +22352,7 @@ xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt, */ sto = (xmlSchemaIDCStateObjPtr) xmlMalloc(sizeof(xmlSchemaIDCStateObj)); if (sto == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC state object", NULL); + xmlSchemaVErrMemory(NULL); return (-1); } memset(sto, 0, sizeof(xmlSchemaIDCStateObj)); @@ -22589,10 +22386,6 @@ xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt, sto->sel = sel; sto->nbHistory = 0; -#ifdef DEBUG_IDC - xmlGenericError(xmlGenericErrorContext, "IDC: STO push '%s'\n", - sto->sel->xpath); -#endif return (0); } @@ -22618,30 +22411,12 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, 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); @@ -22659,18 +22434,13 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, /* * 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); + xmlSchemaVErrMemory(NULL); return(-1); } sto->sizeHistory = 5; @@ -22679,28 +22449,18 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, sto->history = (int *) xmlRealloc(sto->history, sto->sizeHistory * sizeof(int)); if (sto->history == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating the state object history", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } 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, @@ -22712,10 +22472,6 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, /* * 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. @@ -22848,16 +22604,6 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, 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. */ @@ -22868,10 +22614,6 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, "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; @@ -22975,9 +22717,7 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, xmlMalloc(matcher->sizeKeySeqs * sizeof(xmlSchemaPSVIIDCKeyPtr *)); if (matcher->keySeqs == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of key-sequences", - NULL); + xmlSchemaVErrMemory(NULL); return(-1); } memset(matcher->keySeqs, 0, @@ -22986,15 +22726,13 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, } else if (pos >= matcher->sizeKeySeqs) { int i = matcher->sizeKeySeqs; - matcher->sizeKeySeqs *= 2; + matcher->sizeKeySeqs = pos * 2; matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **) xmlRealloc(matcher->keySeqs, matcher->sizeKeySeqs * sizeof(xmlSchemaPSVIIDCKeyPtr *)); if (matcher->keySeqs == NULL) { - xmlSchemaVErrMemory(NULL, - "reallocating an array of key-sequences", - NULL); + xmlSchemaVErrMemory(NULL); return (-1); } /* @@ -23044,8 +22782,7 @@ create_sequence: matcher->aidc->def->nbFields * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (keySeq == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC key-sequence", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } memset(keySeq, 0, matcher->aidc->def->nbFields * @@ -23059,8 +22796,7 @@ create_key: key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCKey)); if (key == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating a IDC key", NULL); + xmlSchemaVErrMemory(NULL); xmlFree(keySeq); matcher->keySeqs[pos] = NULL; return(-1); @@ -23222,8 +22958,7 @@ create_key: ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCNode)); if (ntItem == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC node-table item", NULL); + xmlSchemaVErrMemory(NULL); xmlFree(*keySeq); *keySeq = NULL; return(-1); @@ -23330,10 +23065,6 @@ 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 " @@ -23378,16 +23109,6 @@ xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt, 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"); @@ -23456,8 +23177,7 @@ xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt, matcher = (xmlSchemaIDCMatcherPtr) xmlMalloc(sizeof(xmlSchemaIDCMatcher)); if (matcher == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating an IDC matcher", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } memset(matcher, 0, sizeof(xmlSchemaIDCMatcher)); @@ -23472,9 +23192,6 @@ xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt, 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. */ @@ -23872,8 +23589,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating IDC list of node-table items", NULL); + xmlSchemaVErrMemory(NULL); goto internal_error; } parBind->sizeNodes = 1; @@ -23883,8 +23599,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(parBind->nodeTable, parBind->sizeNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating IDC list of node-table items", NULL); + xmlSchemaVErrMemory(NULL); goto internal_error; } } @@ -23937,9 +23652,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) xmlMalloc(bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of IDC node-table " - "items", NULL); + xmlSchemaVErrMemory(NULL); xmlSchemaIDCFreeBinding(parBind); goto internal_error; } @@ -24148,8 +23861,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) xmlMalloc(sizeof(xmlSchemaAttrInfoPtr)); vctxt->sizeAttrInfos = 1; if (vctxt->attrInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating attribute info list", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } } else if (vctxt->sizeAttrInfos <= vctxt->nbAttrInfos) { @@ -24158,8 +23870,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(vctxt->attrInfos, vctxt->sizeAttrInfos * sizeof(xmlSchemaAttrInfoPtr)); if (vctxt->attrInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating attribute info list", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } } else { @@ -24178,7 +23889,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) iattr = (xmlSchemaAttrInfoPtr) xmlMalloc(sizeof(xmlSchemaAttrInfo)); if (iattr == NULL) { - xmlSchemaVErrMemory(vctxt, "creating new attribute info", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } memset(iattr, 0, sizeof(xmlSchemaAttrInfo)); @@ -24329,8 +24040,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) vctxt->elemInfos = (xmlSchemaNodeInfoPtr *) xmlMalloc(10 * sizeof(xmlSchemaNodeInfoPtr)); if (vctxt->elemInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the element info array", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } memset(vctxt->elemInfos, 0, 10 * sizeof(xmlSchemaNodeInfoPtr)); @@ -24343,8 +24053,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(vctxt->elemInfos, vctxt->sizeElemInfos * sizeof(xmlSchemaNodeInfoPtr)); if (vctxt->elemInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the element info array", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } /* @@ -24360,8 +24069,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) info = (xmlSchemaNodeInfoPtr) xmlMalloc(sizeof(xmlSchemaNodeInfo)); if (info == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating an element info", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } vctxt->elemInfos[vctxt->depth] = info; @@ -24824,7 +24532,6 @@ xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt, /* * Validation via a public API is not implemented yet. */ - TODO goto internal_error; } if (ret != 0) { @@ -25637,7 +25344,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) if (wildIDs != 0) { /* VAL TODO */ iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID; - TODO continue; } wildIDs++; @@ -25655,7 +25361,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) XML_SCHEMAS_ID)) { /* URGENT VAL TODO: implement */ iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID; - TODO break; } } @@ -25791,7 +25496,7 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) ns = xmlSearchNsByHref(defAttrOwnerElem->doc, defAttrOwnerElem, iattr->nsName); if (ns == NULL) { - xmlChar prefix[12]; + xmlChar prefix[13]; int counter = 0; /* @@ -25799,7 +25504,7 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) * root node if no namespace declaration is in scope. */ do { - snprintf((char *) prefix, 12, "p%d", counter++); + snprintf((char *) prefix, 13, "p%d", counter++); ns = xmlSearchNs(defAttrOwnerElem->doc, defAttrOwnerElem, BAD_CAST prefix); if (counter > 1000) { @@ -25909,14 +25614,12 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) */ if (iattr->val == NULL) { /* VAL TODO: A value was not precomputed. */ - TODO goto eval_idcs; } if ((iattr->use != NULL) && (iattr->use->defValue != NULL)) { if (iattr->use->defVal == NULL) { /* VAL TODO: A default value was not precomputed. */ - TODO goto eval_idcs; } iattr->vcValue = iattr->use->defValue; @@ -25931,7 +25634,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) } else { if (iattr->decl->defVal == NULL) { /* VAL TODO: A default value was not precomputed. */ - TODO goto eval_idcs; } iattr->vcValue = iattr->decl->defValue; @@ -26185,25 +25887,6 @@ xmlSchemaVContentModelCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, xmlSchemaElementPtr item = (xmlSchemaElementPtr) transdata; xmlSchemaNodeInfoPtr inode = (xmlSchemaNodeInfoPtr) inputdata; 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 @@ -26294,10 +25977,6 @@ xmlSchemaValidatorPopElem(xmlSchemaValidCtxtPtr vctxt) "failed to create a regex context"); goto internal_error; } -#ifdef DEBUG_AUTOMATA - xmlGenericError(xmlGenericErrorContext, - "AUTOMATON create on '%s'\n", inode->localName); -#endif } /* @@ -26305,11 +25984,6 @@ xmlSchemaValidatorPopElem(xmlSchemaValidCtxtPtr vctxt) */ if (INODE_NILLED(inode)) { ret = 0; -#ifdef DEBUG_AUTOMATA - xmlGenericError(xmlGenericErrorContext, - "AUTOMATON succeeded on nilled '%s'\n", - inode->localName); -#endif goto skip_nilled; } @@ -26331,21 +26005,11 @@ xmlSchemaValidatorPopElem(xmlSchemaValidCtxtPtr 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 } } @@ -26648,12 +26312,6 @@ end_elem: * 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)) { @@ -26845,10 +26503,6 @@ xmlSchemaValidateChildElem(xmlSchemaValidCtxtPtr vctxt) return (-1); } pielem->regexCtxt = regexCtxt; -#ifdef DEBUG_AUTOMATA - xmlGenericError(xmlGenericErrorContext, "AUTOMATA create on '%s'\n", - pielem->localName); -#endif } /* @@ -26863,16 +26517,6 @@ xmlSchemaValidateChildElem(xmlSchemaValidCtxtPtr vctxt) 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()"); @@ -27514,7 +27158,6 @@ xmlSchemaSAXHandleReference(void *ctx ATTRIBUTE_UNUSED, if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) return; /* SAX VAL TODO: What to do here? */ - TODO } static void @@ -27575,9 +27218,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, (const xmlChar **) xmlMalloc(10 * sizeof(const xmlChar *)); if (ielem->nsBindings == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating namespace bindings for SAX validation", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } ielem->nbNsBindings = 0; @@ -27589,9 +27230,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, (void *) ielem->nsBindings, ielem->sizeNsBindings * 2 * sizeof(const xmlChar *)); if (ielem->nsBindings == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating namespace bindings for SAX validation", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } } @@ -27629,9 +27268,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, valueLen = attributes[j+4] - attributes[j+3]; value = xmlMallocAtomic(valueLen + 1); if (value == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating string for decoded attribute", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } for (k = 0, l = 0; k < valueLen; l++) { @@ -27748,7 +27385,7 @@ xmlSchemaNewValidCtxt(xmlSchemaPtr schema) ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt)); if (ret == NULL) { - xmlSchemaVErrMemory(NULL, "allocating validation context", NULL); + xmlSchemaVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaValidCtxt)); @@ -28016,6 +27653,8 @@ xmlSchemaIsValid(xmlSchemaValidCtxtPtr ctxt) * @warn: the warning function * @ctx: the functions context * + * DEPRECATED: Use xmlSchemaSetValidStructuredErrors. + * * Set the error and warning callback information */ void @@ -28691,28 +28330,28 @@ commentSplit(void *ctx, const xmlChar *value) * Varargs error callbacks to the user application, harder ... */ -static void XMLCDECL +static void warningSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->warning != NULL)) { - TODO + /* TODO */ } } -static void XMLCDECL +static void errorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->error != NULL)) { - TODO + /* TODO */ } } -static void XMLCDECL +static void fatalErrorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->fatalError != NULL)) { - TODO + /* TODO */ } } @@ -29042,6 +28681,55 @@ xmlSchemaValidateStreamLocator(void *ctx, const char **file, return(-1); } +/** + * xmlSchemaValidateStreamInternal: + * @ctxt: a schema validation context + * @pctxt: a parser context + * + * Returns 0 if the document is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +static int +xmlSchemaValidateStreamInternal(xmlSchemaValidCtxtPtr ctxt, + xmlParserCtxtPtr pctxt) { + xmlSchemaSAXPlugPtr plug = NULL; + int ret; + + pctxt->linenumbers = 1; + xmlSchemaValidateSetLocator(ctxt, xmlSchemaValidateStreamLocator, pctxt); + + ctxt->parserCtxt = pctxt; + ctxt->input = pctxt->input->buf; + + /* + * Plug the validation and launch the parsing + */ + plug = xmlSchemaSAXPlug(ctxt, &(pctxt->sax), &(pctxt->userData)); + if (plug == NULL) { + ret = -1; + goto done; + } + ctxt->input = pctxt->input->buf; + 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); + } + return (ret); +} + /** * xmlSchemaValidateStream: * @ctxt: a schema validation context @@ -29062,8 +28750,6 @@ 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; @@ -29074,18 +28760,22 @@ xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, /* * prepare the parser */ - pctxt = xmlNewParserCtxt(); - if (pctxt == NULL) - return (-1); - old_sax = pctxt->sax; - pctxt->sax = sax; - pctxt->userData = user_data; + if (sax != NULL) { + pctxt = xmlNewSAXParserCtxt(sax, user_data); + if (pctxt == NULL) + return (-1); + } else { + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return (-1); + /* We really want pctxt->sax to be NULL here. */ + xmlFree(pctxt->sax); + pctxt->sax = NULL; + } #if 0 if (options) xmlCtxtUseOptions(pctxt, options); #endif - pctxt->linenumbers = 1; - xmlSchemaValidateSetLocator(ctxt, xmlSchemaValidateStreamLocator, pctxt); inputStream = xmlNewIOInputStream(pctxt, input, enc);; if (inputStream == NULL) { @@ -29093,39 +28783,14 @@ xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, 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; - } + ret = xmlSchemaValidateStreamInternal(ctxt, pctxt); 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); @@ -29149,17 +28814,19 @@ xmlSchemaValidateFile(xmlSchemaValidCtxtPtr ctxt, int options ATTRIBUTE_UNUSED) { int ret; - xmlParserInputBufferPtr input; + xmlParserCtxtPtr pctxt = NULL; if ((ctxt == NULL) || (filename == NULL)) return (-1); - input = xmlParserInputBufferCreateFilename(filename, - XML_CHAR_ENCODING_NONE); - if (input == NULL) + pctxt = xmlCreateURLParserCtxt(filename, 0); + if (pctxt == NULL) return (-1); - ret = xmlSchemaValidateStream(ctxt, input, XML_CHAR_ENCODING_NONE, - NULL, NULL); + /* We really want pctxt->sax to be NULL here. */ + xmlFree(pctxt->sax); + pctxt->sax = NULL; + ret = xmlSchemaValidateStreamInternal(ctxt, pctxt); + xmlFreeParserCtxt(pctxt); return (ret); } diff --git a/xmlschemastypes.c b/xmlschemastypes.c index 26c033d411d..5c6db292725 100644 --- a/xmlschemastypes.c +++ b/xmlschemastypes.c @@ -17,6 +17,7 @@ #ifdef LIBXML_SCHEMAS_ENABLED +#include #include #include #include @@ -25,15 +26,15 @@ #include #include #include -#include #include #include +#include #include #include #include -#define DEBUG +#include "private/error.h" #ifndef LIBXML_XPATH_ENABLED extern double xmlXPathNAN; @@ -41,11 +42,6 @@ extern double xmlXPathPINF; extern double xmlXPathNINF; #endif -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - #define XML_SCHEMAS_NAMESPACE_NAME \ (const xmlChar *)"http://www.w3.org/2001/XMLSchema" @@ -82,15 +78,11 @@ struct _xmlSchemaValDuration { typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal; typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr; -struct _xmlSchemaValDecimal { - /* would use long long but not portable */ - unsigned long lo; - unsigned long mi; - unsigned long hi; - unsigned int extra; - unsigned int sign:1; - unsigned int frac:7; - unsigned int total:8; +struct _xmlSchemaValDecimal +{ + xmlChar *str; + unsigned integralPlaces; + unsigned fractionalPlaces; }; typedef struct _xmlSchemaValQName xmlSchemaValQName; @@ -200,9 +192,9 @@ static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL; * Handle an out of memory condition */ static void -xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra) +xmlSchemaTypeErrMemory(void) { - __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_DATATYPE, NULL); } /************************************************************************ @@ -236,6 +228,8 @@ static xmlSchemaFacetPtr xmlSchemaNewMinLengthFacet(int value) { xmlSchemaFacetPtr ret; + size_t bufsize; + xmlSchemaValDecimal *decimal; ret = xmlSchemaNewFacet(); if (ret == NULL) { @@ -245,9 +239,19 @@ xmlSchemaNewMinLengthFacet(int value) ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER); if (ret->val == NULL) { xmlFree(ret); - return(NULL); + return(NULL); + } + bufsize = snprintf(NULL, 0, "%+d.0", value) + 1; + decimal = &ret->val->value.decimal; + decimal->str = xmlMalloc(bufsize); + if (decimal->str == NULL) + { + xmlSchemaFreeFacet(ret); + return NULL; } - ret->val->value.decimal.lo = value; + snprintf((char *)decimal->str, bufsize, "%+d.0", value); + decimal->integralPlaces = bufsize - 4; + decimal->fractionalPlaces = 1; return (ret); } @@ -265,7 +269,7 @@ xmlSchemaInitBasicType(const char *name, xmlSchemaValType type, ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { - xmlSchemaTypeErrMemory(NULL, "could not initialize basic types"); + xmlSchemaTypeErrMemory(); return(NULL); } memset(ret, 0, sizeof(xmlSchemaType)); @@ -326,6 +330,90 @@ xmlSchemaInitBasicType(const char *name, xmlSchemaValType type, return(ret); } +static const xmlChar * +xmlSchemaValDecimalGetFractionalPart(const xmlSchemaValDecimal *decimal) +{ + /* 2 = sign+dot */ + return decimal->str+2+decimal->integralPlaces; +} + +static int +xmlSchemaValDecimalIsInteger(const xmlSchemaValDecimal *decimal) +{ + return decimal->fractionalPlaces == 1 && xmlSchemaValDecimalGetFractionalPart(decimal)[0] == '0'; +} + +static unsigned long +xmlSchemaValDecimalGetSignificantDigitCount(const xmlSchemaValDecimal *decimal) +{ + unsigned fractionalPlaces = xmlSchemaValDecimalIsInteger(decimal) ? 0 : decimal->fractionalPlaces; + unsigned integralPlaces = decimal->integralPlaces; + if(integralPlaces == 1 && decimal->str[1] == '0') + { + integralPlaces = 0; + } + if(integralPlaces+fractionalPlaces == 0) + { + /* 0, but that's still 1 significant digit */ + return 1; + } + return integralPlaces+fractionalPlaces; +} + +/** + * @brief Compares two decimals + * + * @param lhs + * @param rhs + * @return positive value if lhs > rhs, negative if lhs < rhs, or 0 if lhs == rhs + */ +static int xmlSchemaValDecimalCompare(const xmlSchemaValDecimal *lhs, const xmlSchemaValDecimal *rhs) +{ + int sign = 1; + /* may be +0 and -0 for some reason, handle */ + if(strcmp((const char*)lhs->str+1, "0.0") == 0 && + strcmp((const char*)rhs->str+1, "0.0") == 0) + { + return 0; + } + /* first take care of sign */ + if(lhs->str[0] != rhs->str[0]) + { + /* ASCII- > ASCII+ */ + return rhs->str[0]-lhs->str[0]; + } + /* signs are equal, but if negative the comparison must be reversed */ + if(lhs->str[0] == '-') + { + sign = -1; + } + /* internal representation never contains leading zeroes, longer decimal representation = larger number */ + if(lhs->integralPlaces != rhs->integralPlaces) + { + return ((int)lhs->integralPlaces-(int)rhs->integralPlaces)*sign; + } + /* same length, only digits => lexicographical sorting == numerical sorting. + If integral parts are equal it will compare compare fractional parts. Again, lexicographical is good enough, + length doesn't matter. We'll be starting from 0.1, always comparing like to like, and NULL < '0' + If one is shorter and is equal until end, it must be smaller, since there are no trailing zeroes + and the longer number must therefore have at least one non-zero digit after the other has ended. + +1 to skip the sign + */ + return strcmp((const char*)lhs->str+1, (const char*)rhs->str+1)*sign; +} + +static int xmlSchemaValDecimalCompareWithInteger(const xmlSchemaValDecimal *lhs, long rhs) +{ + /* can handle integers up to 128 bits, should be good for a while */ + char buf[43]; + xmlSchemaValDecimal tmpVal; + /* 3 = sign+dot+0+NULL */ + tmpVal.integralPlaces = snprintf(buf, sizeof(buf), "%+ld.0", rhs)-3; + tmpVal.str = (xmlChar*)buf; + tmpVal.fractionalPlaces = 1; + return xmlSchemaValDecimalCompare(lhs, &tmpVal); +} + /* * WARNING: Those type reside normally in xmlschemas.c but are * redefined here locally in oder of being able to use them for xs:anyType- @@ -373,7 +461,7 @@ xmlSchemaAddParticle(void) ret = (xmlSchemaParticlePtr) xmlMalloc(sizeof(xmlSchemaParticle)); if (ret == NULL) { - xmlSchemaTypeErrMemory(NULL, "allocating particle component"); + xmlSchemaTypeErrMemory(); return (NULL); } memset(ret, 0, sizeof(xmlSchemaParticle)); @@ -383,18 +471,61 @@ xmlSchemaAddParticle(void) return (ret); } +static void +xmlSchemaFreeTypeEntry(void *type, const xmlChar *name ATTRIBUTE_UNUSED) { + xmlSchemaFreeType((xmlSchemaTypePtr) type); +} + +/** + * xmlSchemaCleanupTypesInternal: + * + * Cleanup the default XML Schemas type library + */ +static void +xmlSchemaCleanupTypesInternal(void) { + xmlSchemaParticlePtr particle; + + /* + * Free xs:anyType. + */ + if (xmlSchemaTypeAnyTypeDef != NULL) { + /* 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; + xmlSchemaTypeAnyTypeDef = NULL; + } + + xmlHashFree(xmlSchemaTypesBank, xmlSchemaFreeTypeEntry); + xmlSchemaTypesBank = NULL; + /* Note that the xmlSchemaType*Def pointers aren't set to NULL. */ +} + /* * xmlSchemaInitTypes: * * Initialize the default XML Schemas type library + * + * Returns 0 on success, -1 on error. */ -void +int xmlSchemaInitTypes(void) { if (xmlSchemaTypesInitialized != 0) - return; + return (0); xmlSchemaTypesBank = xmlHashCreate(40); - + if (xmlSchemaTypesBank == NULL) { + xmlSchemaTypeErrMemory(); + goto error; + } /* * 3.4.7 Built-in Complex Type Definition @@ -402,6 +533,8 @@ xmlSchemaInitTypes(void) xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType", XML_SCHEMAS_ANYTYPE, NULL); + if (xmlSchemaTypeAnyTypeDef == NULL) + goto error; xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef; xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED; /* @@ -415,14 +548,14 @@ xmlSchemaInitTypes(void) /* First particle. */ particle = xmlSchemaAddParticle(); if (particle == NULL) - return; + goto error; xmlSchemaTypeAnyTypeDef->subtypes = (xmlSchemaTypePtr) particle; /* Sequence model group. */ sequence = (xmlSchemaModelGroupPtr) xmlMalloc(sizeof(xmlSchemaModelGroup)); if (sequence == NULL) { - xmlSchemaTypeErrMemory(NULL, "allocating model group component"); - return; + xmlSchemaTypeErrMemory(); + goto error; } memset(sequence, 0, sizeof(xmlSchemaModelGroup)); sequence->type = XML_SCHEMA_TYPE_SEQUENCE; @@ -430,15 +563,15 @@ xmlSchemaInitTypes(void) /* Second particle. */ particle = xmlSchemaAddParticle(); if (particle == NULL) - return; + goto error; 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; + xmlSchemaTypeErrMemory(); + goto error; } memset(wild, 0, sizeof(xmlSchemaWildcard)); wild->type = XML_SCHEMA_TYPE_ANY; @@ -450,9 +583,8 @@ xmlSchemaInitTypes(void) */ wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); if (wild == NULL) { - xmlSchemaTypeErrMemory(NULL, "could not create an attribute " - "wildcard on anyType"); - return; + xmlSchemaTypeErrMemory(); + goto error; } memset(wild, 0, sizeof(xmlSchemaWildcard)); wild->any = 1; @@ -462,66 +594,106 @@ xmlSchemaInitTypes(void) xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType", XML_SCHEMAS_ANYSIMPLETYPE, xmlSchemaTypeAnyTypeDef); + if (xmlSchemaTypeAnySimpleTypeDef == NULL) + goto error; /* * primitive datatypes */ xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string", XML_SCHEMAS_STRING, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeStringDef == NULL) + goto error; xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal", XML_SCHEMAS_DECIMAL, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeDecimalDef == NULL) + goto error; xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date", XML_SCHEMAS_DATE, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeDateDef == NULL) + goto error; xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime", XML_SCHEMAS_DATETIME, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeDatetimeDef == NULL) + goto error; xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time", XML_SCHEMAS_TIME, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeTimeDef == NULL) + goto error; xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear", XML_SCHEMAS_GYEAR, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeGYearDef == NULL) + goto error; xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth", XML_SCHEMAS_GYEARMONTH, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeGYearMonthDef == NULL) + goto error; xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth", XML_SCHEMAS_GMONTH, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeGMonthDef == NULL) + goto error; xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay", XML_SCHEMAS_GMONTHDAY, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeGMonthDayDef == NULL) + goto error; xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay", XML_SCHEMAS_GDAY, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeGDayDef == NULL) + goto error; xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration", XML_SCHEMAS_DURATION, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeDurationDef == NULL) + goto error; xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float", XML_SCHEMAS_FLOAT, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeFloatDef == NULL) + goto error; xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double", XML_SCHEMAS_DOUBLE, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeDoubleDef == NULL) + goto error; xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean", XML_SCHEMAS_BOOLEAN, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeBooleanDef == NULL) + goto error; xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI", XML_SCHEMAS_ANYURI, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeAnyURIDef == NULL) + goto error; xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary", XML_SCHEMAS_HEXBINARY, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeHexBinaryDef == NULL) + goto error; xmlSchemaTypeBase64BinaryDef = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeBase64BinaryDef == NULL) + goto error; xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION", XML_SCHEMAS_NOTATION, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeNotationDef == NULL) + goto error; xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName", XML_SCHEMAS_QNAME, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeQNameDef == NULL) + goto error; /* * derived datatypes @@ -529,69 +701,113 @@ xmlSchemaInitTypes(void) xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer", XML_SCHEMAS_INTEGER, xmlSchemaTypeDecimalDef); + if (xmlSchemaTypeIntegerDef == NULL) + goto error; xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger", XML_SCHEMAS_NPINTEGER, xmlSchemaTypeIntegerDef); + if (xmlSchemaTypeNonPositiveIntegerDef == NULL) + goto error; xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER, xmlSchemaTypeNonPositiveIntegerDef); + if (xmlSchemaTypeNegativeIntegerDef == NULL) + goto error; xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG, xmlSchemaTypeIntegerDef); + if (xmlSchemaTypeLongDef == NULL) + goto error; xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT, xmlSchemaTypeLongDef); + if (xmlSchemaTypeIntDef == NULL) + goto error; xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short", XML_SCHEMAS_SHORT, xmlSchemaTypeIntDef); + if (xmlSchemaTypeShortDef == NULL) + goto error; xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte", XML_SCHEMAS_BYTE, xmlSchemaTypeShortDef); + if (xmlSchemaTypeByteDef == NULL) + goto error; xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger", XML_SCHEMAS_NNINTEGER, xmlSchemaTypeIntegerDef); + if (xmlSchemaTypeNonNegativeIntegerDef == NULL) + goto error; xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG, xmlSchemaTypeNonNegativeIntegerDef); + if (xmlSchemaTypeUnsignedLongDef == NULL) + goto error; xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT, xmlSchemaTypeUnsignedLongDef); + if (xmlSchemaTypeUnsignedIntDef == NULL) + goto error; xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT, xmlSchemaTypeUnsignedIntDef); + if (xmlSchemaTypeUnsignedShortDef == NULL) + goto error; xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE, xmlSchemaTypeUnsignedShortDef); + if (xmlSchemaTypeUnsignedByteDef == NULL) + goto error; xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER, xmlSchemaTypeNonNegativeIntegerDef); + if (xmlSchemaTypePositiveIntegerDef == NULL) + goto error; xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString", XML_SCHEMAS_NORMSTRING, xmlSchemaTypeStringDef); + if (xmlSchemaTypeNormStringDef == NULL) + goto error; xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token", XML_SCHEMAS_TOKEN, xmlSchemaTypeNormStringDef); + if (xmlSchemaTypeTokenDef == NULL) + goto error; xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language", XML_SCHEMAS_LANGUAGE, xmlSchemaTypeTokenDef); + if (xmlSchemaTypeLanguageDef == NULL) + goto error; xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name", XML_SCHEMAS_NAME, xmlSchemaTypeTokenDef); + if (xmlSchemaTypeNameDef == NULL) + goto error; xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN", XML_SCHEMAS_NMTOKEN, xmlSchemaTypeTokenDef); + if (xmlSchemaTypeNmtokenDef == NULL) + goto error; xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName", XML_SCHEMAS_NCNAME, xmlSchemaTypeNameDef); + if (xmlSchemaTypeNCNameDef == NULL) + goto error; xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID, xmlSchemaTypeNCNameDef); + if (xmlSchemaTypeIdDef == NULL) + goto error; xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF", XML_SCHEMAS_IDREF, xmlSchemaTypeNCNameDef); + if (xmlSchemaTypeIdrefDef == NULL) + goto error; xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY", XML_SCHEMAS_ENTITY, xmlSchemaTypeNCNameDef); + if (xmlSchemaTypeEntityDef == NULL) + goto error; /* * Derived list types. */ @@ -599,25 +815,31 @@ xmlSchemaInitTypes(void) xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES", XML_SCHEMAS_ENTITIES, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeEntitiesDef == NULL) + goto error; xmlSchemaTypeEntitiesDef->subtypes = xmlSchemaTypeEntityDef; /* IDREFS */ xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS", XML_SCHEMAS_IDREFS, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeIdrefsDef == NULL) + goto error; xmlSchemaTypeIdrefsDef->subtypes = xmlSchemaTypeIdrefDef; /* NMTOKENS */ xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS", XML_SCHEMAS_NMTOKENS, xmlSchemaTypeAnySimpleTypeDef); + if (xmlSchemaTypeNmtokensDef == NULL) + goto error; xmlSchemaTypeNmtokensDef->subtypes = xmlSchemaTypeNmtokenDef; xmlSchemaTypesInitialized = 1; -} + return (0); -static void -xmlSchemaFreeTypeEntry(void *type, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlSchemaFreeType((xmlSchemaTypePtr) type); +error: + xmlSchemaCleanupTypesInternal(); + return (-1); } /** @@ -626,34 +848,16 @@ xmlSchemaFreeTypeEntry(void *type, const xmlChar *name ATTRIBUTE_UNUSED) { * DEPRECATED: This function will be made private. Call xmlCleanupParser * to free global state but see the warnings there. xmlCleanupParser * should be only called once at program exit. In most cases, you don't - * have call cleanup functions at all. + * have to call cleanup functions at all. * * 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; + if (xmlSchemaTypesInitialized != 0) { + xmlSchemaCleanupTypesInternal(); + xmlSchemaTypesInitialized = 0; } - xmlHashFree(xmlSchemaTypesBank, xmlSchemaFreeTypeEntry); - xmlSchemaTypesInitialized = 0; } /** @@ -748,8 +952,9 @@ xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType) xmlSchemaTypePtr xmlSchemaGetBuiltInType(xmlSchemaValType type) { - if (xmlSchemaTypesInitialized == 0) - xmlSchemaInitTypes(); + if ((xmlSchemaTypesInitialized == 0) && + (xmlSchemaInitTypes() < 0)) + return (NULL); switch (type) { case XML_SCHEMAS_ANYSIMPLETYPE: @@ -1061,6 +1266,23 @@ xmlSchemaFreeValue(xmlSchemaValPtr value) { if (value->value.base64.str != NULL) xmlFree(value->value.base64.str); break; + case XML_SCHEMAS_DECIMAL: + case XML_SCHEMAS_INTEGER: + case XML_SCHEMAS_NNINTEGER: + case XML_SCHEMAS_PINTEGER: + case XML_SCHEMAS_NPINTEGER: + case XML_SCHEMAS_NINTEGER: + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_LONG: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_SHORT: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_BYTE: + case XML_SCHEMAS_UBYTE: + if (value->value.decimal.str != NULL) + xmlFree(value->value.decimal.str); + break; default: break; } @@ -1081,8 +1303,9 @@ xmlSchemaFreeValue(xmlSchemaValPtr value) { */ xmlSchemaTypePtr xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) { - if (xmlSchemaTypesInitialized == 0) - xmlSchemaInitTypes(); + if ((xmlSchemaTypesInitialized == 0) && + (xmlSchemaInitTypes() < 0)) + return (NULL); if (name == NULL) return(NULL); return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns)); @@ -1154,7 +1377,7 @@ static const unsigned int daysInMonthLeap[12] = ((dt)->hour == 24 && (dt)->min == 0 && (dt)->sec == 0) #define VALID_TIME(dt) \ - (((VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \ + (((VALID_HOUR((int)dt->hour) && VALID_MIN((int)dt->min) && \ VALID_SEC(dt->sec)) || VALID_END_OF_DAY(dt)) && \ VALID_TZO(dt->tzo)) @@ -1178,25 +1401,6 @@ static const long dayInLeapYearByMonth[12] = 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 @@ -2138,21 +2342,16 @@ xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value, /** * xmlSchemaParseUInt: * @str: pointer to the string R/W - * @llo: pointer to the low result - * @lmi: pointer to the mid result - * @lhi: pointer to the high result + * @val: pointer to the resulting decimal * - * Parse an unsigned long into 3 fields. + * Parse an unsigned long into a decimal. * * Returns the number of significant digits in the number or * -1 if overflow of the capacity and -2 if it's not a number. */ -static int -xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo, - unsigned long *lmi, unsigned long *lhi) { - unsigned long lo = 0, mi = 0, hi = 0; - const xmlChar *tmp, *cur = *str; - int ret = 0, i = 0; +static int xmlSchemaParseUInt(const xmlChar **str, xmlSchemaValDecimalPtr val) { + const xmlChar *tmp, *cur = *str; + int ret = 0, i = 0; if (!((*cur >= '0') && (*cur <= '9'))) return(-2); @@ -2160,31 +2359,29 @@ xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo, while (*cur == '0') { /* ignore leading zeroes */ cur++; } + /* back up in case there is nothing after the leading zeroes */ + if(!(*cur >= '0' && *cur <= '9')) + { + --cur; + } tmp = cur; while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) { i++;tmp++;ret++; } - if (i > 24) { - *str = tmp; - return(-1); - } - while (i > 16) { - hi = hi * 10 + (*cur++ - '0'); - i--; - } - while (i > 8) { - mi = mi * 10 + (*cur++ - '0'); - i--; - } - while (i > 0) { - lo = lo * 10 + (*cur++ - '0'); - i--; + if (val->integralPlaces + val->fractionalPlaces < (unsigned)i + 1) + { + if (val->str != NULL) + { + xmlFree(val->str); + } + /* sign, dot, fractional 0 and NULL terminator */ + val->str = xmlMalloc(i + 4); } + val->fractionalPlaces = 1; + val->integralPlaces = i; + snprintf((char *)val->str, i + 4, "+%.*s.0", i, cur); - *str = cur; - *llo = lo; - *lmi = mi; - *lhi = hi; + *str = tmp; return(ret); } @@ -2251,8 +2448,9 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, xmlChar *norm = NULL; int ret = 0; - if (xmlSchemaTypesInitialized == 0) - xmlSchemaInitTypes(); + if ((xmlSchemaTypesInitialized == 0) && + (xmlSchemaInitTypes() < 0)) + return (-1); if (type == NULL) return (-1); @@ -2371,9 +2569,11 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, } case XML_SCHEMAS_DECIMAL:{ const xmlChar *cur = value; - unsigned int len, neg, integ, hasLeadingZeroes; - xmlChar cval[25]; - xmlChar *cptr = cval; + const xmlChar *numStart, *numEnd; + xmlSchemaValDecimal decimal; + xmlChar sign; + + memset(&decimal, 0, sizeof(decimal)); if ((cur == NULL) || (*cur == 0)) goto return1; @@ -2387,9 +2587,9 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, /* * First we handle an optional sign. */ - neg = 0; + sign = '+'; if (*cur == '-') { - neg = 1; + sign = '-'; cur++; } else if (*cur == '+') cur++; @@ -2398,47 +2598,44 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, */ if (*cur == 0) goto return1; - /* - * Next we "pre-parse" the number, in preparation for calling - * the common routine xmlSchemaParseUInt. We get rid of any - * leading zeroes (because we have reserved only 25 chars), - * and note the position of a decimal point. - */ - len = 0; - integ = ~0u; - hasLeadingZeroes = 0; + /* * Skip leading zeroes. */ while (*cur == '0') { cur++; - hasLeadingZeroes = 1; - } - if (*cur != 0) { - do { - if ((*cur >= '0') && (*cur <= '9')) { - *cptr++ = *cur++; - len++; - } else if (*cur == '.') { - cur++; - integ = len; - do { - if ((*cur >= '0') && (*cur <= '9')) { - *cptr++ = *cur++; - len++; - } else - break; - } while (len < 24); - /* - * Disallow "." but allow "00." - */ - if ((len == 0) && (!hasLeadingZeroes)) - goto return1; - break; - } else - break; - } while (len < 24); } + + numStart = cur; + + while ((*cur >= '0') && (*cur <= '9')) { + ++cur; + ++decimal.integralPlaces; + } + if (*cur == '.') { + ++cur; + } + while ((*cur >= '0') && (*cur <= '9')) { + ++cur; + ++decimal.fractionalPlaces; + } + + /* disallow "." */ + if ( + decimal.fractionalPlaces == 0 && decimal.integralPlaces == 0 + && (numStart == value || numStart[-1] != '0') + ) { + goto return1; + } + + numEnd = cur; + + /* find if there are trailing FRACTIONAL zeroes, and deal with them if necessary */ + while (numEnd > numStart && decimal.fractionalPlaces && numEnd[-1] == '0') { + --numEnd; + --decimal.fractionalPlaces; + } + if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur != 0) @@ -2446,50 +2643,36 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, if (val != NULL) { v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); if (v != NULL) { - /* - * Now evaluate the significant digits of the number - */ - if (len != 0) { - - if (integ != ~0u) { - /* - * Get rid of trailing zeroes in the - * fractional part. - */ - while ((len != integ) && (*(cptr-1) == '0')) { - cptr--; - len--; - } - } - /* - * Terminate the (preparsed) string. - */ - if (len != 0) { - *cptr = 0; - cptr = cval; - - xmlSchemaParseUInt((const xmlChar **)&cptr, - &v->value.decimal.lo, - &v->value.decimal.mi, - &v->value.decimal.hi); - } - } - /* - * Set the total digits to 1 if a zero value. - */ - v->value.decimal.sign = neg; - if (len == 0) { - /* Speedup for zero values. */ - v->value.decimal.total = 1; - } else { - v->value.decimal.total = len; - if (integ == ~0u) - v->value.decimal.frac = 0; - else - v->value.decimal.frac = len - integ; - } + /* create a standardized representation */ + size_t bufsize; + const char *integralStart = (const char *)numStart; + const char *fractionalStart = (const char *)numEnd - decimal.fractionalPlaces; + if (decimal.integralPlaces == 0) + { + integralStart = "0"; + decimal.integralPlaces = 1; + } + if (decimal.fractionalPlaces == 0) + { + fractionalStart = "0"; + decimal.fractionalPlaces = 1; + } + /* 3 = sign, dot, NULL terminator */ + bufsize = decimal.integralPlaces + decimal.fractionalPlaces + 3; + decimal.str = xmlMalloc(bufsize); + if (!decimal.str) + { + goto error; + } + snprintf((char *)decimal.str, bufsize, "%c%.*s.%.*s", sign, decimal.integralPlaces, integralStart, + decimal.fractionalPlaces, fractionalStart); + v->value.decimal = decimal; *val = v; } + else + { + goto error; + } } goto return0; } @@ -2869,19 +3052,19 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, * NOTE: the IDness might have already be declared in the DTD */ if (attr->atype != XML_ATTRIBUTE_ID) { - xmlIDPtr res; xmlChar *strip; + int res; strip = xmlSchemaStrip(value); if (strip != NULL) { - res = xmlAddID(NULL, node->doc, strip, attr); + res = xmlAddIDSafe(attr, strip); xmlFree(strip); } else - res = xmlAddID(NULL, node->doc, value, attr); - if (res == NULL) { + res = xmlAddIDSafe(attr, value); + if (res < 0) { + goto error; + } else if (res == 0) { ret = 2; - } else { - attr->atype = XML_ATTRIBUTE_ID; } } } @@ -2945,7 +3128,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, ret = 4; } if ((ret == 0) && (val != NULL)) { - TODO; + /* TODO */ } if ((ret == 0) && (node != NULL) && (node->type == XML_ATTRIBUTE_NODE)) { @@ -3034,6 +3217,8 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, value = norm; } tmpval = xmlStrdup(value); + if (tmpval == NULL) + goto error; for (cur = tmpval; *cur; ++cur) { if (*cur < 32 || *cur >= 127 || *cur == ' ' || *cur == '<' || *cur == '>' || *cur == '"' || @@ -3095,7 +3280,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, */ cur = xmlStrndup(start, i); if (cur == NULL) { - xmlSchemaTypeErrMemory(node, "allocating hexbin data"); + xmlSchemaTypeErrMemory(); xmlFree(v); goto return1; } @@ -3220,10 +3405,9 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, if (v == NULL) goto error; base = - (xmlChar *) xmlMallocAtomic((i + pad + 1) * - sizeof(xmlChar)); + (xmlChar *) xmlMallocAtomic(i + pad + 1); if (base == NULL) { - xmlSchemaTypeErrMemory(node, "allocating base64 data"); + xmlSchemaTypeErrMemory(); xmlFree(v); goto return1; } @@ -3243,201 +3427,152 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, case XML_SCHEMAS_PINTEGER: case XML_SCHEMAS_NPINTEGER: case XML_SCHEMAS_NINTEGER: - case XML_SCHEMAS_NNINTEGER:{ - const xmlChar *cur = value; - unsigned long lo, mi, hi; - int sign = 0; - - if (cur == NULL) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur == '-') { - sign = 1; - cur++; - } else if (*cur == '+') - cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); - if (ret < 0) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_NPINTEGER) { - if ((sign == 0) && - ((hi != 0) || (mi != 0) || (lo != 0))) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_PINTEGER) { - if (sign == 1) - goto return1; - if ((hi == 0) && (mi == 0) && (lo == 0)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_NINTEGER) { - if (sign == 0) - goto return1; - if ((hi == 0) && (mi == 0) && (lo == 0)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) { - if ((sign == 1) && - ((hi != 0) || (mi != 0) || (lo != 0))) - goto return1; - } - if (val != NULL) { - v = xmlSchemaNewValue(type->builtInType); - if (v != NULL) { - if (ret == 0) - ret++; - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = sign; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; - *val = v; - } - } - goto return0; - } + case XML_SCHEMAS_NNINTEGER: case XML_SCHEMAS_LONG: case XML_SCHEMAS_BYTE: case XML_SCHEMAS_SHORT: - case XML_SCHEMAS_INT:{ + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_UBYTE: { const xmlChar *cur = value; - unsigned long lo, mi, hi; - int sign = 0; + xmlSchemaValDecimal decimal; + xmlChar sign = '+'; + + memset(&decimal, 0, sizeof(decimal)); if (cur == NULL) goto return1; - if (normOnTheFly) + if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur == '-') { - sign = 1; + sign = '-'; cur++; } else if (*cur == '+') cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); + ret = xmlSchemaParseUInt(&cur, &decimal); + /* add sign */ if (ret < 0) - goto return1; + goto valIntegerReturn1; + decimal.str[0] = sign; if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_LONG) { - if (hi >= 922) { - if (hi > 922) - goto return1; - if (mi >= 33720368) { - if (mi > 33720368) - goto return1; - if ((sign == 0) && (lo > 54775807)) - goto return1; - if ((sign == 1) && (lo > 54775808)) - goto return1; - } - } - } else if (type->builtInType == XML_SCHEMAS_INT) { - if (hi != 0) - goto return1; - if (mi >= 21) { - if (mi > 21) - goto return1; - if ((sign == 0) && (lo > 47483647)) - goto return1; - if ((sign == 1) && (lo > 47483648)) - goto return1; - } - } else if (type->builtInType == XML_SCHEMAS_SHORT) { - if ((mi != 0) || (hi != 0)) - goto return1; - if ((sign == 1) && (lo > 32768)) - goto return1; - if ((sign == 0) && (lo > 32767)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_BYTE) { - if ((mi != 0) || (hi != 0)) - goto return1; - if ((sign == 1) && (lo > 128)) - goto return1; - if ((sign == 0) && (lo > 127)) - goto return1; + goto valIntegerReturn1; + if (type->builtInType == XML_SCHEMAS_NPINTEGER) + { + if(xmlSchemaValDecimalCompareWithInteger(&decimal, 0) > 0) + goto valIntegerReturn1; } - if (val != NULL) { - v = xmlSchemaNewValue(type->builtInType); - if (v != NULL) { - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = sign; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; - *val = v; - } + else if (type->builtInType == XML_SCHEMAS_PINTEGER) + { + if (sign == '-') + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) <= 0) + goto valIntegerReturn1; } - goto return0; - } - case XML_SCHEMAS_UINT: - case XML_SCHEMAS_ULONG: - case XML_SCHEMAS_USHORT: - case XML_SCHEMAS_UBYTE:{ - const xmlChar *cur = value; - unsigned long lo, mi, hi; - - if (cur == NULL) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); - if (ret < 0) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_ULONG) { - if (hi >= 1844) { - if (hi > 1844) - goto return1; - if (mi >= 67440737) { - if (mi > 67440737) - goto return1; - if (lo > 9551615) - goto return1; - } - } - } else if (type->builtInType == XML_SCHEMAS_UINT) { - if (hi != 0) - goto return1; - if (mi >= 42) { - if (mi > 42) - goto return1; - if (lo > 94967295) - goto return1; - } - } else if (type->builtInType == XML_SCHEMAS_USHORT) { - if ((mi != 0) || (hi != 0)) - goto return1; - if (lo > 65535) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_UBYTE) { - if ((mi != 0) || (hi != 0)) - goto return1; - if (lo > 255) - goto return1; + else if (type->builtInType == XML_SCHEMAS_NINTEGER) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) >= 0) + goto valIntegerReturn1; + } + else if (type->builtInType == XML_SCHEMAS_NNINTEGER) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_LONG) + { + /* (u)int64_t may not be available on 32 bit platform, just use decimal */ + xmlSchemaValDecimal tmpDecimal; + static const char maxLong[] = "+9223372036854775807.0"; + static const char minLong[] = "-9223372036854775808.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 19; + tmpDecimal.str = BAD_CAST maxLong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + tmpDecimal.str = BAD_CAST minLong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_ULONG) + { + xmlSchemaValDecimal tmpDecimal; + static const char maxULong[] = "+18446744073709551615.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 20; + tmpDecimal.str = (xmlChar*)maxULong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_INT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7fffffff) > 0) /* INT32_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x7fffffff-1) < 0) /* INT32_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_SHORT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7fff) > 0) /* INT16_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x8000) < 0) /* INT16_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_BYTE) + {if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7f) > 0) /* INT8_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x80) < 0) /* INT8_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_UINT) + { + xmlSchemaValDecimal tmpDecimal; + static const char maxUInt[] = "+4294967295.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 10; + tmpDecimal.str = (xmlChar*)maxUInt; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_USHORT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0xffff) > 0) /* UINT16_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_UBYTE) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0xff) > 0) /* UINT8_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; } if (val != NULL) { v = xmlSchemaNewValue(type->builtInType); if (v != NULL) { - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = 0; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; + v->value.decimal = decimal; *val = v; } } + else if(decimal.str != NULL) + { + xmlFree(decimal.str); + } goto return0; + valIntegerReturn1: + if(decimal.str != NULL) + { + xmlFree(decimal.str); + } + goto return1; } } @@ -3534,139 +3669,16 @@ xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value, static int xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y) { - xmlSchemaValPtr swp; - int order = 1, integx, integy, dlen; - unsigned long hi, mi, lo; - - /* - * First test: If x is -ve and not zero - */ - if ((x->value.decimal.sign) && - ((x->value.decimal.lo != 0) || - (x->value.decimal.mi != 0) || - (x->value.decimal.hi != 0))) { - /* - * Then if y is -ve and not zero reverse the compare - */ - if ((y->value.decimal.sign) && - ((y->value.decimal.lo != 0) || - (y->value.decimal.mi != 0) || - (y->value.decimal.hi != 0))) - order = -1; - /* - * Otherwise (y >= 0) we have the answer - */ - else - return (-1); - /* - * If x is not -ve and y is -ve we have the answer - */ - } else if ((y->value.decimal.sign) && - ((y->value.decimal.lo != 0) || - (y->value.decimal.mi != 0) || - (y->value.decimal.hi != 0))) { - return (1); - } - /* - * If it's not simply determined by a difference in sign, - * then we need to compare the actual values of the two nums. - * To do this, we start by looking at the integral parts. - * If the number of integral digits differ, then we have our - * answer. - */ - integx = x->value.decimal.total - x->value.decimal.frac; - integy = y->value.decimal.total - y->value.decimal.frac; - /* - * NOTE: We changed the "total" for values like "0.1" - * (or "-0.1" or ".1") to be 1, which was 2 previously. - * Therefore the special case, when such values are - * compared with 0, needs to be handled separately; - * otherwise a zero would be recognized incorrectly as - * greater than those values. This has the nice side effect - * that we gain an overall optimized comparison with zeroes. - * Note that a "0" has a "total" of 1 already. - */ - if (integx == 1) { - if (x->value.decimal.lo == 0) { - if (integy != 1) - return -order; - else if (y->value.decimal.lo != 0) - return -order; - else - return(0); - } - } - if (integy == 1) { - if (y->value.decimal.lo == 0) { - if (integx != 1) - return order; - else if (x->value.decimal.lo != 0) - return order; - else - return(0); - } - } - - if (integx > integy) - return order; - else if (integy > integx) - return -order; - - /* - * If the number of integral digits is the same for both numbers, - * then things get a little more complicated. We need to "normalize" - * the numbers in order to properly compare them. To do this, we - * look at the total length of each number (length => number of - * significant digits), and divide the "shorter" by 10 (decreasing - * the length) until they are of equal length. - */ - dlen = x->value.decimal.total - y->value.decimal.total; - if (dlen < 0) { /* y has more digits than x */ - swp = x; - hi = y->value.decimal.hi; - mi = y->value.decimal.mi; - lo = y->value.decimal.lo; - dlen = -dlen; - order = -order; - } else { /* x has more digits than y */ - swp = y; - hi = x->value.decimal.hi; - mi = x->value.decimal.mi; - lo = x->value.decimal.lo; - } - while (dlen > 8) { /* in effect, right shift by 10**8 */ - lo = mi; - mi = hi; - hi = 0; - dlen -= 8; - } - while (dlen > 0) { - unsigned long rem1, rem2; - rem1 = (hi % 10) * 100000000L; - hi = hi / 10; - rem2 = (mi % 10) * 100000000L; - mi = (mi + rem1) / 10; - lo = (lo + rem2) / 10; - dlen--; + int res = xmlSchemaValDecimalCompare(&x->value.decimal, &y->value.decimal); + if(res > 0) + { + return 1; } - if (hi > swp->value.decimal.hi) { - return order; - } else if (hi == swp->value.decimal.hi) { - if (mi > swp->value.decimal.mi) { - return order; - } else if (mi == swp->value.decimal.mi) { - if (lo > swp->value.decimal.lo) { - return order; - } else if (lo == swp->value.decimal.lo) { - if (x->value.decimal.total == y->value.decimal.total) { - return 0; - } else { - return order; - } - } - } + if(res < 0) + { + return -1; } - return -order; + return 0; } /** @@ -3853,6 +3865,24 @@ xmlSchemaCopyValue(xmlSchemaValPtr val) cur->value.base64.str = xmlStrdup(BAD_CAST val->value.base64.str); break; + case XML_SCHEMAS_DECIMAL: + case XML_SCHEMAS_INTEGER: + case XML_SCHEMAS_PINTEGER: + case XML_SCHEMAS_NPINTEGER: + case XML_SCHEMAS_NINTEGER: + case XML_SCHEMAS_NNINTEGER: + case XML_SCHEMAS_LONG: + case XML_SCHEMAS_BYTE: + case XML_SCHEMAS_SHORT: + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_UBYTE: + cur = xmlSchemaDupVal(val); + if (val->value.decimal.str != NULL) + cur->value.decimal.str = xmlStrdup(BAD_CAST val->value.decimal.str); + break; default: cur = xmlSchemaDupVal(val); break; @@ -4141,9 +4171,15 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) if (!y->value.date.tz_flag) { p1 = xmlSchemaDateNormalize(x, 0); + if (p1 == NULL) + return -2; p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; /* normalize y + 14:00 */ q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR)); + if (q1 == NULL) { + xmlSchemaFreeValue(p1); + return -2; + } q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; if (p1d < q1d) { @@ -4162,6 +4198,11 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) int ret = 0; /* normalize y - 14:00 */ q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR)); + if (q2 == NULL) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -2; + } q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day; if (p1d > q2d) ret = 1; @@ -4185,10 +4226,16 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) } } else if (y->value.date.tz_flag) { q1 = xmlSchemaDateNormalize(y, 0); + if (q1 == NULL) + return -2; q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; /* normalize x - 14:00 */ p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR)); + if (p1 == NULL) { + xmlSchemaFreeValue(q1); + return -2; + } p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; if (p1d < q1d) { @@ -4207,6 +4254,11 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) int ret = 0; /* normalize x + 14:00 */ p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR)); + if (p2 == NULL) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -2; + } p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day; if (p2d > q1d) { @@ -4236,9 +4288,15 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) if (x->type == y->type) { int ret = 0; q1 = xmlSchemaDateNormalize(y, 0); + if (q1 == NULL) + return -2; q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; p1 = xmlSchemaDateNormalize(x, 0); + if (p1 == NULL) { + xmlSchemaFreeValue(q1); + return -2; + } p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; if (p1d < q1d) { @@ -4915,7 +4973,7 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, * TODO: Compare those against QName. */ if (ytype == XML_SCHEMAS_QNAME) { - TODO + /* TODO */ if (y == NULL) return(-2); return (-2); @@ -5040,7 +5098,7 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, case XML_SCHEMAS_IDREFS: case XML_SCHEMAS_ENTITIES: case XML_SCHEMAS_NMTOKENS: - TODO + /* TODO */ break; } return -2; @@ -5190,9 +5248,10 @@ xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet) /* * TODO: Check if this is a decimal. */ + char *discard; if (facet == NULL || facet->val == NULL) return 0; - return ((unsigned long) facet->val->value.decimal.lo); + return strtoul((const char*)facet->val->value.decimal.str+1, &discard, 10); } /** @@ -5220,21 +5279,21 @@ xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet, * (compare value.decimal.mi and value.decimal.hi as well?). */ if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (actualLen != facet->val->value.decimal.lo) { + if (actualLen != xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_LENGTH_VALID); } } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (actualLen < facet->val->value.decimal.lo) { + if (actualLen < xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_MINLENGTH_VALID); } } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) { - if (actualLen > facet->val->value.decimal.lo) { + if (actualLen > xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); } } else @@ -5287,7 +5346,8 @@ xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_DECIMAL) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !(xmlSchemaValDecimalIsInteger(&facet->val->value.decimal))) + { return(-1); } if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) @@ -5341,21 +5401,22 @@ xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, */ return (0); default: - TODO + /* TODO */ + break; } } *length = (unsigned long) len; /* - * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi". + * TODO: Return the whole expected value. (This may be possible now with xmlSchemaValDecimalCompareWithInteger) */ if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (len != facet->val->value.decimal.lo) + if (len != xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_LENGTH_VALID); } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (len < facet->val->value.decimal.lo) + if (len < xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MINLENGTH_VALID); } else { - if (len > facet->val->value.decimal.lo) + if (len > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); } @@ -5551,7 +5612,7 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_DECIMAL) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !xmlSchemaValDecimalIsInteger(&facet->val->value.decimal)) { return(-1); } if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) @@ -5595,18 +5656,18 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, len = xmlSchemaNormLen(value); break; default: - TODO + /* TODO */ + break; } } if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (len != facet->val->value.decimal.lo) + if (len != xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_LENGTH_VALID); } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (len < facet->val->value.decimal.lo) + if (len < xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MINLENGTH_VALID); - } else { - if (len > facet->val->value.decimal.lo) - return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); + } else if (len > xmlSchemaGetFacetValueAsULong(facet)) { + return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); } break; } @@ -5616,7 +5677,7 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_PINTEGER) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !xmlSchemaValDecimalIsInteger(&facet->val->value.decimal)) { return(-1); } if ((val == NULL) || @@ -5637,16 +5698,17 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, return(-1); } if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { - if (val->value.decimal.total > facet->val->value.decimal.lo) + if (xmlSchemaValDecimalGetSignificantDigitCount(&val->value.decimal) > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID); } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) { - if (val->value.decimal.frac > facet->val->value.decimal.lo) + if ((xmlSchemaValDecimalIsInteger(&val->value.decimal) ? 0 : val->value.decimal.fractionalPlaces) > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID); } break; default: - TODO + /* TODO */ + break; } return(0); @@ -5872,75 +5934,13 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) BAD_CAST val->value.qname.uri); } break; - case XML_SCHEMAS_DECIMAL: - /* - * TODO: Lookout for a more simple implementation. - */ - if ((val->value.decimal.total == 1) && - (val->value.decimal.lo == 0)) { - *retValue = xmlStrdup(BAD_CAST "0.0"); - } else { - xmlSchemaValDecimal dec = val->value.decimal; - int bufsize; - char *buf = NULL, *offs; - - /* Add room for the decimal point as well. */ - bufsize = dec.total + 2; - if (dec.sign) - bufsize++; - /* Add room for leading/trailing zero. */ - if ((dec.frac == 0) || (dec.frac == dec.total)) - bufsize++; - buf = xmlMalloc(bufsize); - if (buf == NULL) - return(-1); - offs = buf; - if (dec.sign) - *offs++ = '-'; - if (dec.frac == dec.total) { - *offs++ = '0'; - *offs++ = '.'; - } - if (dec.hi != 0) - snprintf(offs, bufsize - (offs - buf), - "%lu%lu%lu", dec.hi, dec.mi, dec.lo); - else if (dec.mi != 0) - snprintf(offs, bufsize - (offs - buf), - "%lu%lu", dec.mi, dec.lo); - else - snprintf(offs, bufsize - (offs - buf), - "%lu", dec.lo); - - if (dec.frac != 0) { - if (dec.frac != dec.total) { - int diff = dec.total - dec.frac; - /* - * Insert the decimal point. - */ - memmove(offs + diff + 1, offs + diff, dec.frac +1); - offs[diff] = '.'; - } else { - unsigned int i = 0; - /* - * Insert missing zeroes behind the decimal point. - */ - while (*(offs + i) != 0) - i++; - if (i < dec.total) { - memmove(offs + (dec.total - i), offs, i +1); - memset(offs, '0', dec.total - i); - } - } - } else { - /* - * Append decimal point and zero. - */ - offs = buf + bufsize - 1; - *offs-- = 0; - *offs-- = '0'; - *offs-- = '.'; - } - *retValue = BAD_CAST buf; + case XML_SCHEMAS_DECIMAL: { + xmlChar *start = val->value.decimal.str; + if(start[0] == '+') + { + start += 1; + } + *retValue = xmlStrdup(start); } break; case XML_SCHEMAS_INTEGER: @@ -5955,40 +5955,20 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) case XML_SCHEMAS_UINT: case XML_SCHEMAS_ULONG: case XML_SCHEMAS_USHORT: - case XML_SCHEMAS_UBYTE: - if ((val->value.decimal.total == 1) && - (val->value.decimal.lo == 0)) - *retValue = xmlStrdup(BAD_CAST "0"); - else { - xmlSchemaValDecimal dec = val->value.decimal; - int bufsize = dec.total + 1; - - /* Add room for the decimal point as well. */ - if (dec.sign) - bufsize++; - *retValue = xmlMalloc(bufsize); - if (*retValue == NULL) - return(-1); - if (dec.hi != 0) { - if (dec.sign) - snprintf((char *) *retValue, bufsize, - "-%lu%lu%lu", dec.hi, dec.mi, dec.lo); - else - snprintf((char *) *retValue, bufsize, - "%lu%lu%lu", dec.hi, dec.mi, dec.lo); - } else if (dec.mi != 0) { - if (dec.sign) - snprintf((char *) *retValue, bufsize, - "-%lu%lu", dec.mi, dec.lo); - else - snprintf((char *) *retValue, bufsize, - "%lu%lu", dec.mi, dec.lo); - } else { - if (dec.sign) - snprintf((char *) *retValue, bufsize, "-%lu", dec.lo); - else - snprintf((char *) *retValue, bufsize, "%lu", dec.lo); - } + case XML_SCHEMAS_UBYTE: { + xmlChar *start = val->value.decimal.str; + /* 2 = sign+NULL */ + size_t bufSize = val->value.decimal.integralPlaces+2; + if(start[0] == '+') + { + start += 1; + bufSize -= 1; + } + *retValue = xmlMalloc(bufSize); + if(*retValue) { + /* no need to limit string length in format, it will only print bufSize-1 chars anyways */ + snprintf((char*)*retValue, bufSize, "%s", start); + } } break; case XML_SCHEMAS_BOOLEAN: diff --git a/xmlstring.c b/xmlstring.c index 46301c3b2b7..258ecc92c3b 100644 --- a/xmlstring.c +++ b/xmlstring.c @@ -23,6 +23,17 @@ #include #include +#include "private/parser.h" +#include "private/string.h" + +#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) + #else + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) + #endif +#endif + /************************************************************************ * * * Commodity functions to handle xmlChars * @@ -43,12 +54,11 @@ xmlStrndup(const xmlChar *cur, int len) { xmlChar *ret; if ((cur == NULL) || (len < 0)) return(NULL); - ret = (xmlChar *) xmlMallocAtomic(((size_t) len + 1) * sizeof(xmlChar)); + ret = (xmlChar *) xmlMallocAtomic((size_t) len + 1); if (ret == NULL) { - xmlErrMemory(NULL, NULL); return(NULL); } - memcpy(ret, cur, len * sizeof(xmlChar)); + memcpy(ret, cur, len); ret[len] = 0; return(ret); } @@ -88,12 +98,12 @@ xmlCharStrndup(const char *cur, int len) { xmlChar *ret; if ((cur == NULL) || (len < 0)) return(NULL); - ret = (xmlChar *) xmlMallocAtomic(((size_t) len + 1) * sizeof(xmlChar)); + ret = (xmlChar *) xmlMallocAtomic((size_t) len + 1); if (ret == NULL) { - xmlErrMemory(NULL, NULL); return(NULL); } for (i = 0;i < len;i++) { + /* Explicit sign change */ ret[i] = (xmlChar) cur[i]; if (ret[i] == 0) return(ret); } @@ -457,12 +467,12 @@ xmlStrncat(xmlChar *cur, const xmlChar *add, int len) { size = xmlStrlen(cur); if ((size < 0) || (size > INT_MAX - len)) return(NULL); - ret = (xmlChar *) xmlRealloc(cur, ((size_t) size + len + 1) * sizeof(xmlChar)); + ret = (xmlChar *) xmlRealloc(cur, (size_t) size + len + 1); if (ret == NULL) { - xmlErrMemory(NULL, NULL); - return(cur); + xmlFree(cur); + return(NULL); } - memcpy(&ret[size], add, len * sizeof(xmlChar)); + memcpy(&ret[size], add, len); ret[size + len] = 0; return(ret); } @@ -489,21 +499,19 @@ xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len) { if (len < 0) return(NULL); } - if ((str2 == NULL) || (len == 0)) - return(xmlStrdup(str1)); if (str1 == NULL) return(xmlStrndup(str2, len)); + if ((str2 == NULL) || (len == 0)) + return(xmlStrdup(str1)); size = xmlStrlen(str1); if ((size < 0) || (size > INT_MAX - len)) return(NULL); - ret = (xmlChar *) xmlMalloc(((size_t) size + len + 1) * 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 = (xmlChar *) xmlMalloc((size_t) size + len + 1); + if (ret == NULL) + return(NULL); + memcpy(ret, str1, size); + memcpy(&ret[size], str2, len); ret[size + len] = 0; return(ret); } @@ -543,7 +551,7 @@ xmlStrcat(xmlChar *cur, const xmlChar *add) { * * Returns the number of characters written to @buf or -1 if an error occurs. */ -int XMLCDECL +int xmlStrPrintf(xmlChar *buf, int len, const char *msg, ...) { va_list args; int ret; @@ -585,6 +593,148 @@ xmlStrVPrintf(xmlChar *buf, int len, const char *msg, va_list ap) { return(ret); } +/** + * xmlStrVASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @msg: printf format string + * @ap: arguments for format string + * + * Creates a newly allocated string according to format. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap) { + char empty[1]; + va_list copy; + xmlChar *buf; + int res, size; + int truncated = 0; + + if (out == NULL) + return(1); + *out = NULL; + if (msg == NULL) + return(1); + if (maxSize < 32) + maxSize = 32; + + va_copy(copy, ap); + res = vsnprintf(empty, 1, msg, copy); + va_end(copy); + + if (res > 0) { + /* snprintf seems to work according to C99. */ + + if (res < maxSize) { + size = res + 1; + } else { + size = maxSize; + truncated = 1; + } + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + if (vsnprintf((char *) buf, size, msg, ap) < 0) { + xmlFree(buf); + return(1); + } + } else { + /* + * Unfortunately, older snprintf implementations don't follow the + * C99 spec. If the output exceeds the size of the buffer, they can + * return -1, 0 or the number of characters written instead of the + * needed size. Older MSCVRT also won't write a terminating null + * byte if the buffer is too small. + * + * If the value returned is non-negative and strictly less than + * the buffer size (without terminating null), the result should + * have been written completely, so we double the buffer size + * until this condition is true. This assumes that snprintf will + * eventually return a non-negative value. Otherwise, we will + * allocate more and more memory until we run out. + * + * Note that this code path is also executed on conforming + * platforms if the output is the empty string. + */ + + buf = NULL; + size = 32; + while (1) { + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + + va_copy(copy, ap); + res = vsnprintf((char *) buf, size, msg, copy); + va_end(copy); + if ((res >= 0) && (res < size - 1)) + break; + + if (size >= maxSize) { + truncated = 1; + break; + } + + xmlFree(buf); + + if (size > maxSize / 2) + size = maxSize; + else + size *= 2; + } + } + + /* + * If the output was truncated, make sure that the buffer doesn't + * end with a truncated UTF-8 sequence. + */ + if (truncated != 0) { + int i = size - 1; + + while (i > 0) { + /* Break after ASCII */ + if (buf[i-1] < 0x80) + break; + i -= 1; + /* Break before non-ASCII */ + if (buf[i] >= 0xc0) + break; + } + + buf[i] = 0; + } + + *out = (xmlChar *) buf; + return(truncated); +} + +/** + * xmlStrASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @msg: printf format string + * @...: arguments for format string + * + * See xmlStrVASPrintf. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...) { + va_list ap; + int ret; + + va_start(ap, msg); + ret = xmlStrVASPrintf(out, maxSize, msg, ap); + va_end(ap); + + return(ret); +} + /************************************************************************ * * * Generic UTF8 handling routines * @@ -712,47 +862,47 @@ xmlGetUTF8Char(const unsigned char *utf, int *len) { goto error; if (len == NULL) goto error; - if (*len < 1) - goto error; c = utf[0]; - if (c & 0x80) { - if (*len < 2) + if (c < 0x80) { + if (*len < 1) goto error; - if ((utf[1] & 0xc0) != 0x80) + /* 1-byte code */ + *len = 1; + } else { + if ((*len < 2) || ((utf[1] & 0xc0) != 0x80)) goto error; - if ((c & 0xe0) == 0xe0) { - if (*len < 3) + if (c < 0xe0) { + if (c < 0xc2) goto error; - if ((utf[2] & 0xc0) != 0x80) + /* 2-byte code */ + *len = 2; + c = (c & 0x1f) << 6; + c |= utf[1] & 0x3f; + } else { + if ((*len < 3) || ((utf[2] & 0xc0) != 0x80)) goto error; - if ((c & 0xf0) == 0xf0) { - if (*len < 4) + if (c < 0xf0) { + /* 3-byte code */ + *len = 3; + c = (c & 0xf) << 12; + c |= (utf[1] & 0x3f) << 6; + c |= utf[2] & 0x3f; + if ((c < 0x800) || ((c >= 0xd800) && (c < 0xe000))) goto error; - if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + } else { + if ((*len < 4) || ((utf[3] & 0xc0) != 0x80)) goto error; *len = 4; /* 4-byte code */ - c = (utf[0] & 0x7) << 18; + c = (c & 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; + if ((c < 0x10000) || (c >= 0x110000)) + goto error; } - } else { - /* 2-byte code */ - *len = 2; - c = (utf[0] & 0x1f) << 6; - c |= utf[1] & 0x3f; } - } else { - /* 1-byte code */ - *len = 1; } return(c); @@ -871,11 +1021,11 @@ xmlUTF8Strndup(const xmlChar *utf, int len) { if ((utf == NULL) || (len < 0)) return(NULL); i = xmlUTF8Strsize(utf, len); - ret = (xmlChar *) xmlMallocAtomic(((size_t) i + 1) * sizeof(xmlChar)); + ret = (xmlChar *) xmlMallocAtomic((size_t) i + 1); if (ret == NULL) { return(NULL); } - memcpy(ret, utf, i * sizeof(xmlChar)); + memcpy(ret, utf, i); ret[i] = 0; return(ret); } @@ -956,8 +1106,9 @@ xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar) { * Create a substring from a given UTF-8 string * Note: positions are given in units of UTF-8 chars * - * Returns a pointer to a newly created string - * or NULL if any problem + * Returns a pointer to a newly created string or NULL if the + * start index is out of bounds or a memory allocation failed. + * If len is too large, the result is truncated. */ xmlChar * @@ -972,16 +1123,18 @@ xmlUTF8Strsub(const xmlChar *utf, int start, int len) { /* * Skip over any leading chars */ - for (i = 0;i < start;i++) { - if ((ch=*utf++) == 0) return(NULL); - if ( ch & 0x80 ) { - /* if not simple ascii, verify proper format */ - if ( (ch & 0xc0) != 0xc0 ) - return(NULL); - /* then skip over remaining bytes for this char */ - while ( (ch <<= 1) & 0x80 ) - if ( (*utf++ & 0xc0) != 0x80 ) + for (i = 0; i < start; i++) { + ch = *utf++; + if (ch == 0) + return(NULL); + /* skip over remaining bytes for this char */ + if (ch & 0x80) { + ch <<= 1; + while (ch & 0x80) { + if (*utf++ == 0) return(NULL); + ch <<= 1; + } } } @@ -1022,13 +1175,12 @@ xmlEscapeFormatString(xmlChar **msg) if ((count > INT_MAX) || (msgLen > INT_MAX - count)) return(NULL); resultLen = msgLen + count + 1; - result = (xmlChar *) xmlMallocAtomic(resultLen * sizeof(xmlChar)); + result = (xmlChar *) xmlMallocAtomic(resultLen); if (result == NULL) { /* Clear *msg to prevent format string vulnerabilities in out-of-memory situations. */ xmlFree(*msg); *msg = NULL; - xmlErrMemory(NULL, NULL); return(NULL); } diff --git a/xmlwriter.c b/xmlwriter.c index 85c19558d9d..f648dc0520b 100644 --- a/xmlwriter.c +++ b/xmlwriter.c @@ -11,43 +11,32 @@ #define IN_LIBXML #include "libxml.h" #include +#include #include #include +#include #include #include +#include #ifdef LIBXML_WRITER_ENABLED #include -#include "buf.h" -#include "enc.h" -#include "save.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" +#include "private/save.h" #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 but (hopefully) will - * be sufficient for libxml2. - */ -#ifndef VA_COPY - #ifdef HAVE_VA_COPY - #define VA_COPY(dest, src) va_copy(dest, src) +#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) #else - #ifdef HAVE___VA_COPY - #define VA_COPY(dest,src) __va_copy(dest, src) - #else - #ifndef VA_LIST_IS_ARRAY - #define VA_COPY(dest,src) (dest) = (src) - #else - #include - #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list)) - #endif - #endif + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) #endif #endif @@ -188,7 +177,7 @@ xmlNewTextWriter(xmlOutputBufferPtr out) "xmlNewTextWriter : out of memory!\n"); return NULL; } - memset(ret, 0, (size_t) sizeof(xmlTextWriter)); + memset(ret, 0, sizeof(xmlTextWriter)); ret->nodes = xmlListCreate(xmlFreeTextWriterStackEntry, xmlCmpTextWriterStackEntry); @@ -708,7 +697,11 @@ xmlTextWriterEndDocument(xmlTextWriterPtr writer) sum += count; } - sum += xmlTextWriterFlush(writer); + count = xmlTextWriterFlush(writer); + if (count < 0) + return -1; + sum += count; + return sum; } @@ -863,7 +856,7 @@ xmlTextWriterEndComment(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, const char *format, ...) { @@ -1291,7 +1284,7 @@ xmlTextWriterFullEndElement(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, const char *format, ...) { @@ -1417,7 +1410,7 @@ xmlTextWriterWriteRaw(xmlTextWriterPtr writer, const xmlChar * content) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatString(xmlTextWriterPtr writer, const char *format, ...) { @@ -1503,8 +1496,8 @@ xmlTextWriterWriteString(xmlTextWriterPtr writer, const xmlChar * content) break; case XML_TEXTWRITER_ATTRIBUTE: buf = NULL; - xmlBufAttrSerializeTxtContent(writer->out->buffer, - writer->doc, NULL, content); + xmlBufAttrSerializeTxtContent(writer->out, writer->doc, + content); break; default: break; @@ -1963,7 +1956,7 @@ xmlTextWriterEndAttribute(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) @@ -2058,7 +2051,7 @@ xmlTextWriterWriteAttribute(xmlTextWriterPtr writer, const xmlChar * name, * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, @@ -2166,7 +2159,7 @@ xmlTextWriterWriteAttributeNS(xmlTextWriterPtr writer, * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) @@ -2263,7 +2256,7 @@ xmlTextWriterWriteElement(xmlTextWriterPtr writer, const xmlChar * name, * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, const xmlChar * prefix, const xmlChar * name, @@ -2520,7 +2513,7 @@ xmlTextWriterEndPI(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, const xmlChar * target, const char *format, ...) { @@ -2735,7 +2728,7 @@ xmlTextWriterEndCDATA(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, const char *format, ...) { @@ -3044,7 +3037,7 @@ xmlTextWriterEndDTD(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, const xmlChar * name, const xmlChar * pubid, @@ -3288,7 +3281,7 @@ xmlTextWriterEndDTDElement(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) @@ -3525,7 +3518,7 @@ xmlTextWriterEndDTDAttlist(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name, const char *format, ...) @@ -3783,7 +3776,7 @@ xmlTextWriterEndDTDEntity(xmlTextWriterPtr writer) * * Returns the bytes written (may be 0 because of buffering) or -1 in case of error */ -int XMLCDECL +int xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, int pe, const xmlChar * name, @@ -4243,6 +4236,35 @@ xmlTextWriterFlush(xmlTextWriterPtr writer) return count; } +/** + * xmlTextWriterClose: + * @writer: the xmlTextWriterPtr + * + * Flushes and closes the output buffer. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors code. + */ +int +xmlTextWriterClose(xmlTextWriterPtr writer) +{ + int result; + + if ((writer == NULL) || (writer->out == NULL)) + return XML_ERR_ARGUMENT; + + result = xmlOutputBufferClose(writer->out); + writer->out = NULL; + + if (result >= 0) + result = XML_ERR_OK; + else + result = -result; + + return result; +} + /** * misc */ @@ -4480,7 +4502,7 @@ xmlTextWriterVSprintf(const char *format, va_list argptr) return NULL; } - VA_COPY(locarg, argptr); + va_copy(locarg, argptr); while (((count = vsnprintf((char *) buf, size, format, locarg)) < 0) || (count == size - 1) || (count == size) || (count > size)) { va_end(locarg); @@ -4492,7 +4514,7 @@ xmlTextWriterVSprintf(const char *format, va_list argptr) "xmlTextWriterVSprintf : out of memory!\n"); return NULL; } - VA_COPY(locarg, argptr); + va_copy(locarg, argptr); } va_end(locarg); @@ -4511,28 +4533,17 @@ xmlTextWriterStartDocumentCallback(void *ctx) xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlDocPtr doc; - if (ctxt->html) { #ifdef LIBXML_HTML_ENABLED + if (ctxt->html) { if (ctxt->myDoc == NULL) ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL); if (ctxt->myDoc == NULL) { - 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; + xmlCtxtErrMemory(ctxt); return; } -#else - 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 #endif - } else { + { doc = ctxt->myDoc; if (doc == NULL) doc = ctxt->myDoc = xmlNewDoc(ctxt->version); @@ -4545,12 +4556,7 @@ xmlTextWriterStartDocumentCallback(void *ctx) 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; + xmlCtxtErrMemory(ctxt); return; } } diff --git a/xpath.c b/xpath.c index 4a6f0e216e7..033de6219d8 100644 --- a/xpath.c +++ b/xpath.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include @@ -44,21 +43,20 @@ #endif #include #include -#include #ifdef LIBXML_PATTERN_ENABLED #include #endif -#include "buf.h" +#include "private/buf.h" +#include "private/error.h" +#include "private/xpath.h" +/* Disabled for now */ +#if 0 #ifdef LIBXML_PATTERN_ENABLED #define XPATH_STREAMING #endif - -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +#endif /** * WITH_TIM_SORT: @@ -87,13 +85,6 @@ */ #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 */ - /* * XPATH_MAX_STEPS: * when compiling an XPath expression we arbitrary limit the maximum @@ -129,6 +120,9 @@ */ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION #define XPATH_MAX_RECURSION_DEPTH 500 +#elif defined(_WIN32) +/* Windows typically limits stack size to 1MB. */ +#define XPATH_MAX_RECURSION_DEPTH 1000 #else #define XPATH_MAX_RECURSION_DEPTH 5000 #endif @@ -140,6 +134,116 @@ * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) */ +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) + +/************************************************************************ + * * + * Floating point stuff * + * * + ************************************************************************/ + +double xmlXPathNAN = 0.0; +double xmlXPathPINF = 0.0; +double xmlXPathNINF = 0.0; + +/** + * xmlXPathInit: + * + * DEPRECATED: Alias for xmlInitParser. + */ +void +xmlXPathInit(void) { + xmlInitParser(); +} + +/** + * xmlInitXPathInternal: + * + * Initialize the XPath environment + */ +ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") +void +xmlInitXPathInternal(void) { +#if defined(NAN) && defined(INFINITY) + xmlXPathNAN = NAN; + xmlXPathPINF = INFINITY; + xmlXPathNINF = -INFINITY; +#else + /* MSVC doesn't allow division by zero in constant expressions. */ + double zero = 0.0; + xmlXPathNAN = 0.0 / zero; + xmlXPathPINF = 1.0 / zero; + xmlXPathNINF = -xmlXPathPINF; +#endif +} + +/** + * xmlXPathIsNaN: + * @val: a double value + * + * Checks whether a double is a NaN. + * + * Returns 1 if the value is a NaN, 0 otherwise + */ +int +xmlXPathIsNaN(double val) { +#ifdef isnan + return isnan(val); +#else + return !(val == val); +#endif +} + +/** + * xmlXPathIsInf: + * @val: a double value + * + * Checks whether a double is an infinity. + * + * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise + */ +int +xmlXPathIsInf(double val) { +#ifdef isinf + return isinf(val) ? (val > 0 ? 1 : -1) : 0; +#else + if (val >= xmlXPathPINF) + return 1; + if (val <= -xmlXPathPINF) + return -1; + return 0; +#endif +} + +#endif /* SCHEMAS or XPATH */ + +#ifdef LIBXML_XPATH_ENABLED + +/* + * TODO: when compatibility allows remove all "fake node libxslt" strings + * the test should just be name[0] = ' ' + */ + +static const xmlNs xmlXPathXMLNamespaceStruct = { + NULL, + XML_NAMESPACE_DECL, + XML_XML_NAMESPACE, + BAD_CAST "xml", + NULL, + NULL +}; +static const xmlNs *const 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 + +static void +xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes); + #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON /** * xmlXPathCmpNodesExt: @@ -467,107 +571,6 @@ int wrap_cmp( xmlNodePtr x, xmlNodePtr y ); #include "timsort.h" #endif /* WITH_TIM_SORT */ -#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) - -/************************************************************************ - * * - * Floating point stuff * - * * - ************************************************************************/ - -double xmlXPathNAN = 0.0; -double xmlXPathPINF = 0.0; -double xmlXPathNINF = 0.0; - -/** - * xmlXPathInit: - * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * Initialize the XPath environment - */ -ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") -void -xmlXPathInit(void) { -#if defined(NAN) && defined(INFINITY) - xmlXPathNAN = NAN; - xmlXPathPINF = INFINITY; - xmlXPathNINF = -INFINITY; -#else - /* MSVC doesn't allow division by zero in constant expressions. */ - double zero = 0.0; - xmlXPathNAN = 0.0 / zero; - xmlXPathPINF = 1.0 / zero; - xmlXPathNINF = -xmlXPathPINF; -#endif -} - -/** - * xmlXPathIsNaN: - * @val: a double value - * - * Returns 1 if the value is a NaN, 0 otherwise - */ -int -xmlXPathIsNaN(double val) { -#ifdef isnan - return isnan(val); -#else - return !(val == val); -#endif -} - -/** - * xmlXPathIsInf: - * @val: a double value - * - * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise - */ -int -xmlXPathIsInf(double val) { -#ifdef isinf - return isinf(val) ? (val > 0 ? 1 : -1) : 0; -#else - if (val >= xmlXPathPINF) - return 1; - if (val <= -xmlXPathPINF) - return -1; - return 0; -#endif -} - -#endif /* SCHEMAS or XPATH */ - -#ifdef LIBXML_XPATH_ENABLED - -/* - * 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 * @@ -621,120 +624,100 @@ static const char* const xmlXPathErrorMessages[] = { /** * xmlXPathErrMemory: * @ctxt: an XPath context - * @extra: extra information * - * Handle a redefinition of attribute error + * Handle a memory allocation failure. */ -static void -xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) +void +xmlXPathErrMemory(xmlXPathContextPtr ctxt) { - if (ctxt != NULL) { - xmlResetError(&ctxt->lastError); - if (extra) { - xmlChar buf[200]; - - xmlStrPrintf(buf, 200, - "Memory allocation failed : %s\n", - extra); - ctxt->lastError.message = (char *) xmlStrdup(buf); - } else { - ctxt->lastError.message = (char *) - xmlStrdup(BAD_CAST "Memory allocation failed\n"); - } - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; - if (ctxt->error != NULL) - ctxt->error(ctxt->userData, &ctxt->lastError); - } else { - if (extra) - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); - } + if (ctxt == NULL) + return; + xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH, + &ctxt->lastError); } /** * xmlXPathPErrMemory: * @ctxt: an XPath parser context - * @extra: extra information * - * Handle a redefinition of attribute error + * Handle a memory allocation failure. */ -static void -xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) +void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt) { if (ctxt == NULL) - xmlXPathErrMemory(NULL, extra); - else { - ctxt->error = XPATH_MEMORY_ERROR; - xmlXPathErrMemory(ctxt->context, extra); - } + return; + ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathErrMemory(ctxt->context); } /** * xmlXPathErr: * @ctxt: a XPath parser context - * @error: the error code + * @code: the error code * * Handle an XPath error */ void -xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) +xmlXPathErr(xmlXPathParserContextPtr ctxt, int code) { - if ((error < 0) || (error > MAXERRNO)) - error = MAXERRNO; - if (ctxt == NULL) { - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, - XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - "%s", xmlXPathErrorMessages[error]); - return; - } - 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; - } + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + xmlNodePtr node = NULL; + int res; + + if (ctxt == NULL) + return; + if ((code < 0) || (code > MAXERRNO)) + code = MAXERRNO; + /* Only report the first error */ + if (ctxt->error != 0) + return; - /* cleanup current last error */ - xmlResetError(&ctxt->context->lastError); + ctxt->error = code; - ctxt->context->lastError.domain = XML_FROM_XPATH; - ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - - XPATH_EXPRESSION_OK; - ctxt->context->lastError.level = XML_ERR_ERROR; - ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); - ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; - ctxt->context->lastError.node = ctxt->context->debugNode; - if (ctxt->context->error != NULL) { - ctxt->context->error(ctxt->context->userData, - &ctxt->context->lastError); - } else { - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->context->debugNode, XML_FROM_XPATH, - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, - XML_ERR_ERROR, NULL, 0, - (const char *) ctxt->base, NULL, NULL, - ctxt->cur - ctxt->base, 0, - "%s", xmlXPathErrorMessages[error]); + if (ctxt->context != NULL) { + xmlErrorPtr err = &ctxt->context->lastError; + + /* Don't overwrite memory error. */ + if (err->code == XML_ERR_NO_MEMORY) + return; + + /* cleanup current last error */ + xmlResetError(err); + + err->domain = XML_FROM_XPATH; + err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK; + err->level = XML_ERR_ERROR; + if (ctxt->base != NULL) { + err->str1 = (char *) xmlStrdup(ctxt->base); + if (err->str1 == NULL) { + xmlXPathPErrMemory(ctxt); + return; + } + } + err->int1 = ctxt->cur - ctxt->base; + err->node = ctxt->context->debugNode; + + schannel = ctxt->context->error; + data = ctxt->context->userData; + node = ctxt->context->debugNode; + } + + if (schannel == NULL) { + channel = xmlGenericError; + data = xmlGenericErrorContext; } + res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH, + code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, + XML_ERR_ERROR, NULL, 0, + (const char *) ctxt->base, NULL, NULL, + ctxt->cur - ctxt->base, 0, + "%s", xmlXPathErrorMessages[code]); + if (res < 0) + xmlXPathPErrMemory(ctxt); } /** @@ -780,113 +763,13 @@ xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { /************************************************************************ * * - * Utilities * + * Parser Types * * * ************************************************************************/ -/** - * 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) { - if (list->size > 50000000) { - xmlXPathErrMemory(NULL, - "xmlPointerListAddSize: re-allocating item\n"); - return(-1); - } - list->size *= 2; - list->items = (void **) xmlRealloc(list->items, - list->size * sizeof(void *)); - if (list->items == NULL) { - xmlXPathErrMemory(NULL, - "xmlPointerListAddSize: 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: - */ + * Types are private: + */ typedef enum { XPATH_OP_END=0, @@ -966,10 +849,6 @@ struct _xmlXPathCompExpr { int last; /* index of last step in expression */ xmlChar *expr; /* the expression being computed */ xmlDictPtr dict; /* the dictionary to use if any */ -#ifdef DEBUG_EVAL_COUNTS - int nb; - xmlChar *string; -#endif #ifdef XPATH_STREAMING xmlPatternPtr stream; #endif @@ -980,8 +859,7 @@ struct _xmlXPathCompExpr { * Forward declarations * * * ************************************************************************/ -static void -xmlXPathFreeValueTree(xmlNodeSetPtr obj); + static void xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); static int @@ -1012,25 +890,19 @@ xmlXPathNewCompExpr(void) { xmlXPathCompExprPtr cur; cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); - if (cur == NULL) { - xmlXPathErrMemory(NULL, "allocating component\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlXPathCompExpr)); cur->maxStep = 10; cur->nbStep = 0; cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * sizeof(xmlXPathStepOp)); if (cur->steps == NULL) { - xmlXPathErrMemory(NULL, "allocating steps\n"); xmlFree(cur); return(NULL); } memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); cur->last = -1; -#ifdef DEBUG_EVAL_COUNTS - cur->nb = 0; -#endif return(cur); } @@ -1073,11 +945,6 @@ xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 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); @@ -1115,7 +982,7 @@ xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, xmlXPathStepOp *real; if (comp->maxStep >= XPATH_MAX_STEPS) { - xmlXPathPErrMemory(ctxt, "adding step\n"); + xmlXPathPErrMemory(ctxt); return(-1); } comp->maxStep *= 2; @@ -1123,7 +990,7 @@ xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, comp->maxStep * sizeof(xmlXPathStepOp)); if (real == NULL) { comp->maxStep /= 2; - xmlXPathPErrMemory(ctxt, "adding step\n"); + xmlXPathPErrMemory(ctxt); return(-1); } comp->steps = real; @@ -1209,48 +1076,15 @@ xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \ /* #define XP_DEFAULT_CACHE_ON */ -#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) - typedef struct _xmlXPathContextCache xmlXPathContextCache; typedef xmlXPathContextCache *xmlXPathContextCachePtr; struct _xmlXPathContextCache { - xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ + xmlXPathObjectPtr nodesetObjs; /* stringval points to next */ + xmlXPathObjectPtr miscObjs; /* stringval points to next */ + int numNodeset; int maxNodeset; - int maxString; - int maxBoolean; - int maxNumber; + int numMisc; int maxMisc; -#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 }; /************************************************************************ @@ -1259,11 +1093,6 @@ struct _xmlXPathContextCache { * * ************************************************************************/ -#define STRANGE \ - xmlGenericError(xmlGenericErrorContext, \ - "Internal error at %s:%d\n", \ - __FILE__, __LINE__); - #ifdef LIBXML_DEBUG_ENABLED static void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { @@ -1707,478 +1536,6 @@ xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, } } -#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; - -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; -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - cache->dbgReusedPoint++; - break; - case XPATH_RANGE: - cache->dbgReusedRange++; - break; - case XPATH_LOCATIONSET: - cache->dbgReusedLocset++; - break; -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - 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; -#ifdef LIBXML_XPTR_LOCS_ENABLED - 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; -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - 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; -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - cache->dbgCachedPoint++; - break; - case XPATH_RANGE: - cache->dbgCachedRange++; - break; - case XPATH_LOCATIONSET: - cache->dbgCachedLocset++; - break; -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - 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; -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - xmlXPathDebugObjCounterPoint--; - break; - case XPATH_RANGE: - xmlXPathDebugObjCounterRange--; - break; - case XPATH_LOCATIONSET: - xmlXPathDebugObjCounterLocset--; - break; -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - case XPATH_USERS: - xmlXPathDebugObjCounterUsers--; - break; - case XPATH_XSLT_TREE: - xmlXPathDebugObjCounterXSLTTree--; - break; - default: - break; - } - xmlXPathDebugObjCounterAll--; -} - -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 */ /************************************************************************ @@ -2200,45 +1557,31 @@ xmlXPathNewCache(void) xmlXPathContextCachePtr ret; ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating object cache\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); + memset(ret, 0 , sizeof(xmlXPathContextCache)); ret->maxNodeset = 100; - ret->maxString = 100; - ret->maxBoolean = 100; - ret->maxNumber = 100; ret->maxMisc = 100; return(ret); } static void -xmlXPathCacheFreeObjectList(xmlPointerListPtr list) +xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list) { - int i; - xmlXPathObjectPtr obj; + while (list != NULL) { + xmlXPathObjectPtr next; - if (list == NULL) - return; + next = (void *) list->stringval; - for (i = 0; i < list->number; i++) { - obj = list->items[i]; - /* - * Note that it is already assured that we don't need to - * look out for namespace nodes in the node-set. - */ - if (obj->nodesetval != NULL) { - if (obj->nodesetval->nodeTab != NULL) - xmlFree(obj->nodesetval->nodeTab); - xmlFree(obj->nodesetval); + if (list->nodesetval != NULL) { + if (list->nodesetval->nodeTab != NULL) + xmlFree(list->nodesetval->nodeTab); + xmlFree(list->nodesetval); } - xmlFree(obj); -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjCounterAll--; -#endif + xmlFree(list); + + list = next; } - xmlPointerListFree(list); } static void @@ -2248,12 +1591,6 @@ xmlXPathFreeCache(xmlXPathContextCachePtr cache) return; if (cache->nodesetObjs) xmlXPathCacheFreeObjectList(cache->nodesetObjs); - if (cache->stringObjs) - xmlXPathCacheFreeObjectList(cache->stringObjs); - if (cache->booleanObjs) - xmlXPathCacheFreeObjectList(cache->booleanObjs); - if (cache->numberObjs) - xmlXPathCacheFreeObjectList(cache->numberObjs); if (cache->miscObjs) xmlXPathCacheFreeObjectList(cache->miscObjs); xmlFree(cache); @@ -2275,8 +1612,8 @@ xmlXPathFreeCache(xmlXPathContextCachePtr cache) * @value: * This will set the maximum number of XPath objects * to be cached per slot - * There are 5 slots for: node-set, string, number, boolean, and - * misc objects. Use <0 for the default number (100). + * There are two slots for node-set and misc objects. + * Use <0 for the default number (100). * Other values for @options have currently no effect. * * Returns 0 if the setting succeeded, and -1 on API or internal errors. @@ -2294,17 +1631,16 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt, if (ctxt->cache == NULL) { ctxt->cache = xmlXPathNewCache(); - if (ctxt->cache == NULL) + if (ctxt->cache == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } } cache = (xmlXPathContextCachePtr) ctxt->cache; if (options == 0) { if (value < 0) value = 100; cache->maxNodeset = value; - cache->maxString = value; - cache->maxNumber = value; - cache->maxBoolean = value; cache->maxMisc = value; } } else if (ctxt->cache != NULL) { @@ -2316,44 +1652,46 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt, /** * xmlXPathCacheWrapNodeSet: - * @ctxt: the XPath context + * @pctxt: 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. + * + * In case of error the node set is destroyed and NULL is returned. */ static xmlXPathObjectPtr -xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) +xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; ret->type = XPATH_NODESET; ret->nodesetval = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); -#endif return(ret); } } - return(xmlXPathWrapNodeSet(val)); - + ret = xmlXPathWrapNodeSet(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); } /** * xmlXPathCacheWrapString: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the xmlChar * value * * This is the cached version of xmlXPathWrapString(). @@ -2362,49 +1700,33 @@ xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) +xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - if ((cache->stringObjs != NULL) && - (cache->stringObjs->number != 0)) - { - - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->stringObjs->items[--cache->stringObjs->number]; - ret->type = XPATH_STRING; - ret->stringval = val; -#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]; - + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; ret->type = XPATH_STRING; ret->stringval = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); -#endif return(ret); } } - return(xmlXPathWrapString(val)); + + ret = xmlXPathWrapString(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); } /** * xmlXPathCacheNewNodeSet: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the NodePtr value * * This is the cached version of xmlXPathNewNodeSet(). @@ -2414,117 +1736,67 @@ xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) +xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val) { - if ((ctxt != NULL) && (ctxt->cache)) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - if ((cache->nodesetObjs != NULL) && - (cache->nodesetObjs->number != 0)) - { - xmlXPathObjectPtr ret; + if (cache->nodesetObjs != NULL) { /* * Use the nodeset-cache. */ - ret = (xmlXPathObjectPtr) - cache->nodesetObjs->items[--cache->nodesetObjs->number]; + ret = cache->nodesetObjs; + cache->nodesetObjs = (void *) ret->stringval; + cache->numNodeset -= 1; + ret->stringval = NULL; ret->type = XPATH_NODESET; ret->boolval = 0; if (val) { if ((ret->nodesetval->nodeMax == 0) || (val->type == XML_NAMESPACE_DECL)) { - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique(ret->nodesetval, val); + if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0) + xmlXPathPErrMemory(pctxt); } else { ret->nodesetval->nodeTab[0] = val; ret->nodesetval->nodeNr = 1; } } -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); -#endif return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; + } else if (cache->miscObjs != NULL) { + xmlNodeSetPtr set; /* * Fallback to misc-cache. */ - ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; - - ret->type = XPATH_NODESET; - ret->boolval = 0; - ret->nodesetval = xmlXPathNodeSetCreate(val); - if (ret->nodesetval == NULL) { - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; + set = xmlXPathNodeSetCreate(val); + if (set == NULL) { + xmlXPathPErrMemory(pctxt); return(NULL); } -#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 + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; + ret->type = XPATH_NODESET; + ret->boolval = 0; + ret->nodesetval = set; return(ret); } } - return(xmlXPathNewCString(val)); + ret = xmlXPathNewNodeSet(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); } /** * xmlXPathCacheNewString: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the xmlChar * value * * This is the cached version of xmlXPathNewString(). @@ -2533,276 +1805,172 @@ xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) +xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val) { - if ((ctxt != NULL) && (ctxt->cache)) { - xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; - if ((cache->stringObjs != NULL) && - (cache->stringObjs->number != 0)) - { - xmlXPathObjectPtr ret; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - 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; + if (cache->miscObjs != NULL) { + xmlChar *copy; - ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; + if (val == NULL) + val = BAD_CAST ""; + copy = xmlStrdup(val); + if (copy == NULL) { + xmlXPathPErrMemory(pctxt); + return(NULL); + } + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; 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 + ret->stringval = copy; 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)); + ret = xmlXPathNewString(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); } /** - * xmlXPathCacheNewFloat: - * @ctxt: the XPath context - * @val: the double value + * xmlXPathCacheNewCString: + * @pctxt the XPath context + * @val: the char * value * - * This is the cached version of xmlXPathNewFloat(). - * Acquires an xmlXPathObjectPtr of type double and of value @val + * 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 -xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) +xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *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: -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - case XPATH_RANGE: - case XPATH_LOCATIONSET: -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; - break; - } - xmlXPathReleaseObject(ctxt, val); - if (res == NULL) - return(xmlXPathCacheNewCString(ctxt, "")); - return(xmlXPathCacheWrapString(ctxt, res)); + return xmlXPathCacheNewString(pctxt, BAD_CAST val); } /** - * xmlXPathCacheObjectCopy: - * @ctxt: the XPath context - * @val: the original object + * xmlXPathCacheNewBoolean: + * @pctxt the XPath context + * @val: the boolean value * - * This is the cached version of xmlXPathObjectCopy(). - * Acquire a copy of a given object + * This is the cached version of xmlXPathNewBoolean(). + * Acquires an xmlXPathObjectPtr of type boolean and of value @val * - * Returns a created or reused created object. + * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) +xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val) { - if (val == NULL) - return(NULL); + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; - 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; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; + + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; + ret->type = XPATH_BOOLEAN; + ret->boolval = (val != 0); + return(ret); } } - return(xmlXPathObjectCopy(val)); + + ret = xmlXPathNewBoolean(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); } /** - * xmlXPathCacheConvertBoolean: - * @ctxt: the XPath context - * @val: an XPath object + * xmlXPathCacheNewFloat: + * @pctxt the XPath context + * @val: the double value * - * This is the cached version of xmlXPathConvertBoolean(). - * Converts an existing object to its boolean() equivalent + * This is the cached version of xmlXPathNewFloat(). + * Acquires an xmlXPathObjectPtr of type double and of value @val * - * Returns a created or reused object, the old one is freed (or the operation - * is done directly on @val) + * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { +xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val) +{ xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; - if (val == NULL) - return(xmlXPathCacheNewBoolean(ctxt, 0)); - if (val->type == XPATH_BOOLEAN) - return(val); - ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); - xmlXPathReleaseObject(ctxt, val); + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; + + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; + ret->type = XPATH_NUMBER; + ret->floatval = val; + return(ret); + } + } + + ret = xmlXPathNewFloat(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); return(ret); } /** - * xmlXPathCacheConvertNumber: - * @ctxt: the XPath context - * @val: an XPath object + * xmlXPathCacheObjectCopy: + * @pctxt the XPath context + * @val: the original object * - * This is the cached version of xmlXPathConvertNumber(). - * Converts an existing object to its number() equivalent + * This is the cached version of xmlXPathObjectCopy(). + * Acquire a copy of a given object * - * Returns a created or reused object, the old one is freed (or the operation - * is done directly on @val) + * Returns a created or reused created object. */ static xmlXPathObjectPtr -xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { +xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val) +{ xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; if (val == NULL) - return(xmlXPathCacheNewFloat(ctxt, 0.0)); - if (val->type == XPATH_NUMBER) - return(val); - ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); - xmlXPathReleaseObject(ctxt, val); + return(NULL); + + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + switch (val->type) { + case XPATH_NODESET: { + xmlNodeSetPtr set; + + set = xmlXPathNodeSetMerge(NULL, val->nodesetval); + if (set == NULL) { + xmlXPathPErrMemory(pctxt); + return(NULL); + } + return(xmlXPathCacheWrapNodeSet(pctxt, set)); + } + case XPATH_STRING: + return(xmlXPathCacheNewString(pctxt, val->stringval)); + case XPATH_BOOLEAN: + return(xmlXPathCacheNewBoolean(pctxt, val->boolval)); + case XPATH_NUMBER: + return(xmlXPathCacheNewFloat(pctxt, val->floatval)); + default: + break; + } + } + ret = xmlXPathObjectCopy(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); return(ret); } @@ -2813,39 +1981,59 @@ xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { ************************************************************************/ /** - * xmlXPathSetFrame: - * @ctxt: an XPath parser context + * xmlXPathCastToNumberInternal: + * @ctxt: parser context + * @val: an XPath object * - * Set the callee evaluation frame + * Converts an XPath object to its number value * - * Returns the previous frame value to be restored once done + * Returns the number value */ -static int -xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { - int ret; +static double +xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr val) { + double ret = 0.0; - if (ctxt == NULL) - return(0); - ret = ctxt->valueFrame; - ctxt->valueFrame = ctxt->valueNr; - return(ret); -} + if (val == NULL) + return(xmlXPathNAN); + switch (val->type) { + case XPATH_UNDEFINED: + ret = xmlXPathNAN; + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: { + xmlChar *str; -/** - * 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); + str = xmlXPathCastNodeSetToString(val->nodesetval); + if (str == NULL) { + xmlXPathPErrMemory(ctxt); + ret = xmlXPathNAN; + } else { + ret = xmlXPathCastStringToNumber(str); + xmlFree(str); + } + break; + } + case XPATH_STRING: + ret = xmlXPathCastStringToNumber(val->stringval); + break; + case XPATH_NUMBER: + ret = val->floatval; + break; + case XPATH_BOOLEAN: + ret = xmlXPathCastBooleanToNumber(val->boolval); + break; + case XPATH_USERS: +#ifdef LIBXML_XPTR_LOCS_ENABLED + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: +#endif /* LIBXML_XPTR_LOCS_ENABLED */ + /* TODO */ + ret = xmlXPathNAN; + break; } - ctxt->valueFrame = frame; + return(ret); } /** @@ -2864,11 +2052,6 @@ valuePop(xmlXPathParserContextPtr ctxt) 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]; @@ -2887,6 +2070,8 @@ valuePop(xmlXPathParserContextPtr ctxt) * a memory error is recorded in the parser context. * * Returns the number of items on the value stack, or -1 in case of error. + * + * The object is destroyed in case of error. */ int valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) @@ -2894,24 +2079,25 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) if (ctxt == NULL) return(-1); if (value == NULL) { /* - * A NULL value typically indicates that a memory allocation failed, - * so we set ctxt->error here to propagate the error. + * A NULL value typically indicates that a memory allocation failed. */ - ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathPErrMemory(ctxt); return(-1); } if (ctxt->valueNr >= ctxt->valueMax) { xmlXPathObjectPtr *tmp; if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { - xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n"); + xmlXPathPErrMemory(ctxt); + xmlXPathFreeObject(value); return (-1); } tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2 * ctxt->valueMax * sizeof(ctxt->valueTab[0])); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "pushing value\n"); + xmlXPathPErrMemory(ctxt); + xmlXPathFreeObject(value); return (-1); } ctxt->valueMax *= 2; @@ -2969,7 +2155,7 @@ xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { return(0); } if (obj->type != XPATH_NUMBER) - ret = xmlXPathCastToNumber(obj); + ret = xmlXPathCastToNumberInternal(ctxt, obj); else ret = obj->floatval; xmlXPathReleaseObject(ctxt->context, obj); @@ -2995,10 +2181,9 @@ xmlXPathPopString (xmlXPathParserContextPtr ctxt) { xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); return(NULL); } - ret = xmlXPathCastToString(obj); /* this does required strdup */ - /* TODO: needs refactoring somewhere else */ - if (obj->stringval == ret) - obj->stringval = NULL; + ret = xmlXPathCastToString(obj); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathReleaseObject(ctxt->context, obj); return(ret); } @@ -3097,7 +2282,7 @@ xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) #define COPY_BUF(l,b,i,v) \ - if (l == 1) b[i++] = (xmlChar) v; \ + if (l == 1) b[i++] = v; \ else i += xmlCopyChar(l,&b[i],v) #define NEXTL(l) ctxt->cur += l @@ -3304,7 +2489,7 @@ xmlXPathOrderDocElems(xmlDocPtr doc) { } } while (cur != NULL); } - return((long) count); + return(count); } /** @@ -3527,16 +2712,25 @@ xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { * Allocate a new Namespace and fill the fields. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlXPathErrMemory(NULL, "duplicating namespace\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_NAMESPACE_DECL; - if (ns->href != NULL) + if (ns->href != NULL) { cur->href = xmlStrdup(ns->href); - if (ns->prefix != NULL) + if (cur->href == NULL) { + xmlFree(cur); + return(NULL); + } + } + if (ns->prefix != NULL) { cur->prefix = xmlStrdup(ns->prefix); + if (cur->prefix == NULL) { + xmlFree((xmlChar *) cur->href); + xmlFree(cur); + return(NULL); + } + } cur->next = (xmlNsPtr) node; return((xmlNodePtr) cur); } @@ -3576,28 +2770,28 @@ xmlXPathNodeSetCreate(xmlNodePtr val) { xmlNodeSetPtr ret; ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); + memset(ret, 0 , sizeof(xmlNodeSet)); if (val != NULL) { ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); if (ret->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); xmlFree(ret); return(NULL); } memset(ret->nodeTab, 0 , - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); ret->nodeMax = XML_NODESET_DEFAULT; if (val->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) val; + xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); - /* TODO: Check memory error. */ - ret->nodeTab[ret->nodeNr++] = - xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + if (nsNode == NULL) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } + ret->nodeTab[ret->nodeNr++] = nsNode; } else ret->nodeTab[ret->nodeNr++] = val; } @@ -3654,7 +2848,7 @@ xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { int xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { int i; - + xmlNodePtr nsNode; if ((cur == NULL) || (ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) || @@ -3679,31 +2873,27 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; - if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeMax *= 2; cur->nodeTab = temp; } - /* TODO: Check memory error. */ - cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); + nsNode = xmlXPathNodeSetDupNs(node, ns); + if(nsNode == NULL) + return(-1); + cur->nodeTab[cur->nodeNr++] = nsNode; return(0); } @@ -3735,35 +2925,30 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; - if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeMax *= 2; cur->nodeTab = temp; } if (val->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) val; + xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); - /* TODO: Check memory error. */ - cur->nodeTab[cur->nodeNr++] = - xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + if (nsNode == NULL) + return(-1); + cur->nodeTab[cur->nodeNr++] = nsNode; } else cur->nodeTab[cur->nodeNr++] = val; return(0); @@ -3790,35 +2975,30 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; - if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeTab = temp; cur->nodeMax *= 2; } if (val->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) val; + xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); - /* TODO: Check memory error. */ - cur->nodeTab[cur->nodeNr++] = - xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + if (nsNode == NULL) + return(-1); + cur->nodeTab[cur->nodeNr++] = nsNode; } else cur->nodeTab[cur->nodeNr++] = val; return(0); @@ -3833,45 +3013,21 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { * if @val1 is NULL, a new set is created and copied from @val2 * * Returns @val1 once extended or NULL in case of error. + * + * Frees @val1 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 helpful. - */ - /* - * 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 + if (val1 == NULL) + return (NULL); } + if (val2 == NULL) + return(val1); /* @@ with_ns to check whether namespace nodes should be looked at @@ */ initNr = val1->nodeNr; @@ -3907,40 +3063,39 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { if (val1->nodeMax == 0) { val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (val1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (val1->nodeTab == NULL) + goto error; memset(val1->nodeTab, 0 , - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); val1->nodeMax = XML_NODESET_DEFAULT; } else if (val1->nodeNr == val1->nodeMax) { xmlNodePtr *temp; - if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); - return(NULL); - } + if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) + goto error; temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (temp == NULL) + goto error; val1->nodeTab = temp; val1->nodeMax *= 2; } if (n2->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) n2; + xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); - /* TODO: Check memory error. */ - val1->nodeTab[val1->nodeNr++] = - xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + if (nsNode == NULL) + goto error; + val1->nodeTab[val1->nodeNr++] = nsNode; } else val1->nodeTab[val1->nodeNr++] = n2; } return(val1); + +error: + xmlXPathFreeNodeSet(val1); + return(NULL); } @@ -3953,6 +3108,8 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { * Checks for duplicate nodes. Clears set2. * * Returns @set1 once extended or NULL in case of error. + * + * Frees @set1 in case of error. */ static xmlNodeSetPtr xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) @@ -3981,7 +3138,6 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) /* * Free the namespace node. */ - set2->nodeTab[i] = NULL; xmlXPathNodeSetFreeNs((xmlNsPtr) n2); goto skip_node; } @@ -3993,36 +3149,35 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) if (set1->nodeMax == 0) { set1->nodeTab = (xmlNodePtr *) xmlMalloc( XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (set1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (set1->nodeTab == NULL) + goto error; memset(set1->nodeTab, 0, - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); set1->nodeMax = XML_NODESET_DEFAULT; } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp; - if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); - return(NULL); - } + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) + goto error; temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (temp == NULL) + goto error; set1->nodeTab = temp; set1->nodeMax *= 2; } set1->nodeTab[set1->nodeNr++] = n2; skip_node: - {} + set2->nodeTab[i] = NULL; } } set2->nodeNr = 0; return(set1); + +error: + xmlXPathFreeNodeSet(set1); + xmlXPathNodeSetClear(set2, 1); + return(NULL); } /** @@ -4034,6 +3189,8 @@ skip_node: * Doesn't check for duplicate nodes. Clears set2. * * Returns @set1 once extended or NULL in case of error. + * + * Frees @set1 in case of error. */ static xmlNodeSetPtr xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) @@ -4047,34 +3204,34 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) if (set1->nodeMax == 0) { set1->nodeTab = (xmlNodePtr *) xmlMalloc( XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (set1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (set1->nodeTab == NULL) + goto error; memset(set1->nodeTab, 0, - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); set1->nodeMax = XML_NODESET_DEFAULT; } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp; - if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); - return(NULL); - } + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) + goto error; temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); - return(NULL); - } + if (temp == NULL) + goto error; set1->nodeTab = temp; set1->nodeMax *= 2; } set1->nodeTab[set1->nodeNr++] = n2; + set2->nodeTab[i] = NULL; } } set2->nodeNr = 0; return(set1); + +error: + xmlXPathFreeNodeSet(set1); + xmlXPathNodeSetClear(set2, 1); + return(NULL); } /** @@ -4098,11 +3255,6 @@ xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 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) && @@ -4224,75 +3376,6 @@ xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) set->nodeNr = 1; } -/** - * xmlXPathFreeValueTree: - * @obj: the xmlNodeSetPtr to free - * - * Free the NodeSet compound and the actual tree, this is different - * from xmlXPathFreeNodeSet() - */ -static void -xmlXPathFreeValueTree(xmlNodeSetPtr obj) { - int i; - - if (obj == NULL) return; - - if (obj->nodeTab != NULL) { - for (i = 0;i < obj->nodeNr;i++) { - if (obj->nodeTab[i] != NULL) { - if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { - xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); - } else { - xmlFreeNodeList(obj->nodeTab[i]); - } - } - } - xmlFree(obj->nodeTab); - } - xmlFree(obj); -} - -#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 @@ -4307,19 +3390,17 @@ xmlXPathNewNodeSet(xmlNodePtr val) { xmlXPathObjectPtr ret; ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_NODESET; ret->boolval = 0; - /* TODO: Check memory error. */ ret->nodesetval = xmlXPathNodeSetCreate(val); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } /* @@ with_ns to check whether namespace nodes should be looked at @@ */ -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); -#endif return(ret); } @@ -4336,19 +3417,11 @@ xmlXPathObjectPtr xmlXPathNewValueTree(xmlNodePtr val) { xmlXPathObjectPtr ret; - ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating result value tree\n"); + ret = xmlXPathNewNodeSet(val); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (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); } @@ -4365,7 +3438,6 @@ xmlXPathObjectPtr xmlXPathNewNodeSetList(xmlNodeSetPtr val) { xmlXPathObjectPtr ret; - int i; if (val == NULL) ret = NULL; @@ -4374,12 +3446,12 @@ xmlXPathNewNodeSetList(xmlNodeSetPtr val) else { ret = xmlXPathNewNodeSet(val->nodeTab[0]); if (ret) { - for (i = 1; i < val->nodeNr; ++i) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) - < 0) break; - } - } + ret->nodesetval = xmlXPathNodeSetMerge(NULL, val); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } + } } return (ret); @@ -4392,6 +3464,8 @@ xmlXPathNewNodeSetList(xmlNodeSetPtr val) * Wrap the Nodeset @val in a new xmlXPathObjectPtr * * Returns the newly created object. + * + * In case of error the node set is destroyed and NULL is returned. */ xmlXPathObjectPtr xmlXPathWrapNodeSet(xmlNodeSetPtr val) { @@ -4399,15 +3473,12 @@ xmlXPathWrapNodeSet(xmlNodeSetPtr val) { ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating node set object\n"); + xmlXPathFreeNodeSet(val); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_NODESET; ret->nodesetval = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); -#endif return(ret); } @@ -4421,9 +3492,6 @@ xmlXPathWrapNodeSet(xmlNodeSetPtr val) { void xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { if (obj == NULL) return; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageReleased(NULL, obj->type); -#endif xmlFree(obj); } @@ -4447,8 +3515,9 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { if (xmlXPathNodeSetIsEmpty(nodes2)) return(nodes1); - /* TODO: Check memory error. */ ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(NULL); if (xmlXPathNodeSetIsEmpty(nodes1)) return(ret); @@ -4457,9 +3526,10 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { for (i = 0; i < l1; i++) { cur = xmlXPathNodeSetItem(nodes1, i); if (!xmlXPathNodeSetContains(nodes2, cur)) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } } return(ret); @@ -4494,9 +3564,10 @@ xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { for (i = 0; i < l1; i++) { cur = xmlXPathNodeSetItem(nodes1, i); if (xmlXPathNodeSetContains(nodes2, cur)) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } } return(ret); @@ -4532,16 +3603,23 @@ xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { cur = xmlXPathNodeSetItem(nodes, i); strval = xmlXPathCastNodeToString(cur); if (xmlHashLookup(hash, strval) == NULL) { - xmlHashAddEntry(hash, strval, strval); - /* TODO: Propagate memory error. */ + if (xmlHashAddEntry(hash, strval, strval) < 0) { + xmlFree(strval); + goto error; + } if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + goto error; } else { xmlFree(strval); } } xmlHashFree(hash, xmlHashDefaultDeallocator); return(ret); + +error: + xmlHashFree(hash, xmlHashDefaultDeallocator); + xmlXPathFreeNodeSet(ret); + return(NULL); } /** @@ -4627,9 +3705,10 @@ xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } return(ret); } @@ -4733,9 +3812,10 @@ xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } xmlXPathNodeSetSort(ret); /* bug 413451 */ return(ret); @@ -4843,6 +3923,8 @@ xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, int xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri, xmlXPathFunction f) { + int ret; + if (ctxt == NULL) return(-1); if (name == NULL) @@ -4850,13 +3932,21 @@ xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, if (ctxt->funcHash == NULL) ctxt->funcHash = xmlHashCreate(0); - if (ctxt->funcHash == NULL) + if (ctxt->funcHash == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } if (f == NULL) return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); -XML_IGNORE_PEDANTIC_WARNINGS - return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); +XML_IGNORE_FPTR_CAST_WARNINGS + ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f); XML_POP_WARNINGS + if (ret < 0) { + xmlXPathErrMemory(ctxt); + return(-1); + } + + return(0); } /** @@ -4937,7 +4027,7 @@ xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, if (ctxt->funcHash == NULL) return(NULL); -XML_IGNORE_PEDANTIC_WARNINGS +XML_IGNORE_FPTR_CAST_WARNINGS ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); XML_POP_WARNINGS return(ret); @@ -5085,8 +4175,7 @@ xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, if (name == NULL) return(NULL); - return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) - xmlHashLookup2(ctxt->varHash, name, ns_uri))); + return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri))); } /** @@ -5118,6 +4207,8 @@ xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { int xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, const xmlChar *ns_uri) { + xmlChar *copy; + if (ctxt == NULL) return(-1); if (prefix == NULL) @@ -5127,13 +4218,27 @@ xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, if (ctxt->nsHash == NULL) ctxt->nsHash = xmlHashCreate(10); - if (ctxt->nsHash == NULL) + if (ctxt->nsHash == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } if (ns_uri == NULL) return(xmlHashRemoveEntry(ctxt->nsHash, prefix, xmlHashDefaultDeallocator)); - return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), - xmlHashDefaultDeallocator)); + + copy = xmlStrdup(ns_uri); + if (copy == NULL) { + xmlXPathErrMemory(ctxt); + return(-1); + } + if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy, + xmlHashDefaultDeallocator) < 0) { + xmlXPathErrMemory(ctxt); + xmlFree(copy); + return(-1); + } + + return(0); } /** @@ -5153,10 +4258,8 @@ xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { if (prefix == NULL) return(NULL); -#ifdef XML_XML_NAMESPACE if (xmlStrEqual(prefix, (const xmlChar *) "xml")) return(XML_XML_NAMESPACE); -#endif if (ctxt->namespaces != NULL) { int i; @@ -5207,16 +4310,11 @@ xmlXPathNewFloat(double val) { xmlXPathObjectPtr ret; ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating float object\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_NUMBER; ret->floatval = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); -#endif return(ret); } @@ -5233,16 +4331,11 @@ xmlXPathNewBoolean(int val) { xmlXPathObjectPtr ret; ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating boolean object\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_BOOLEAN; ret->boolval = (val != 0); -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); -#endif return(ret); } @@ -5259,19 +4352,17 @@ xmlXPathNewString(const xmlChar *val) { xmlXPathObjectPtr ret; ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating string object\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , 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 + if (val == NULL) + val = BAD_CAST ""; + ret->stringval = xmlStrdup(val); + if (ret->stringval == NULL) { + xmlFree(ret); + return(NULL); + } return(ret); } @@ -5282,6 +4373,8 @@ xmlXPathNewString(const xmlChar *val) { * Wraps the @val string into an XPath object. * * Returns the newly created object. + * + * Frees @val in case of error. */ xmlXPathObjectPtr xmlXPathWrapString (xmlChar *val) { @@ -5289,15 +4382,12 @@ xmlXPathWrapString (xmlChar *val) { ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating string object\n"); + xmlFree(val); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_STRING; ret->stringval = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); -#endif return(ret); } @@ -5311,20 +4401,7 @@ xmlXPathWrapString (xmlChar *val) { */ 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); + return(xmlXPathNewString(BAD_CAST val)); } /** @@ -5353,16 +4430,11 @@ xmlXPathWrapExternal (void *val) { xmlXPathObjectPtr ret; ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating user object\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_USERS; ret->user = val; -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); -#endif return(ret); } @@ -5382,14 +4454,9 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { return(NULL); ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "copying object\n"); + if (ret == NULL) return(NULL); - } - memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageRequested(NULL, val->type); -#endif + memcpy(ret, val , sizeof(xmlXPathObject)); switch (val->type) { case XPATH_BOOLEAN: case XPATH_NUMBER: @@ -5400,6 +4467,10 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { break; case XPATH_STRING: ret->stringval = xmlStrdup(val->stringval); + if (ret->stringval == NULL) { + xmlFree(ret); + return(NULL); + } break; case XPATH_XSLT_TREE: #if 0 @@ -5435,8 +4506,11 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { break; #endif case XPATH_NODESET: - /* TODO: Check memory error. */ ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } /* Do not deallocate the copied tree value */ ret->boolval = 0; break; @@ -5451,10 +4525,9 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { case XPATH_USERS: ret->user = val->user; break; - case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, - "xmlXPathObjectCopy: unsupported type %d\n", - val->type); + default: + xmlFree(ret); + ret = NULL; break; } return(ret); @@ -5470,20 +4543,8 @@ void xmlXPathFreeObject(xmlXPathObjectPtr obj) { if (obj == NULL) return; if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { - if (obj->boolval) { -#if 0 - if (obj->user != NULL) { - xmlXPathFreeNodeSet(obj->nodesetval); - xmlFreeNodeList((xmlNodePtr) obj->user); - } else -#endif - obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ - if (obj->nodesetval != NULL) - xmlXPathFreeValueTree(obj->nodesetval); - } else { - if (obj->nodesetval != NULL) - xmlXPathFreeNodeSet(obj->nodesetval); - } + if (obj->nodesetval != NULL) + xmlXPathFreeNodeSet(obj->nodesetval); #ifdef LIBXML_XPTR_LOCS_ENABLED } else if (obj->type == XPATH_LOCATIONSET) { if (obj->user != NULL) @@ -5493,9 +4554,6 @@ xmlXPathFreeObject(xmlXPathObjectPtr obj) { if (obj->stringval != NULL) xmlFree(obj->stringval); } -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageReleased(NULL, obj->type); -#endif xmlFree(obj); } @@ -5514,12 +4572,6 @@ xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { static void xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) { -#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ - sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ - if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; - -#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) - if (obj == NULL) return; if ((ctxt == NULL) || (ctxt->cache == NULL)) { @@ -5532,20 +4584,11 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) case XPATH_NODESET: case XPATH_XSLT_TREE: if (obj->nodesetval != NULL) { - if (obj->boolval) { - /* - * It looks like the @boolval is used for - * evaluation if this an XSLT Result Tree Fragment. - * TODO: Check if this assumption is correct. - */ - obj->type = XPATH_XSLT_TREE; /* just for debugging */ - xmlXPathFreeValueTree(obj->nodesetval); - obj->nodesetval = NULL; - } else if ((obj->nodesetval->nodeMax <= 40) && - (XP_CACHE_WANTS(cache->nodesetObjs, - cache->maxNodeset))) - { - XP_CACHE_ADD(cache->nodesetObjs, obj); + if ((obj->nodesetval->nodeMax <= 40) && + (cache->numNodeset < cache->maxNodeset)) { + obj->stringval = (void *) cache->nodesetObjs; + cache->nodesetObjs = obj; + cache->numNodeset += 1; goto obj_cached; } else { xmlXPathFreeNodeSet(obj->nodesetval); @@ -5556,23 +4599,10 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) case XPATH_STRING: if (obj->stringval != NULL) xmlFree(obj->stringval); - - if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { - XP_CACHE_ADD(cache->stringObjs, obj); - goto obj_cached; - } + obj->stringval = NULL; break; case XPATH_BOOLEAN: - if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { - XP_CACHE_ADD(cache->booleanObjs, obj); - goto obj_cached; - } - break; case XPATH_NUMBER: - if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { - XP_CACHE_ADD(cache->numberObjs, obj); - goto obj_cached; - } break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_LOCATIONSET: @@ -5588,27 +4618,22 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) /* * Fallback to adding to the misc-objects slot. */ - if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { - XP_CACHE_ADD(cache->miscObjs, obj); - } else + if (cache->numMisc >= cache->maxMisc) goto free_obj; + obj->stringval = (void *) cache->miscObjs; + cache->miscObjs = obj; + cache->numMisc += 1; obj_cached: - -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageReleased(ctxt, obj->type); -#endif - + obj->boolval = 0; if (obj->nodesetval != NULL) { xmlNodeSetPtr tmpset = obj->nodesetval; /* - * TODO: Due to those nasty ns-nodes, we need to traverse - * the list and free the ns-nodes. - * URGENT TODO: Check if it's actually slowing things down. - * Maybe we shouldn't try to preserve the list. + * Due to those nasty ns-nodes, we need to traverse + * the list and free the ns-nodes. */ - if (tmpset->nodeNr > 1) { + if (tmpset->nodeNr > 0) { int i; xmlNodePtr node; @@ -5620,16 +4645,9 @@ obj_cached: xmlXPathNodeSetFreeNs((xmlNsPtr) node); } } - } else if (tmpset->nodeNr == 1) { - if ((tmpset->nodeTab[0] != NULL) && - (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) - xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); } tmpset->nodeNr = 0; - memset(obj, 0, sizeof(xmlXPathObject)); - obj->nodesetval = tmpset; - } else - memset(obj, 0, sizeof(xmlXPathObject)); + } return; @@ -5639,9 +4657,6 @@ free_obj: */ if (obj->nodesetval != NULL) xmlXPathFreeNodeSet(obj->nodesetval); -#ifdef XP_DEBUG_OBJ_USAGE - xmlXPathDebugObjUsageReleased(NULL, obj->type); -#endif xmlFree(obj); } return; @@ -5717,10 +4732,7 @@ xmlXPathCastNumberToString (double val) { */ xmlChar * xmlXPathCastNodeToString (xmlNodePtr node) { -xmlChar *ret; - if ((ret = xmlNodeGetContent(node)) == NULL) - ret = xmlStrdup((const xmlChar *) ""); - return(ret); + return(xmlNodeGetContent(node)); } /** @@ -5758,9 +4770,6 @@ xmlXPathCastToString(xmlXPathObjectPtr val) { 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: @@ -5782,7 +4791,7 @@ xmlXPathCastToString(xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ ret = xmlStrdup((const xmlChar *) ""); break; } @@ -5807,9 +4816,6 @@ xmlXPathConvertString(xmlXPathObjectPtr val) { switch (val->type) { case XPATH_UNDEFINED: -#ifdef DEBUG_EXPR - xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); -#endif break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -5829,7 +4835,7 @@ xmlXPathConvertString(xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; + /* TODO */ break; } xmlXPathFreeObject(val); @@ -5867,29 +4873,44 @@ xmlXPathCastStringToNumber(const xmlChar * val) { } /** - * xmlXPathCastNodeToNumber: + * xmlXPathNodeToNumberInternal: * @node: a node * * Converts a node to its number value * * Returns the number value */ -double -xmlXPathCastNodeToNumber (xmlNodePtr node) { +static double +xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) { xmlChar *strval; double ret; if (node == NULL) return(xmlXPathNAN); strval = xmlXPathCastNodeToString(node); - if (strval == NULL) + if (strval == NULL) { + xmlXPathPErrMemory(ctxt); return(xmlXPathNAN); + } ret = xmlXPathCastStringToNumber(strval); xmlFree(strval); return(ret); } +/** + * xmlXPathCastNodeToNumber: + * @node: a node + * + * Converts a node to its number value + * + * Returns the number value + */ +double +xmlXPathCastNodeToNumber (xmlNodePtr node) { + return(xmlXPathNodeToNumberInternal(NULL, node)); +} + /** * xmlXPathCastNodeSetToNumber: * @ns: a node-set @@ -5921,41 +4942,7 @@ xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { */ double xmlXPathCastToNumber(xmlXPathObjectPtr val) { - double ret = 0.0; - - if (val == NULL) - return(xmlXPathNAN); - switch (val->type) { - case XPATH_UNDEFINED: -#ifdef DEBUG_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: -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - case XPATH_RANGE: - case XPATH_LOCATIONSET: -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; - ret = xmlXPathNAN; - break; - } - return(ret); + return(xmlXPathCastToNumberInternal(NULL, val)); } /** @@ -6041,9 +5028,6 @@ xmlXPathCastToBoolean (xmlXPathObjectPtr val) { return(0); switch (val->type) { case XPATH_UNDEFINED: -#ifdef DEBUG_EXPR - xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); -#endif ret = 0; break; case XPATH_NODESET: @@ -6065,7 +5049,7 @@ xmlXPathCastToBoolean (xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; + /* TODO */ ret = 0; break; } @@ -6114,11 +5098,9 @@ xmlXPathNewContext(xmlDocPtr doc) { xmlXPathContextPtr ret; ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating context\n"); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); + memset(ret, 0 , sizeof(xmlXPathContext)); ret->doc = doc; ret->node = NULL; @@ -6128,8 +5110,6 @@ xmlXPathNewContext(xmlDocPtr doc) { ret->max_types = 0; ret->types = NULL; - ret->funcHash = xmlHashCreate(0); - ret->nb_axis = 0; ret->max_axis = 0; ret->axis = NULL; @@ -6149,6 +5129,11 @@ xmlXPathNewContext(xmlDocPtr doc) { xmlXPathRegisterAllFunctions(ret); + if (ret->lastError.code != XML_ERR_OK) { + xmlXPathFreeContext(ret); + return(NULL); + } + return(ret); } @@ -6171,43 +5156,33 @@ xmlXPathFreeContext(xmlXPathContextPtr ctxt) { xmlFree(ctxt); } +/** + * xmlXPathSetErrorHandler: + * @ctxt: the XPath context + * @handler: error handler + * @data: user data which will be passed to the handler + * + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * Available since 2.13.0. + */ +void +xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt, + xmlStructuredErrorFunc handler, void *data) { + if (ctxt == NULL) + return; + + ctxt->error = handler; + ctxt->userData = data; +} + /************************************************************************ * * * Routines to handle XPath parser contexts * * * ************************************************************************/ -#define CHECK_CTXT(ctxt) \ - if (ctxt == NULL) { \ - __xmlRaiseError(NULL, NULL, NULL, \ - NULL, NULL, XML_FROM_XPATH, \ - XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ - __FILE__, __LINE__, \ - NULL, NULL, NULL, 0, 0, \ - "NULL context pointer\n"); \ - return(NULL); \ - } \ - -#define CHECK_CTXT_NEG(ctxt) \ - if (ctxt == NULL) { \ - __xmlRaiseError(NULL, NULL, NULL, \ - NULL, NULL, XML_FROM_XPATH, \ - XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ - __FILE__, __LINE__, \ - NULL, NULL, NULL, 0, 0, \ - "NULL context pointer\n"); \ - return(-1); \ - } \ - - -#define CHECK_CONTEXT(ctxt) \ - if ((ctxt == NULL) || (ctxt->doc == NULL) || \ - (ctxt->doc->children == NULL)) { \ - xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ - return(NULL); \ - } - - /** * xmlXPathNewParserContext: * @str: the XPath expression @@ -6223,15 +5198,16 @@ xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); if (ret == NULL) { - xmlXPathErrMemory(ctxt, "creating parser context\n"); + xmlXPathErrMemory(ctxt); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); + memset(ret, 0 , sizeof(xmlXPathParserContext)); ret->cur = ret->base = str; ret->context = ctxt; ret->comp = xmlXPathNewCompExpr(); if (ret->comp == NULL) { + xmlXPathErrMemory(ctxt); xmlFree(ret->valueTab); xmlFree(ret); return(NULL); @@ -6259,23 +5235,22 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); if (ret == NULL) { - xmlXPathErrMemory(ctxt, "creating evaluation context\n"); + xmlXPathErrMemory(ctxt); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); + memset(ret, 0 , 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"); + xmlXPathErrMemory(ctxt); return(NULL); } ret->valueNr = 0; ret->valueMax = 10; ret->value = NULL; - ret->valueFrame = 0; ret->context = ctxt; ret->comp = comp; @@ -6360,16 +5335,14 @@ xmlXPathNodeValHash(xmlNodePtr node) { return(0); if (string[0] == 0) return(0); - return(((unsigned int) string[0]) + - (((unsigned int) string[1]) << 8)); + return(string[0] + (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)); + return(string[0] + (string[1] << 8)); case XML_ATTRIBUTE_NODE: tmp = ((xmlAttrPtr) node)->children; break; @@ -6391,24 +5364,24 @@ xmlXPathNodeValHash(xmlNodePtr node) { } if ((string != NULL) && (string[0] != 0)) { if (len == 1) { - return(ret + (((unsigned int) string[0]) << 8)); + return(ret + (string[0] << 8)); } if (string[1] == 0) { len = 1; - ret = (unsigned int) string[0]; + ret = string[0]; } else { - return(((unsigned int) string[0]) + - (((unsigned int) string[1]) << 8)); + return(string[0] + (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->children != NULL) && + (tmp->type != XML_DTD_NODE) && + (tmp->type != XML_ENTITY_REF_NODE) && + (tmp->children->type != XML_ENTITY_DECL)) { + tmp = tmp->children; + continue; } if (tmp == node) break; @@ -6447,11 +5420,10 @@ xmlXPathNodeValHash(xmlNodePtr node) { static unsigned int xmlXPathStringHash(const xmlChar * string) { if (string == NULL) - return((unsigned int) 0); + return(0); if (string[0] == 0) return(0); - return(((unsigned int) string[0]) + - (((unsigned int) string[1]) << 8)); + return(string[0] + (string[1] << 8)); } /** @@ -6494,15 +5466,16 @@ xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, for (i = 0;i < ns->nodeNr;i++) { str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, str2)); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); xmlXPathNumberFunction(ctxt, 1); - valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f)); ret = xmlXPathCompareValues(ctxt, inf, strict); if (ret) break; - } + } else { + xmlXPathPErrMemory(ctxt); + } } } xmlXPathReleaseObject(ctxt->context, arg); @@ -6550,13 +5523,15 @@ xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, str2)); + xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); - valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s)); ret = xmlXPathCompareValues(ctxt, inf, strict); if (ret) break; - } + } else { + xmlXPathPErrMemory(ctxt); + } } } xmlXPathReleaseObject(ctxt->context, arg); @@ -6593,7 +5568,7 @@ xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, * and then the comparison must be done when possible */ static int -xmlXPathCompareNodeSets(int inf, int strict, +xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict, xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { int i, j, init = 0; double val1; @@ -6630,19 +5605,19 @@ xmlXPathCompareNodeSets(int inf, int strict, values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); if (values2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlXPathFreeObject(arg1); xmlXPathFreeObject(arg2); return(0); } for (i = 0;i < ns1->nodeNr;i++) { - val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); + val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]); if (xmlXPathIsNaN(val1)) continue; for (j = 0;j < ns2->nodeNr;j++) { if (init == 0) { - values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); + values2[j] = xmlXPathNodeToNumberInternal(ctxt, + ns2->nodeTab[j]); } if (xmlXPathIsNaN(values2[j])) continue; @@ -6700,7 +5675,7 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); case XPATH_NODESET: case XPATH_XSLT_TREE: - return(xmlXPathCompareNodeSets(inf, strict, arg, val)); + return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val)); case XPATH_STRING: return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); case XPATH_BOOLEAN: @@ -6709,10 +5684,6 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, valuePush(ctxt, val); return(xmlXPathCompareValues(ctxt, inf, strict)); default: - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompareNodeSetValue: Can't compare node set " - "and object of type %d\n", - val->type); xmlXPathReleaseObject(ctxt->context, arg); xmlXPathReleaseObject(ctxt->context, val); XP_ERROR0(XPATH_INVALID_TYPE); @@ -6735,7 +5706,8 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, * Returns 0 or 1 depending on the results of the test. */ static int -xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) +xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr arg, const xmlChar * str, int neq) { int i; xmlNodeSetPtr ns; @@ -6756,22 +5728,20 @@ xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) for (i = 0; i < ns->nodeNr; i++) { if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { str2 = xmlNodeGetContent(ns->nodeTab[i]); - if ((str2 != NULL) && (xmlStrEqual(str, str2))) { + if (str2 == NULL) { + xmlXPathPErrMemory(ctxt); + return(0); + } + if (xmlStrEqual(str, str2)) { xmlFree(str2); if (neq) continue; return (1); - } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { - if (neq) - continue; - return (1); } else if (neq) { - if (str2 != NULL) - xmlFree(str2); + xmlFree(str2); return (1); } - if (str2 != NULL) - xmlFree(str2); + xmlFree(str2); } else if (neq) return (1); } @@ -6811,9 +5781,10 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, for (i=0;inodeNr;i++) { str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); xmlXPathNumberFunction(ctxt, 1); + CHECK_ERROR0; val = valuePop(ctxt); v = val->floatval; xmlXPathReleaseObject(ctxt->context, val); @@ -6829,7 +5800,9 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, if (neq) ret = 1; } - } + } else { + xmlXPathPErrMemory(ctxt); + } } } @@ -6855,7 +5828,8 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, * Returns 0 or 1 depending on the results of the test. */ static int -xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { +xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1, + xmlXPathObjectPtr arg2, int neq) { int i, j; unsigned int *hashs1; unsigned int *hashs2; @@ -6891,30 +5865,26 @@ xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); if (values1 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); return(0); } hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); if (hashs1 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(values1); return(0); } memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); if (values2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(hashs1); xmlFree(values1); return(0); } hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); if (hashs2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(hashs1); xmlFree(values1); xmlFree(values2); @@ -6933,10 +5903,16 @@ xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { } } else { - if (values1[i] == NULL) + if (values1[i] == NULL) { values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); - if (values2[j] == NULL) + if (values1[i] == NULL) + xmlXPathPErrMemory(ctxt); + } + if (values2[j] == NULL) { values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); + if (values2[j] == NULL) + xmlXPathPErrMemory(ctxt); + } ret = xmlStrEqual(values1[i], values2[j]) ^ neq; if (ret) break; @@ -6968,25 +5944,12 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, */ 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: @@ -7006,7 +5969,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -7016,10 +5979,6 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 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== @@ -7029,6 +5988,8 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, valuePush(ctxt, arg2); xmlXPathNumberFunction(ctxt, 1); arg2 = valuePop(ctxt); + if (ctxt->error) + break; /* Falls through. */ case XPATH_NUMBER: /* Hand check NaN and Infinity equalities */ @@ -7065,7 +6026,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -7075,10 +6036,6 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 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) || @@ -7094,6 +6051,8 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, valuePush(ctxt, arg1); xmlXPathNumberFunction(ctxt, 1); arg1 = valuePop(ctxt); + if (ctxt->error) + break; /* Hand check NaN and Infinity equalities */ if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { @@ -7128,7 +6087,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -7141,7 +6100,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -7177,10 +6136,6 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { } if (arg1 == arg2) { -#ifdef DEBUG_EXPR - xmlGenericError(xmlGenericErrorContext, - "Equal: by pointer\n"); -#endif xmlXPathFreeObject(arg1); return(1); } @@ -7200,14 +6155,10 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { } 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); + ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0); break; case XPATH_BOOLEAN: if ((arg1->nodesetval == NULL) || @@ -7220,7 +6171,8 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); break; case XPATH_STRING: - ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); + ret = xmlXPathEqualNodeSetString(ctxt, arg1, + arg2->stringval, 0); break; case XPATH_USERS: #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -7228,7 +6180,7 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; } xmlXPathReleaseObject(ctxt->context, arg1); @@ -7264,10 +6216,6 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { } if (arg1 == arg2) { -#ifdef DEBUG_EXPR - xmlGenericError(xmlGenericErrorContext, - "NotEqual: by pointer\n"); -#endif xmlXPathReleaseObject(ctxt->context, arg1); return(0); } @@ -7287,14 +6235,10 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { } 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); + ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1); break; case XPATH_BOOLEAN: if ((arg1->nodesetval == NULL) || @@ -7307,7 +6251,8 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); break; case XPATH_STRING: - ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); + ret = xmlXPathEqualNodeSetString(ctxt, arg1, + arg2->stringval, 1); break; case XPATH_USERS: #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -7315,7 +6260,7 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; } xmlXPathReleaseObject(ctxt->context, arg1); @@ -7375,7 +6320,7 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { */ if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ - ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); + ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2); } else { if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, @@ -7393,21 +6338,13 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 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); - } + if (ctxt->error) + goto error; /* * Add tests for infinity and nan * => feedback on 3.4 for Inf and NaN @@ -7457,6 +6394,7 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { } } } +error: xmlXPathReleaseObject(ctxt->context, arg1); xmlXPathReleaseObject(ctxt->context, arg2); return(ret); @@ -7494,7 +6432,7 @@ xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -7517,7 +6455,7 @@ xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -7540,7 +6478,7 @@ xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -7564,7 +6502,7 @@ xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -7587,7 +6525,7 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - arg2 = xmlXPathCastToNumber(arg); + arg2 = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -8391,14 +7329,17 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { if (cur == NULL) { if (ctxt->context->tmpNsList != NULL) xmlFree(ctxt->context->tmpNsList); - ctxt->context->tmpNsList = - xmlGetNsList(ctxt->context->doc, ctxt->context->node); ctxt->context->tmpNsNr = 0; - if (ctxt->context->tmpNsList != NULL) { - while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { - ctxt->context->tmpNsNr++; - } - } + if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node, + &ctxt->context->tmpNsList) < 0) { + xmlXPathPErrMemory(ctxt); + return(NULL); + } + if (ctxt->context->tmpNsList != NULL) { + while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { + ctxt->context->tmpNsNr++; + } + } return((xmlNodePtr) xmlXPathXMLNamespace); } if (ctxt->context->tmpNsNr > 0) { @@ -8461,8 +7402,8 @@ void xmlXPathRoot(xmlXPathParserContextPtr ctxt) { if ((ctxt == NULL) || (ctxt->context == NULL)) return; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - (xmlNodePtr) ctxt->context->doc)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, + (xmlNodePtr) ctxt->context->doc)); } /************************************************************************ @@ -8487,12 +7428,7 @@ 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 + xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize)); } else { XP_ERROR(XPATH_INVALID_CTXT_SIZE); } @@ -8513,13 +7449,8 @@ void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); if (ctxt->context->proximityPosition >= 0) { - valuePush(ctxt, - xmlXPathCacheNewFloat(ctxt->context, - (double) ctxt->context->proximityPosition)); -#ifdef DEBUG_EXPR - xmlGenericError(xmlGenericErrorContext, "position() : %d\n", - ctxt->context->proximityPosition); -#endif + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, + (double) ctxt->context->proximityPosition)); } else { XP_ERROR(XPATH_INVALID_CTXT_POSITION); } @@ -8545,9 +7476,9 @@ xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt); if ((cur == NULL) || (cur->nodesetval == NULL)) - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0)); else - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, (double) cur->nodesetval->nodeNr)); xmlXPathReleaseObject(ctxt->context, cur); } @@ -8581,28 +7512,33 @@ xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { cur++; ID = xmlStrndup(ids, cur - ids); - if (ID != NULL) { - /* - * We used to check the fact that the value passed - * was an NCName, but this generated much troubles for - * me and Aleksey Sanin, people blatantly violated that - * constraint, like Visa3D spec. - * if (xmlValidateNCName(ID, 1) == 0) - */ - attr = xmlGetID(doc, ID); - if (attr != NULL) { - if (attr->type == XML_ATTRIBUTE_NODE) - elem = attr->parent; - else if (attr->type == XML_ELEMENT_NODE) - elem = (xmlNodePtr) attr; - else - elem = NULL; - /* TODO: Check memory error. */ - if (elem != NULL) - xmlXPathNodeSetAdd(ret, elem); - } - xmlFree(ID); - } + if (ID == NULL) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } + /* + * We used to check the fact that the value passed + * was an NCName, but this generated much troubles for + * me and Aleksey Sanin, people blatantly violated that + * constraint, like Visa3D spec. + * if (xmlValidateNCName(ID, 1) == 0) + */ + attr = xmlGetID(doc, ID); + xmlFree(ID); + if (attr != NULL) { + if (attr->type == XML_ATTRIBUTE_NODE) + elem = attr->parent; + else if (attr->type == XML_ELEMENT_NODE) + elem = (xmlNodePtr) attr; + else + elem = NULL; + if (elem != NULL) { + if (xmlXPathNodeSetAdd(ret, elem) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } + } + } while (IS_BLANK_CH(*cur)) cur++; ids = cur; @@ -8641,30 +7577,40 @@ xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns; int i; - /* TODO: Check memory error. */ ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); if (obj->nodesetval != NULL) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { tokens = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); + if (tokens == NULL) + xmlXPathPErrMemory(ctxt); ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); - /* TODO: Check memory error. */ + if (ns == NULL) + xmlXPathPErrMemory(ctxt); ret = xmlXPathNodeSetMerge(ret, ns); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathFreeNodeSet(ns); if (tokens != NULL) xmlFree(tokens); } } xmlXPathReleaseObject(ctxt->context, obj); - valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret)); return; } - obj = xmlXPathCacheConvertString(ctxt->context, obj); - if (obj == NULL) return; - ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); - valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + tokens = xmlXPathCastToString(obj); + if (tokens == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathReleaseObject(ctxt->context, obj); + ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + xmlFree(tokens); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret)); return; } @@ -8688,8 +7634,7 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; } @@ -8701,7 +7646,7 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt); if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */ switch (cur->nodesetval->nodeTab[i]->type) { @@ -8709,18 +7654,17 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { case XML_ATTRIBUTE_NODE: case XML_PI_NODE: if (cur->nodesetval->nodeTab[i]->name[0] == ' ') - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); else - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->name)); break; case XML_NAMESPACE_DECL: - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); break; default: - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } } xmlXPathReleaseObject(ctxt->context, cur); @@ -8747,8 +7691,7 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; } CHECK_ARITY(1); @@ -8759,20 +7702,20 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt); if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */ switch (cur->nodesetval->nodeTab[i]->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: if (cur->nodesetval->nodeTab[i]->ns == NULL) - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); else - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->ns->href)); break; default: - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } } xmlXPathReleaseObject(ctxt->context, cur); @@ -8806,8 +7749,7 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathObjectPtr cur; if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; } @@ -8819,7 +7761,7 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) cur = valuePop(ctxt); if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */ @@ -8828,11 +7770,10 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) case XML_ATTRIBUTE_NODE: if (cur->nodesetval->nodeTab[i]->name[0] == ' ') valuePush(ctxt, - xmlXPathCacheNewCString(ctxt->context, "")); + xmlXPathCacheNewCString(ctxt, "")); else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->name)); } else { xmlChar *fullname; @@ -8842,15 +7783,13 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 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)); + if (fullname == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname)); } break; default: - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, cur->nodesetval->nodeTab[i])); xmlXPathLocalNameFunction(ctxt, 1); } @@ -8898,19 +7837,28 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr cur; + xmlChar *stringval; if (ctxt == NULL) return; if (nargs == 0) { - valuePush(ctxt, - xmlXPathCacheWrapString(ctxt->context, - xmlXPathCastNodeToString(ctxt->context->node))); + stringval = xmlXPathCastNodeToString(ctxt->context->node); + if (stringval == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval)); return; } CHECK_ARITY(1); cur = valuePop(ctxt); if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); + if (cur->type != XPATH_STRING) { + stringval = xmlXPathCastToString(cur); + if (stringval == NULL) + xmlXPathPErrMemory(ctxt); + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheWrapString(ctxt, stringval); + } + valuePush(ctxt, cur); } /** @@ -8933,12 +7881,14 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { if ((ctxt == NULL) || (ctxt->context == NULL)) return; if (ctxt->context->node == NULL) { - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0)); } else { xmlChar *content; content = xmlXPathCastNodeToString(ctxt->context->node); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + if (content == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, xmlUTF8Strlen(content))); xmlFree(content); } @@ -8948,7 +7898,7 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { CAST_TO_STRING; CHECK_TYPE(XPATH_STRING); cur = valuePop(ctxt); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, xmlUTF8Strlen(cur->stringval))); xmlXPathReleaseObject(ctxt->context, cur); } @@ -8989,6 +7939,8 @@ xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { XP_ERROR(XPATH_INVALID_TYPE); } tmp = xmlStrcat(newobj->stringval, cur->stringval); + if (tmp == NULL) + xmlXPathPErrMemory(ctxt); newobj->stringval = cur->stringval; cur->stringval = tmp; xmlXPathReleaseObject(ctxt->context, newobj); @@ -9024,9 +7976,9 @@ xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { XP_ERROR(XPATH_INVALID_TYPE); } if (xmlStrstr(hay->stringval, needle->stringval)) - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); else - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); xmlXPathReleaseObject(ctxt->context, hay); xmlXPathReleaseObject(ctxt->context, needle); } @@ -9060,9 +8012,9 @@ xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { } n = xmlStrlen(needle->stringval); if (xmlStrncmp(hay->stringval, needle->stringval, n)) - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); else - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); xmlXPathReleaseObject(ctxt->context, hay); xmlXPathReleaseObject(ctxt->context, needle); } @@ -9154,12 +8106,17 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { } } - if (i < j) { - xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i); - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); + i -= 1; + j -= 1; + + if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) { + xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret)); xmlFree(ret); } else { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } xmlXPathReleaseObject(ctxt->context, str); @@ -9180,31 +8137,34 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr find; - xmlBufPtr target; - const xmlChar *point; - int offset; - - CHECK_ARITY(2); - CAST_TO_STRING; - find = valuePop(ctxt); - CAST_TO_STRING; - str = valuePop(ctxt); - - target = xmlBufCreate(); - if (target) { + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr find = NULL; + const xmlChar *point; + xmlChar *result; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + if (ctxt->error != 0) + goto error; + point = xmlStrstr(str->stringval, find->stringval); - if (point) { - offset = (int)(point - str->stringval); - xmlBufAdd(target, str->stringval, offset); + if (point == NULL) { + result = xmlStrdup(BAD_CAST ""); + } else { + result = xmlStrndup(str->stringval, point - str->stringval); } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); - xmlBufFree(target); - } - xmlXPathReleaseObject(ctxt->context, str); - xmlXPathReleaseObject(ctxt->context, find); + if (result == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; + } + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result)); + +error: + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); } /** @@ -9216,39 +8176,41 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { * string substring-after(string, string) * The substring-after function returns the substring of the first * argument string that follows the first occurrence of the second - * argument string in the first argument string, or the empty stringi + * argument string in the first argument string, or the empty string * if the first argument string does not contain the second argument * string. For example, substring-after("1999/04/01","/") returns 04/01, * and substring-after("1999/04/01","19") returns 99/04/01. */ void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr find; - xmlBufPtr target; - const xmlChar *point; - int offset; - - CHECK_ARITY(2); - CAST_TO_STRING; - find = valuePop(ctxt); - CAST_TO_STRING; - str = valuePop(ctxt); - - target = xmlBufCreate(); - if (target) { + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr find = NULL; + const xmlChar *point; + xmlChar *result; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + if (ctxt->error != 0) + goto error; + point = xmlStrstr(str->stringval, find->stringval); - if (point) { - offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); - xmlBufAdd(target, &str->stringval[offset], - xmlStrlen(str->stringval) - offset); + if (point == NULL) { + result = xmlStrdup(BAD_CAST ""); + } else { + result = xmlStrdup(point + xmlStrlen(find->stringval)); } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); - xmlBufFree(target); - } - xmlXPathReleaseObject(ctxt->context, str); - xmlXPathReleaseObject(ctxt->context, find); + if (result == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; + } + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result)); + +error: + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); } /** @@ -9273,9 +8235,10 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { /* Use current context node */ - valuePush(ctxt, - xmlXPathCacheWrapString(ctxt->context, - xmlXPathCastNodeToString(ctxt->context->node))); + source = xmlXPathCastNodeToString(ctxt->context->node); + if (source == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source)); nargs = 1; } @@ -9331,14 +8294,14 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr from; - xmlXPathObjectPtr to; + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr from = NULL; + xmlXPathObjectPtr to = NULL; xmlBufPtr target; int offset, max; - xmlChar ch; + int ch; const xmlChar *point; - xmlChar *cptr; + xmlChar *cptr, *content; CHECK_ARITY(3); @@ -9348,47 +8311,71 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { from = valuePop(ctxt); CAST_TO_STRING; str = valuePop(ctxt); + if (ctxt->error != 0) + goto error; - target = xmlBufCreate(); - if (target) { - max = xmlUTF8Strlen(to->stringval); - for (cptr = str->stringval; (ch=*cptr); ) { - offset = xmlUTF8Strloc(from->stringval, cptr); - if (offset >= 0) { - if (offset < max) { - point = xmlUTF8Strpos(to->stringval, offset); - if (point) - xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); - } - } else - xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); - - /* Step to next character in input */ - cptr++; - if ( ch & 0x80 ) { - /* if not simple ascii, verify proper format */ - if ( (ch & 0xc0) != 0xc0 ) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathTranslateFunction: Invalid UTF8 string\n"); - /* not asserting an XPath error is probably better */ - break; - } - /* then skip over remaining bytes for this char */ - while ( (ch <<= 1) & 0x80 ) - if ( (*cptr++ & 0xc0) != 0x80 ) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathTranslateFunction: Invalid UTF8 string\n"); - /* not asserting an XPath error is probably better */ - break; - } - if (ch & 0x80) /* must have had error encountered */ - break; - } - } + /* + * Account for quadratic runtime + */ + if (ctxt->context->opLimit != 0) { + unsigned long f1 = xmlStrlen(from->stringval); + unsigned long f2 = xmlStrlen(str->stringval); + + if ((f1 > 0) && (f2 > 0)) { + unsigned long p; + + f1 = f1 / 10 + 1; + f2 = f2 / 10 + 1; + p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2; + if (xmlXPathCheckOpLimit(ctxt, p) < 0) + goto error; + } + } + + target = xmlBufCreateSize(64); + if (target == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); + + max = xmlUTF8Strlen(to->stringval); + for (cptr = str->stringval; (ch=*cptr); ) { + offset = xmlUTF8Strloc(from->stringval, cptr); + if (offset >= 0) { + if (offset < max) { + point = xmlUTF8Strpos(to->stringval, offset); + if (point) + xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); + } + } else + xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); + + /* Step to next character in input */ + cptr++; + if ( ch & 0x80 ) { + /* if not simple ascii, verify proper format */ + if ( (ch & 0xc0) != 0xc0 ) { + xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR); + break; + } + /* then skip over remaining bytes for this char */ + while ( (ch <<= 1) & 0x80 ) + if ( (*cptr++ & 0xc0) != 0x80 ) { + xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR); + break; + } + if (ch & 0x80) /* must have had error encountered */ + break; + } + } + + content = xmlBufDetach(target); + if (content == NULL) + xmlXPathPErrMemory(ctxt); + else + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content)); xmlBufFree(target); +error: xmlXPathReleaseObject(ctxt->context, str); xmlXPathReleaseObject(ctxt->context, from); xmlXPathReleaseObject(ctxt->context, to); @@ -9414,7 +8401,12 @@ xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(1); cur = valuePop(ctxt); if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); + if (cur->type != XPATH_BOOLEAN) { + int boolval = xmlXPathCastToBoolean(cur); + + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheNewBoolean(ctxt, boolval); + } valuePush(ctxt, cur); } @@ -9447,7 +8439,7 @@ xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); } /** @@ -9461,7 +8453,7 @@ xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); } /** @@ -9487,8 +8479,9 @@ xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr val = NULL; - const xmlChar *theLang = NULL; + xmlXPathObjectPtr val; + xmlNodePtr cur; + xmlChar *theLang; const xmlChar *lang; int ret = 0; int i; @@ -9498,20 +8491,28 @@ xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_TYPE(XPATH_STRING); val = valuePop(ctxt); lang = val->stringval; - theLang = xmlNodeGetLang(ctxt->context->node); + cur = ctxt->context->node; + while (cur != NULL) { + if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE, + &theLang) < 0) + xmlXPathPErrMemory(ctxt); + if (theLang != NULL) + break; + cur = cur->parent; + } if ((theLang != NULL) && (lang != NULL)) { for (i = 0;lang[i] != 0;i++) - if (toupper(lang[i]) != toupper(theLang[i])) - goto not_equal; - if ((theLang[i] == 0) || (theLang[i] == '-')) - ret = 1; + if (toupper(lang[i]) != toupper(theLang[i])) + goto not_equal; + if ((theLang[i] == 0) || (theLang[i] == '-')) + ret = 1; } not_equal: if (theLang != NULL) xmlFree((void *)theLang); xmlXPathReleaseObject(ctxt->context, val); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret)); } /** @@ -9530,12 +8531,14 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { if (ctxt->context->node == NULL) { - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0)); } else { xmlChar* content = xmlNodeGetContent(ctxt->context->node); + if (content == NULL) + xmlXPathPErrMemory(ctxt); res = xmlXPathStringEvalNumber(content); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res)); xmlFree(content); } return; @@ -9543,7 +8546,14 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(1); cur = valuePop(ctxt); - valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); + if (cur->type != XPATH_NUMBER) { + double floatval; + + floatval = xmlXPathCastToNumberInternal(ctxt, cur); + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheNewFloat(ctxt, floatval); + } + valuePush(ctxt, cur); } /** @@ -9571,10 +8581,11 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { for (i = 0; i < cur->nodesetval->nodeNr; i++) { - res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); + res += xmlXPathNodeToNumberInternal(ctxt, + cur->nodesetval->nodeTab[i]); } } - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res)); xmlXPathReleaseObject(ctxt->context, cur); } @@ -9742,7 +8753,7 @@ xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { } else { /* 1-byte code */ *len = 1; - return((int) *cur); + return(*cur); } encoding_error: /* @@ -9798,6 +8809,8 @@ xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { if (count == 0) return(NULL); ret = xmlStrndup(ctxt->cur, count); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = in; return(ret); } @@ -9879,6 +8892,8 @@ xmlXPathParseName(xmlXPathParserContextPtr ctxt) { XP_ERRORNULL(XPATH_EXPR_ERROR); } ret = xmlStrndup(ctxt->cur, count); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = in; return(ret); } @@ -9888,6 +8903,7 @@ xmlXPathParseName(xmlXPathParserContextPtr ctxt) { static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { + xmlChar *ret; xmlChar buf[XML_MAX_NAMELEN + 5]; int len = 0, l; int c; @@ -9924,9 +8940,10 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { if (len > XML_MAX_NAME_LENGTH) { XP_ERRORNULL(XPATH_EXPR_ERROR); } - buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - XP_ERRORNULL(XPATH_MEMORY_ERROR); + xmlXPathPErrMemory(ctxt); + return(NULL); } memcpy(buffer, buf, len); while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ @@ -9941,11 +8958,11 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { XP_ERRORNULL(XPATH_EXPR_ERROR); } max *= 2; - tmp = (xmlChar *) xmlRealloc(buffer, - max * sizeof(xmlChar)); + tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlFree(buffer); - XP_ERRORNULL(XPATH_MEMORY_ERROR); + xmlXPathPErrMemory(ctxt); + return(NULL); } buffer = tmp; } @@ -9959,7 +8976,10 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { } if (len == 0) return(NULL); - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + return(ret); } #define MAX_FRAC 20 @@ -9994,13 +9014,13 @@ xmlXPathStringEvalNumber(const xmlChar *str) { #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++; } + if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) { + return(xmlXPathNAN); + } #ifdef __GNUC__ /* @@ -10162,7 +9182,7 @@ xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) exponent = -exponent; ret *= pow(10.0, (double) exponent); } - num = xmlXPathCacheNewFloat(ctxt->context, ret); + num = xmlXPathCacheNewFloat(ctxt, ret); if (num == NULL) { ctxt->error = XPATH_MEMORY_ERROR; } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num, @@ -10186,32 +9206,33 @@ static xmlChar * xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { const xmlChar *q; xmlChar *ret = NULL; + int quote; if (CUR == '"') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '"')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } + quote = '"'; } else if (CUR == '\'') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } + quote = '\''; } else { XP_ERRORNULL(XPATH_START_LITERAL_ERROR); } + + NEXT; + q = CUR_PTR; + while (CUR != quote) { + int ch; + int len = 4; + + if (CUR == 0) + XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); + ch = xmlGetUTF8Char(CUR_PTR, &len); + if ((ch < 0) || (IS_CHAR(ch) == 0)) + XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR); + CUR_PTR += len; + } + ret = xmlStrndup(q, CUR_PTR - q); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + NEXT; return(ret); } @@ -10228,39 +9249,15 @@ xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { */ static void xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { - const xmlChar *q; xmlChar *ret = NULL; xmlXPathObjectPtr lit; - if (CUR == '"') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '"')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } - } else if (CUR == '\'') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } - } else { - XP_ERROR(XPATH_START_LITERAL_ERROR); - } - if (ret == NULL) return; - lit = xmlXPathCacheNewString(ctxt->context, ret); + ret = xmlXPathParseLiteral(ctxt); + if (ret == NULL) + return; + lit = xmlXPathCacheNewString(ctxt, ret); if (lit == NULL) { - ctxt->error = XPATH_MEMORY_ERROR; + ctxt->error = XPATH_MEMORY_ERROR; } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit, NULL) == -1) { xmlXPathReleaseObject(ctxt->context, lit); @@ -10363,14 +9360,6 @@ xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 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 != '(') { xmlFree(name); @@ -10503,7 +9492,7 @@ xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { static xmlChar * xmlXPathScanName(xmlXPathParserContextPtr ctxt) { - int len = 0, l; + int l; int c; const xmlChar *cur; xmlChar *ret; @@ -10523,11 +9512,12 @@ xmlXPathScanName(xmlXPathParserContextPtr ctxt) { (c == '_') || (c == ':') || (IS_COMBINING(c)) || (IS_EXTENDER(c)))) { - len += l; NEXTL(l); c = CUR_CHAR(l); } ret = xmlStrndup(cur, ctxt->cur - cur); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = cur; return(ret); } @@ -10588,10 +9578,6 @@ xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 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) { @@ -10601,29 +9587,17 @@ xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 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) == '(')) { /* Node Type or Function */ if (xmlXPathIsNodeType(name)) { -#ifdef DEBUG_STEP - xmlGenericError(xmlGenericErrorContext, - "PathExpr: Type search\n"); -#endif lc = 1; #ifdef LIBXML_XPTR_LOCS_ENABLED } else if (ctxt->xptr && @@ -10631,19 +9605,11 @@ xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { lc = 1; #endif } 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) == '>') || @@ -10657,10 +9623,6 @@ xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { len++; } if (NXT(len) == 0) { -#ifdef DEBUG_STEP - xmlGenericError(xmlGenericErrorContext, - "PathExpr: AbbrRelLocation\n"); -#endif /* element name */ lc = 1; } @@ -11064,7 +10026,6 @@ xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, int blanks; if ((test == NULL) || (type == NULL) || (prefix == NULL)) { - STRANGE; return(NULL); } *type = (xmlXPathTypeVal) 0; @@ -11120,9 +10081,6 @@ xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, name = NULL; if (CUR != ')') { name = xmlXPathParseLiteral(ctxt); - if (name == NULL) { - XP_ERRORNULL(XPATH_EXPR_ERROR); - } *test = NODE_TEST_PI; SKIP_BLANKS; } @@ -11371,20 +10329,6 @@ xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 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_LOCS_ENABLED eval_predicates: @@ -11408,16 +10352,6 @@ eval_predicates: xmlFree(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 } /** @@ -11519,93 +10453,6 @@ xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 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 */ - /** * xmlXPathNodeSetFilter: * @ctxt: the XPath Parser context @@ -11727,7 +10574,7 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt, tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab, nodeMax * sizeof(xmlNodePtr)); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "shrinking nodeset\n"); + xmlXPathPErrMemory(ctxt); } else { set->nodeTab = tmp; set->nodeMax = nodeMax; @@ -11845,7 +10692,7 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt, tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab, locMax * sizeof(xmlXPathObjectPtr)); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "shrinking locset\n"); + xmlXPathPErrMemory(ctxt); } else { locset->locTab = tmp; locset->locMax = locMax; @@ -11885,8 +10732,6 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, * Process inner predicates first. */ if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEvalPredicate: Expected a predicate\n"); XP_ERROR(XPATH_INVALID_OPERAND); } if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) @@ -11969,11 +10814,11 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (hasAxisRange != 0) { \ if (++pos == maxPos) { \ if (addNode(seq, cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ goto axis_range_end; } \ } else { \ if (addNode(seq, cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ if (breakOnFirstHit) goto first_hit; } #define XP_TEST_HIT_NS \ @@ -11981,12 +10826,12 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (++pos == maxPos) { \ hasNsNodes = 1; \ if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ goto axis_range_end; } \ } else { \ hasNsNodes = 1; \ if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ if (breakOnFirstHit) goto first_hit; } xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; @@ -11996,9 +10841,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 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; @@ -12123,19 +10965,13 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 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)); + valuePush(ctxt, obj); return(0); } /* @@ -12210,7 +11046,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (seq == NULL) { seq = xmlXPathNodeSetCreate(NULL); if (seq == NULL) { - /* TODO: Propagate memory error. */ + xmlXPathPErrMemory(ctxt); total = 0; goto error; } @@ -12261,14 +11097,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 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: if (type == NODE_TYPE_NODE) { @@ -12346,7 +11177,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, } break; case NODE_TEST_NS:{ - TODO; + /* TODO */ break; } case NODE_TEST_NAME: @@ -12428,9 +11259,11 @@ axis_range_end: /* ----------------------------------------------------- */ if (outSeq == NULL) { outSeq = seq; seq = NULL; - } else - /* TODO: Check memory error. */ + } else { outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } /* * Break if only a true/false result was requested. */ @@ -12446,16 +11279,13 @@ first_hit: /* ---------------------------------------------------------- */ if (outSeq == NULL) { outSeq = seq; seq = NULL; - } else - /* TODO: Check memory error. */ + } else { outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } break; -#ifdef DEBUG_STEP - if (seq != NULL) - nbMatches += seq->nodeNr; -#endif - apply_predicates: /* --------------------------------------------------- */ if (ctxt->error != XPATH_EXPRESSION_OK) goto error; @@ -12513,8 +11343,9 @@ apply_predicates: /* --------------------------------------------------- */ outSeq = seq; seq = NULL; } else { - /* TODO: Check memory error. */ outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); } if (toBool) @@ -12540,11 +11371,13 @@ error: * Ensure we return at least an empty set. */ if (outSeq == NULL) { - if ((seq != NULL) && (seq->nodeNr == 0)) + if ((seq != NULL) && (seq->nodeNr == 0)) { outSeq = seq; - else - /* TODO: Check memory error. */ + } else { outSeq = xmlXPathNodeSetCreate(NULL); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } } if ((seq != NULL) && (seq != outSeq)) { xmlXPathFreeNodeSet(seq); @@ -12553,7 +11386,7 @@ error: * Hand over the result. Better to push the set also in * case of errors. */ - valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq)); /* * Reset the context node. */ @@ -12567,12 +11400,6 @@ error: xpctxt->tmpNsList = NULL; } -#ifdef DEBUG_STEP - xmlGenericError(xmlGenericErrorContext, - "\nExamined %d nodes, found %d nodes at that step\n", - total, nbMatches); -#endif - return(total); } @@ -12657,9 +11484,13 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, break; } - /* TODO: Check memory error. */ - arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, - arg2->nodesetval); + if ((arg2->nodesetval != NULL) && + (arg2->nodesetval->nodeNr != 0)) { + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); + } valuePush(ctxt, arg1); xmlXPathReleaseObject(ctxt->context, arg2); /* optimizer */ @@ -12677,7 +11508,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); break; case XPATH_OP_COLLECT:{ @@ -12691,9 +11522,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_SORT: if (op->ch1 != -1) @@ -12797,9 +11626,13 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, break; } - /* TODO: Check memory error. */ - arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, - arg2->nodesetval); + if ((arg2->nodesetval != NULL) && + (arg2->nodesetval->nodeNr != 0)) { + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); + } valuePush(ctxt, arg1); xmlXPathReleaseObject(ctxt->context, arg2); /* optimizer */ @@ -12817,7 +11650,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); break; case XPATH_OP_COLLECT:{ @@ -12831,9 +11664,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_SORT: if (op->ch1 != -1) @@ -12863,6 +11694,7 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, { int total = 0; xmlXPathCompExprPtr comp; + xmlXPathObjectPtr obj; xmlNodeSetPtr set; CHECK_ERROR0; @@ -12930,13 +11762,20 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, } #endif /* LIBXML_XPTR_LOCS_ENABLED */ + /* + * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from + * the stack. We have to temporarily remove the nodeset object from the + * stack to avoid freeing it prematurely. + */ CHECK_TYPE0(XPATH_NODESET); - set = ctxt->value->nodesetval; + obj = valuePop(ctxt); + set = obj->nodesetval; if (set != NULL) { xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1); if (set->nodeNr > 0) *first = set->nodeTab[0]; } + valuePush(ctxt, obj); return (total); } @@ -13011,7 +11850,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) equal = xmlXPathEqualValues(ctxt); else equal = xmlXPathNotEqualValues(ctxt); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal)); break; case XPATH_OP_CMP: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); @@ -13019,7 +11858,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; ret = xmlXPathCompareValues(ctxt, op->value, op->value2); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret)); break; case XPATH_OP_PLUS: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); @@ -13077,13 +11916,13 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) break; } - if ((arg1->nodesetval == NULL) || - ((arg2->nodesetval != NULL) && + if (((arg2->nodesetval != NULL) && (arg2->nodesetval->nodeNr != 0))) { - /* TODO: Check memory error. */ arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); } valuePush(ctxt, arg1); @@ -13099,8 +11938,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node)); break; case XPATH_OP_COLLECT:{ if (op->ch1 == -1) @@ -13113,9 +11952,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_VARIABLE:{ xmlXPathObjectPtr val; @@ -13133,10 +11970,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) URI = xmlXPathNsLookup(ctxt->context, op->value5); if (URI == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", - (char *) op->value4, (char *)op->value5); - ctxt->error = XPATH_UNDEF_PREFIX_ERROR; + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); break; } val = xmlXPathVariableLookupNS(ctxt->context, @@ -13153,30 +11987,18 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) int i; int frame; - frame = xmlXPathSetFrame(ctxt); + frame = ctxt->valueNr; if (op->ch1 != -1) { total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); - if (ctxt->error != XPATH_EXPRESSION_OK) { - xmlXPathPopFrame(ctxt, frame); + if (ctxt->error != XPATH_EXPRESSION_OK) break; - } } - if (ctxt->valueNr < ctxt->valueFrame + op->value) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: parameter error\n"); - ctxt->error = XPATH_INVALID_OPERAND; - xmlXPathPopFrame(ctxt, frame); - break; - } + if (ctxt->valueNr < frame + op->value) + XP_ERROR0(XPATH_INVALID_OPERAND); for (i = 0; i < op->value; i++) { - if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: parameter error\n"); - ctxt->error = XPATH_INVALID_OPERAND; - xmlXPathPopFrame(ctxt, frame); - break; - } + if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) + XP_ERROR0(XPATH_INVALID_OPERAND); } if (op->cache != NULL) func = op->cache; @@ -13189,23 +12011,13 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) op->value4); else { URI = xmlXPathNsLookup(ctxt->context, op->value5); - if (URI == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", - (char *)op->value4, (char *)op->value5); - xmlXPathPopFrame(ctxt, frame); - ctxt->error = XPATH_UNDEF_PREFIX_ERROR; - break; - } + if (URI == NULL) + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); func = xmlXPathFunctionLookupNS(ctxt->context, op->value4, URI); } - if (func == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: function %s not found\n", - (char *)op->value4); + if (func == NULL) XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); - } op->cache = func; op->cacheURI = (void *) URI; } @@ -13217,9 +12029,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) ctxt->context->function = oldFunc; ctxt->context->functionURI = oldFuncURI; if ((ctxt->error == XPATH_EXPRESSION_OK) && - (ctxt->valueNr != ctxt->valueFrame + 1)) + (ctxt->valueNr != frame + 1)) XP_ERROR0(XPATH_STACK_ERROR); - xmlXPathPopFrame(ctxt, frame); break; } case XPATH_OP_ARG: @@ -13234,6 +12045,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) break; case XPATH_OP_PREDICATE: case XPATH_OP_FILTER:{ + xmlXPathObjectPtr obj; xmlNodeSetPtr set; /* @@ -13348,11 +12160,19 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) } #endif /* LIBXML_XPTR_LOCS_ENABLED */ + /* + * In case of errors, xmlXPathNodeSetFilter can pop additional + * nodes from the stack. We have to temporarily remove the + * nodeset object from the stack to avoid freeing it + * prematurely. + */ CHECK_TYPE0(XPATH_NODESET); - set = ctxt->value->nodesetval; + obj = valuePop(ctxt); + set = obj->nodesetval; if (set != NULL) xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, set->nodeNr, 1); + valuePush(ctxt, obj); break; } case XPATH_OP_SORT: @@ -13416,8 +12236,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) ctxt->context->node = oldlocset->locTab[i]->user; ctxt->context->contextSize = oldlocset->locNr; ctxt->context->proximityPosition = i + 1; - tmp = xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node); + tmp = xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node); valuePush(ctxt, tmp); if (op->ch2 != -1) @@ -13479,8 +12299,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) /* * OPTIMIZE TODO: Avoid recreation for every iteration. */ - tmp = xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node); + tmp = xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node); valuePush(ctxt, tmp); if (op->ch2 != -1) @@ -13527,9 +12347,7 @@ rangeto_error: } #endif /* LIBXML_XPTR_LOCS_ENABLED */ default: - xmlGenericError(xmlGenericErrorContext, - "XPath: unknown precompiled operation %d\n", op->op); - ctxt->error = XPATH_INVALID_OPERAND; + XP_ERROR0(XPATH_INVALID_OPERAND); break; } @@ -13631,12 +12449,12 @@ start: #ifdef XPATH_STREAMING /** * xmlXPathRunStreamEval: - * @ctxt: the XPath parser context with the compiled expression + * @pctxt: the XPath parser context with the compiled expression * * Evaluate the Precompiled Streamable XPath expression in the given context. */ static int -xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, +xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp, xmlXPathObjectPtr *resultSeq, int toBool) { int max_depth, min_depth; @@ -13645,8 +12463,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, int eval_all_nodes; xmlNodePtr cur = NULL, limit = NULL; xmlStreamCtxtPtr patstream = NULL; - - int nb_nodes = 0; + xmlXPathContextPtr ctxt = pctxt->context; if ((ctxt == NULL) || (comp == NULL)) return(-1); @@ -13668,7 +12485,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, if (! toBool) { if (resultSeq == NULL) return(-1); - *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); + *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL); if (*resultSeq == NULL) return(-1); } @@ -13677,20 +12494,24 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, * handle the special cases of "/" amd "." being matched */ if (min_depth == 0) { + int res; + if (from_root) { /* Select "/" */ if (toBool) return(1); - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, - (xmlNodePtr) ctxt->doc); + res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + (xmlNodePtr) ctxt->doc); } else { /* Select "self::node()" */ if (toBool) return(1); - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); + res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + ctxt->node); } + + if (res < 0) + xmlXPathPErrMemory(pctxt); } if (max_depth == 0) { return(0); @@ -13732,10 +12553,8 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, patstream = xmlPatternGetStreamCtxt(comp); if (patstream == NULL) { - /* - * QUESTION TODO: Is this an error? - */ - return(0); + xmlXPathPErrMemory(pctxt); + return(-1); } eval_all_nodes = xmlStreamWantsAnyNode(patstream); @@ -13746,8 +12565,8 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, } else if (ret == 1) { if (toBool) goto return_1; - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); + if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0) + xmlXPathPErrMemory(pctxt); } } depth = 0; @@ -13756,16 +12575,13 @@ next_node: do { if (ctxt->opLimit != 0) { if (ctxt->opCount >= ctxt->opLimit) { - xmlGenericError(xmlGenericErrorContext, - "XPath operation limit exceeded\n"); + xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED); xmlFreeStreamCtxt(patstream); return(-1); } ctxt->opCount++; } - nb_nodes++; - switch (cur->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: @@ -13781,15 +12597,13 @@ next_node: break; if (ret < 0) { - /* NOP. */ + xmlXPathPErrMemory(pctxt); } else if (ret == 1) { if (toBool) goto return_1; - if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) - < 0) { - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; - } + if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + cur) < 0) + xmlXPathPErrMemory(pctxt); } if ((cur->children == NULL) || (depth >= max_depth)) { ret = xmlStreamPop(patstream); @@ -13857,11 +12671,6 @@ scan_children: done: -#if 0 - printf("stream eval: checked %d nodes selected %d\n", - nb_nodes, retObj->nodesetval->nodeNr); -#endif - if (patstream) xmlFreeStreamCtxt(patstream); return(0); @@ -13894,13 +12703,12 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) ctxt->valueTab = (xmlXPathObjectPtr *) xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); if (ctxt->valueTab == NULL) { - xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); + xmlXPathPErrMemory(ctxt); return(-1); } ctxt->valueNr = 0; ctxt->valueMax = 10; ctxt->value = NULL; - ctxt->valueFrame = 0; } #ifdef XPATH_STREAMING if (ctxt->comp->stream) { @@ -13910,8 +12718,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) /* * Evaluation to boolean result. */ - res = xmlXPathRunStreamEval(ctxt->context, - ctxt->comp->stream, NULL, 1); + res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1); if (res != -1) return(res); } else { @@ -13920,8 +12727,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) /* * Evaluation to a sequence. */ - res = xmlXPathRunStreamEval(ctxt->context, - ctxt->comp->stream, &resObj, 0); + res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0); if ((res != -1) && (resObj != NULL)) { valuePush(ctxt, resObj); @@ -13938,8 +12744,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) #endif comp = ctxt->comp; if (comp->last < 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathRunEval: last is less than zero\n"); + xmlXPathErr(ctxt, XPATH_STACK_ERROR); return(-1); } oldDepth = ctxt->context->depth; @@ -13992,7 +12797,7 @@ xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { return((res->stringval != NULL) && (xmlStrlen(res->stringval) != 0)); default: - STRANGE + break; } return(0); } @@ -14043,7 +12848,7 @@ xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, } #endif default: - STRANGE + break; } return(0); } @@ -14074,6 +12879,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && (!xmlStrchr(str, '@'))) { const xmlChar *tmp; + int res; /* * We don't try to handle expressions using the verbose axis @@ -14094,7 +12900,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { if (ctxt->nsNr > 0) { namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); if (namespaces == NULL) { - xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); + xmlXPathErrMemory(ctxt); return(NULL); } for (i = 0, j = 0; (j < ctxt->nsNr); j++) { @@ -14107,14 +12913,20 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { } } - stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces); + res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces, + &stream); if (namespaces != NULL) { xmlFree((xmlChar **)namespaces); } + if (res < 0) { + xmlXPathErrMemory(ctxt); + return(NULL); + } if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { comp = xmlXPathNewCompExpr(); if (comp == NULL) { - xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); + xmlXPathErrMemory(ctxt); + xmlFreePattern(stream); return(NULL); } comp->stream = stream; @@ -14218,6 +13030,7 @@ xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt, xmlXPathCompExprPtr xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { xmlXPathParserContextPtr pctxt; + xmlXPathContextPtr tmpctxt = NULL; xmlXPathCompExprPtr comp; int oldDepth = 0; @@ -14229,18 +13042,32 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { xmlInitParser(); + /* + * We need an xmlXPathContext for the depth check. + */ + if (ctxt == NULL) { + tmpctxt = xmlXPathNewContext(NULL); + if (tmpctxt == NULL) + return(NULL); + ctxt = tmpctxt; + } + pctxt = xmlXPathNewParserContext(str, ctxt); - if (pctxt == NULL) + if (pctxt == NULL) { + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt); return NULL; - if (ctxt != NULL) - oldDepth = ctxt->depth; + } + + oldDepth = ctxt->depth; xmlXPathCompileExpr(pctxt, 1); - if (ctxt != NULL) - ctxt->depth = oldDepth; + ctxt->depth = oldDepth; if( pctxt->error != XPATH_EXPRESSION_OK ) { xmlXPathFreeParserContext(pctxt); + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt); return(NULL); } @@ -14265,13 +13092,11 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { pctxt->comp = NULL; } xmlXPathFreeParserContext(pctxt); + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt); if (comp != NULL) { comp->expr = xmlStrdup(str); -#ifdef DEBUG_EVAL_COUNTS - comp->string = xmlStrdup(str); - comp->nb = 0; -#endif } return(comp); } @@ -14310,47 +13135,34 @@ xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, int toBool) { xmlXPathParserContextPtr pctxt; - xmlXPathObjectPtr resObj; + xmlXPathObjectPtr resObj = NULL; #ifndef LIBXML_THREAD_ENABLED static int reentance = 0; #endif int res; - CHECK_CTXT_NEG(ctxt) - if (comp == NULL) return(-1); xmlInitParser(); + xmlResetError(&ctxt->lastError); + #ifndef LIBXML_THREAD_ENABLED reentance++; if (reentance > 1) 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); + if (pctxt == NULL) + return(-1); res = xmlXPathRunEval(pctxt, toBool); - if (pctxt->error != XPATH_EXPRESSION_OK) { - resObj = NULL; - } else { - resObj = valuePop(pctxt); - if (resObj == NULL) { - if (!toBool) - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: No result on the stack.\n"); - } else if (pctxt->valueNr > 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: %d object(s) left on the stack.\n", - pctxt->valueNr); - } + if (pctxt->error == XPATH_EXPRESSION_OK) { + if (pctxt->valueNr != ((toBool) ? 0 : 1)) + xmlXPathErr(pctxt, XPATH_STACK_ERROR); + else if (!toBool) + resObj = valuePop(pctxt); } if (resObjPtr) @@ -14418,10 +13230,18 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { #endif int oldDepth = 0; - if (ctxt == NULL) return; + if (ctxt == NULL) + return; + if (ctxt->context->lastError.code != 0) + return; #ifdef XPATH_STREAMING comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); + if ((comp == NULL) && + (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) { + xmlXPathPErrMemory(ctxt); + return; + } if (comp != NULL) { if (ctxt->comp != NULL) xmlXPathFreeCompExpr(ctxt->comp); @@ -14468,10 +13288,13 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { xmlXPathParserContextPtr ctxt; xmlXPathObjectPtr res; - CHECK_CTXT(ctx) + if (ctx == NULL) + return(NULL); xmlInitParser(); + xmlResetError(&ctx->lastError); + ctxt = xmlXPathNewParserContext(str, ctx); if (ctxt == NULL) return NULL; @@ -14479,16 +13302,11 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { if (ctxt->error != XPATH_EXPRESSION_OK) { res = NULL; + } else if (ctxt->valueNr != 1) { + xmlXPathErr(ctxt, XPATH_STACK_ERROR); + res = NULL; } else { res = valuePop(ctxt); - if (res == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: No result on the stack.\n"); - } else if (ctxt->valueNr > 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: %d object(s) left on the stack.\n", - ctxt->valueNr); - } } xmlXPathFreeParserContext(ctxt); @@ -14621,7 +13439,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { CAST_TO_STRING; str = valuePop(ctxt); - target = xmlBufCreate(); + target = xmlBufCreateSize(64); escape[0] = '%'; escape[3] = 0; @@ -14661,8 +13479,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { } } } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target))); xmlBufFree(target); xmlXPathReleaseObject(ctxt->context, str); } diff --git a/xpointer.c b/xpointer.c index ba1e31e0d0b..87ea85bbf70 100644 --- a/xpointer.c +++ b/xpointer.c @@ -38,29 +38,14 @@ #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__); +#include "private/error.h" +#include "private/xpath.h" /************************************************************************ * * @@ -68,63 +53,59 @@ * * ************************************************************************/ -/** - * xmlXPtrErrMemory: - * @extra: extra information - * - * Handle a redefinition of attribute error - */ -static void -xmlXPtrErrMemory(const char *extra) -{ - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); -} - /** * xmlXPtrErr: * @ctxt: an XPTR evaluation context * @extra: extra information * - * Handle a redefinition of attribute error + * Handle an XPointer error */ static void LIBXML_ATTR_FORMAT(3,0) -xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error, +xmlXPtrErr(xmlXPathParserContextPtr ctxt, int code, const char * msg, const xmlChar *extra) { - if (ctxt != NULL) - ctxt->error = error; - if ((ctxt == NULL) || (ctxt->context == NULL)) { - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPOINTER, error, - XML_ERR_ERROR, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, extra); - return; - } + xmlStructuredErrorFunc serror = NULL; + void *data = NULL; + xmlNodePtr node = NULL; + int res; - /* cleanup current last error */ - xmlResetError(&ctxt->context->lastError); + if (ctxt == NULL) + return; + /* Only report the first error */ + if (ctxt->error != 0) + return; - ctxt->context->lastError.domain = XML_FROM_XPOINTER; - ctxt->context->lastError.code = error; - ctxt->context->lastError.level = XML_ERR_ERROR; - ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); - ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; - ctxt->context->lastError.node = ctxt->context->debugNode; - if (ctxt->context->error != NULL) { - ctxt->context->error(ctxt->context->userData, - &ctxt->context->lastError); - } else { - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->context->debugNode, XML_FROM_XPOINTER, - error, XML_ERR_ERROR, NULL, 0, - (const char *) extra, (const char *) ctxt->base, NULL, - ctxt->cur - ctxt->base, 0, - msg, extra); + ctxt->error = code; + + if (ctxt->context != NULL) { + xmlErrorPtr err = &ctxt->context->lastError; + + /* cleanup current last error */ + xmlResetError(err); + + err->domain = XML_FROM_XPOINTER; + err->code = code; + err->level = XML_ERR_ERROR; + err->str1 = (char *) xmlStrdup(ctxt->base); + if (err->str1 == NULL) { + xmlXPathPErrMemory(ctxt); + return; + } + err->int1 = ctxt->cur - ctxt->base; + err->node = ctxt->context->debugNode; + + serror = ctxt->context->error; + data = ctxt->context->userData; + node = ctxt->context->debugNode; } + + res = __xmlRaiseError(serror, NULL, data, NULL, node, + XML_FROM_XPOINTER, code, XML_ERR_ERROR, NULL, 0, + (const char *) extra, (const char *) ctxt->base, + NULL, ctxt->cur - ctxt->base, 0, + msg, extra); + if (res < 0) + xmlXPathPErrMemory(ctxt); } /************************************************************************ @@ -214,6 +195,18 @@ xmlXPtrGetNthChild(xmlNodePtr cur, int no) { * * ************************************************************************/ +/** + * xmlXPtrErrMemory: + * @extra: extra information + * + * Handle a redefinition of attribute error + */ +static void +xmlXPtrErrMemory(const char *extra ATTRIBUTE_UNUSED) +{ + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_XPOINTER, NULL); +} + /** * xmlXPtrCmpPoints: * @node1: the first node @@ -266,7 +259,7 @@ xmlXPtrNewPoint(xmlNodePtr node, int indx) { xmlXPtrErrMemory("allocating point"); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_POINT; ret->user = (void *) node; ret->index = indx; @@ -586,7 +579,7 @@ xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { xmlXPtrErrMemory("allocating locationset"); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlLocationSet)); + memset(ret, 0 , sizeof(xmlLocationSet)); if (val != NULL) { ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr)); @@ -596,7 +589,7 @@ xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { return(NULL); } memset(ret->locTab, 0 , - XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr)); ret->locMax = XML_RANGESET_DEFAULT; ret->locTab[ret->locNr++] = val; } @@ -638,7 +631,7 @@ xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { return; } memset(cur->locTab, 0 , - XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr)); cur->locMax = XML_RANGESET_DEFAULT; } else if (cur->locNr == cur->locMax) { xmlXPathObjectPtr *temp; @@ -703,10 +696,6 @@ xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { 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--; @@ -771,7 +760,7 @@ xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) { xmlXPtrErrMemory("allocating locationset"); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_LOCATIONSET; if (end == NULL) ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start)); @@ -798,7 +787,7 @@ xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) { xmlXPtrErrMemory("allocating locationset"); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0, sizeof(xmlXPathObject)); ret->type = XPATH_LOCATIONSET; if (set != NULL) { int i; @@ -834,7 +823,7 @@ xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { xmlXPtrErrMemory("allocating locationset"); return(NULL); } - memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + memset(ret, 0, sizeof(xmlXPathObject)); ret->type = XPATH_LOCATIONSET; ret->user = (void *) val; return(ret); @@ -967,9 +956,9 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { len = xmlStrlen(ctxt->cur); len++; - buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar)); + buffer = (xmlChar *) xmlMallocAtomic(len); if (buffer == NULL) { - xmlXPtrErrMemory("allocating buffer"); + xmlXPathPErrMemory(ctxt); xmlFree(name); return; } @@ -1070,7 +1059,8 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { NEXT; SKIP_BLANKS; - xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur); + if (xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur) < 0) + xmlXPathPErrMemory(ctxt); ctxt->base = oldBase; ctxt->cur = oldCur; xmlFree(prefix); @@ -1240,13 +1230,12 @@ xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { ctxt->valueTab = (xmlXPathObjectPtr *) xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); if (ctxt->valueTab == NULL) { - xmlXPtrErrMemory("allocating evaluation context"); + xmlXPathPErrMemory(ctxt); return; } ctxt->valueNr = 0; ctxt->valueMax = 10; ctxt->value = NULL; - ctxt->valueFrame = 0; } SKIP_BLANKS; if (CUR == '/') { @@ -1362,10 +1351,16 @@ xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { if ((ctx == NULL) || (str == NULL)) return(NULL); + xmlResetError(&ctx->lastError); + ctxt = xmlXPathNewParserContext(str, ctx); - if (ctxt == NULL) + if (ctxt == NULL) { + xmlXPathErrMemory(ctx); return(NULL); + } xmlXPtrEvalXPointer(ctxt); + if (ctx->lastError.code != XML_ERR_OK) + goto error; if ((ctxt->value != NULL) && #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -1403,11 +1398,12 @@ xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { "xmlXPtrEval: object(s) left on the eval stack\n", NULL); } - if (ctxt->error != XPATH_EXPRESSION_OK) { + if (ctx->lastError.code != XML_ERR_OK) { xmlXPathFreeObject(res); res = NULL; } +error: xmlXPathFreeParserContext(ctxt); return(res); } @@ -1546,7 +1542,7 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { /* Do not copy DTD information */ break; case XML_ENTITY_DECL: - TODO /* handle crossing entities -> stack needed */ + /* TODO: handle crossing entities -> stack needed */ break; case XML_XINCLUDE_START: case XML_XINCLUDE_END: @@ -1554,7 +1550,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { break; case XML_ATTRIBUTE_NODE: /* Humm, should not happen ! */ - STRANGE break; default: tmp = xmlCopyNode(cur, 1); @@ -1562,7 +1557,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { } if (tmp != NULL) { if ((list == NULL) || ((last == NULL) && (parent == NULL))) { - STRANGE return(NULL); } if (last != NULL) @@ -1576,7 +1570,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { * Skip to next node in document order */ if ((list == NULL) || ((last == NULL) && (parent == NULL))) { - STRANGE return(NULL); } cur = xmlXPtrAdvanceNode(cur, NULL); @@ -2005,7 +1998,8 @@ xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { } } default: - TODO /* missed one case ??? */ + /* TODO: missed one case ??? */ + break; } return(NULL); } @@ -2152,7 +2146,8 @@ xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { } } default: - TODO /* missed one case ??? */ + /* TODO: missed one case ??? */ + break; } return(NULL); } @@ -2287,7 +2282,6 @@ found: (cur->type != XML_HTML_DOCUMENT_NODE) && (cur->type != XML_CDATA_SECTION_NODE)) { if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */ - TODO goto skip; } goto next; @@ -2361,7 +2355,6 @@ xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { } if (pos > len) { /* Strange, the indx in the text node is greater than it's len */ - STRANGE pos = len; } if (pos + bytes >= len) { @@ -2423,13 +2416,6 @@ xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, 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); @@ -2440,13 +2426,6 @@ xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, 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 { @@ -2506,13 +2485,6 @@ xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, 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; @@ -2529,13 +2501,6 @@ xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, * 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; @@ -2785,25 +2750,12 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { * 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; diff --git a/xzlib.c b/xzlib.c index b2350b90536..9a106b90e2c 100644 --- a/xzlib.c +++ b/xzlib.c @@ -14,9 +14,6 @@ #include #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif #ifdef HAVE_SYS_STAT_H #include #endif @@ -25,6 +22,8 @@ #endif #ifdef HAVE_UNISTD_H #include +#elif defined (_WIN32) +#include #endif #ifdef LIBXML_ZLIB_ENABLED #include @@ -33,7 +32,7 @@ #include #endif -#include "xzlib.h" +#include "private/xzlib.h" #include /* values for xz_state how */ @@ -134,6 +133,7 @@ static xzFile xz_open(const char *path, int fd, const char *mode ATTRIBUTE_UNUSED) { xz_statep state; + off_t offset; /* allocate xzFile structure to return */ state = xmlMalloc(sizeof(xz_state)); @@ -168,9 +168,11 @@ xz_open(const char *path, int fd, const char *mode ATTRIBUTE_UNUSED) } /* save the current position for rewinding (only if reading) */ - state->start = lseek(state->fd, 0, SEEK_CUR); - if (state->start == (uint64_t) - 1) + offset = lseek(state->fd, 0, SEEK_CUR); + if (offset == -1) state->start = 0; + else + state->start = offset; /* initialize stream */ xz_reset(state); @@ -193,6 +195,12 @@ xz_compressed(xzFile f) { case COPY: return(0); case GZIP: +#ifdef LIBXML_ZLIB_ENABLED + /* Don't use lzma for gzip */ + return(0); +#else + return(1); +#endif case LZMA: return(1); } @@ -205,23 +213,10 @@ __libxml2_xzopen(const char *path, const char *mode) return xz_open(path, -1, mode); } -int -__libxml2_xzcompressed(xzFile f) { - return xz_compressed(f); -} - xzFile -__libxml2_xzdopen(int fd, const char *mode) +__libxml2_xzdopen(const char *path, int fd, const char *mode) { - char *path; /* identifier for error messages */ - xzFile xz; - - if (fd == -1 || (path = xmlMalloc(7 + 3 * sizeof(int))) == NULL) - return NULL; - sprintf(path, "", fd); /* for debugging */ - xz = xz_open(path, fd, mode); - xmlFree(path); - return xz; + return xz_open(path, fd, mode); } static int @@ -317,8 +312,12 @@ is_format_lzma(xz_statep state) * If someone complains, this will be reconsidered. */ if (dict_size != UINT32_MAX) { - uint32_t d = dict_size - 1; + uint32_t d; + if (dict_size == 0) + return 0; + + d = dict_size - 1; d |= d >> 2; d |= d >> 3; d |= d >> 4; @@ -697,6 +696,13 @@ xz_skip(xz_statep state, uint64_t len) return 0; } +int +__libxml2_xzcompressed(xzFile f) { + xz_head(f); + + return xz_compressed(f); +} + int __libxml2_xzread(xzFile file, void *buf, unsigned len) { -- GitLab From 548453c6abe3bcf10217791f7825c9e8fb47aa34 Mon Sep 17 00:00:00 2001 From: Spiros Tsalikis Date: Wed, 2 Oct 2024 10:26:13 -0400 Subject: [PATCH 3/3] Add changelog --- Documentation/release/dev/update-libxml2.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Documentation/release/dev/update-libxml2.md diff --git a/Documentation/release/dev/update-libxml2.md b/Documentation/release/dev/update-libxml2.md new file mode 100644 index 00000000000..92bfbbaa4cd --- /dev/null +++ b/Documentation/release/dev/update-libxml2.md @@ -0,0 +1,3 @@ +## libxml2: Update to 2.13.4 + +Libxml2 has been updated to 2.13.4. This release includes a number of bug and security related fixes. -- GitLab