diff --git a/CMakeLists.txt b/CMakeLists.txt index 724f8474579282f23d0ddfa0bca0dad4433df473..cb4e830c7a845bdfd02ea38580cce677a2ef174d 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 <netdb.h> - 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 <sys/socket.h> - #include <sys/types.h> - 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 <stdarg.h> - 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 <stddef.h> - #include <sys/socket.h> - #include <sys/types.h> - 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 <stddef.h> - #include <sys/socket.h> - #include <sys/types.h> - 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 <stddef.h> - #include <sys/socket.h> - #include <sys/types.h> - 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 <stddef.h> + #include <sys/socket.h> + 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 <stddef.h> + #include <sys/socket.h> + 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 <stddef.h> + #include <sys/socket.h> + 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 - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> - $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}/libxml2> + LibXml2 + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}/libxml2> ) else () vtk_module_add_module(VTK::libxml2 @@ -464,219 +412,264 @@ target_include_directories(libxml2 "$<INSTALL_INTERFACE:${_vtk_build_HEADERS_DESTINATION}/vtklibxml2/include>") 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 $<TARGET_PDB_FILE:LibXml2> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug) + install(FILES $<TARGET_PDB_FILE:LibXml2> 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 - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/python> - ) - 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 $<TARGET_PDB_FILE:LibXml2Mod> 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 + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/python> + ) + 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 $<TARGET_PDB_FILE:LibXml2Mod> 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 d61318502caf9587516dd9a2cb637ad9c4877f69..f76a86df63f54f2ce47a86716170955e06ef20e4 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 ba886908e449b54bf2874e62caa070039137525d..221359295653778568f1d42a4de439db8b269755 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -14,30 +14,30 @@ #include <ctype.h> #include <stdlib.h> +#include <libxml/HTMLparser.h> #include <libxml/xmlmemory.h> #include <libxml/tree.h> #include <libxml/parser.h> #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> -#include <libxml/HTMLparser.h> #include <libxml/HTMLtree.h> #include <libxml/entities.h> #include <libxml/encoding.h> -#include <libxml/valid.h> #include <libxml/xmlIO.h> -#include <libxml/globals.h> #include <libxml/uri.h> -#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 ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' + * Parse an XML Processing Instruction. HTML5 doesn't allow processing + * instructions, so this will be removed at some point. */ static void htmlParsePI(htmlParserCtxtPtr ctxt) { @@ -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 ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' + * 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 "<?xm", 4) == 0)) + xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_UTF8); /* * Wipe out everything which is before the first '<' @@ -4955,7 +4780,6 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - /* * Parse possible comments and PIs before any content */ @@ -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 "<?xm", 4) == 0)) { + xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_UTF8); + } + /* * Very first chars read from the document flow. */ cur = in->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 '</'. + */ + ctxt->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 3dd78a91ebaab141c698fd211f10d1a3362f8c53..8fa022c11b86277b3d029253567d38a4241210c6 100644 --- a/HTMLtree.c +++ b/HTMLtree.c @@ -19,13 +19,14 @@ #include <libxml/HTMLparser.h> #include <libxml/HTMLtree.h> #include <libxml/entities.h> -#include <libxml/valid.h> #include <libxml/xmlerror.h> #include <libxml/parserInternals.h> -#include <libxml/globals.h> #include <libxml/uri.h> -#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 ad423e686f94dabf6516b21e7c48d27d56a846cc..58c9433f9aac54542872ad7cde8540faad70ad73 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 -<https://gitlab.gnome.org/GNOME/libxml2/-/wikis>. +Official releases can be downloaded from +<https://download.gnome.org/sources/libxml2/> + +The git repository is hosted on GNOME's GitLab server: +<https://gitlab.gnome.org/GNOME/libxml2> Bugs should be reported at -<https://gitlab.gnome.org/GNOME/libxml2/-/issues>. +<https://gitlab.gnome.org/GNOME/libxml2/-/issues> -A mailing list xml@gnome.org is available. You can subscribe at -<https://mail.gnome.org/mailman/listinfo/xml>. The list archive is at -<https://mail.gnome.org/archives/xml/>. +Documentation is available at +<https://gitlab.gnome.org/GNOME/libxml2/-/wikis> ## 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 <https://gitlab.gnome.org/GNOME/libxml2>. 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 d8e972b84c2d75a7a56b0d38ddb4f32dfab62c6e..7f2f297406c7468b169c8ac8efb883b6ef31dd36 100644 --- a/SAX.c +++ b/SAX.c @@ -25,7 +25,6 @@ #include <libxml/uri.h> #include <libxml/valid.h> #include <libxml/HTMLtree.h> -#include <libxml/globals.h> #include <libxml/SAX2.h> #ifdef LIBXML_LEGACY_ENABLED diff --git a/SAX2.c b/SAX2.c index ec89046b1d6507dccae3b09adfe23143431aca50..32db6b4c1a44d2124f1a9c36819d659b0eb194a4 100644 --- a/SAX2.c +++ b/SAX2.c @@ -13,6 +13,7 @@ #include <string.h> #include <limits.h> #include <stddef.h> +#include <libxml/SAX2.h> #include <libxml/xmlmemory.h> #include <libxml/tree.h> #include <libxml/parser.h> @@ -22,66 +23,24 @@ #include <libxml/xmlerror.h> #include <libxml/debugXML.h> #include <libxml/xmlIO.h> -#include <libxml/SAX.h> #include <libxml/uri.h> #include <libxml/valid.h> #include <libxml/HTMLtree.h> -#include <libxml/globals.h> -/* Define SIZE_T_MAX unless defined through <limits.h>. */ -#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 <richard@cogsci.ed.ac.uk> - *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with - *> values "system" and "public". I have made the default be "system" to - *> match yours. - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +#define XML_MAX_URI_LENGTH 2000 /* * xmlSAX2ErrMemory: * @ctxt: an XML validation parser context * @msg: a string to accompany the error message */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { - xmlStructuredErrorFunc schannel = NULL; - const char *str1 = "out of memory\n"; - - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - __xmlRaiseError(schannel, - ctxt->vctxt.error, ctxt->vctxt.userData, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } else { - __xmlRaiseError(schannel, - NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - } +static void +xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt) { + xmlCtxtErrMemory(ctxt); } /** @@ -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, /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */ 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 6749d975717b0b341526ee8590ab22f5478023bd..f9f59b26b5127681783d84016f1f9b504288cfc2 100644 --- a/buf.c +++ b/buf.c @@ -20,11 +20,11 @@ #include <ctype.h> #include <stdlib.h> -#include <libxml/tree.h> -#include <libxml/globals.h> #include <libxml/tree.h> #include <libxml/parserInternals.h> /* 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 b7bcf61fe2e39264ddaebe813a81cd91d7de4040..0000000000000000000000000000000000000000 --- 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 <libxml/tree.h> - -#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 d55729ccc59d5e4c26c81a700a575641d9e4e555..964ac998973b213c865436c9da49375a3d2a6e8f 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 <stdlib.h> #include <string.h> @@ -21,11 +20,11 @@ #include <libxml/parser.h> #include <libxml/uri.h> #include <libxml/xmlerror.h> -#include <libxml/globals.h> #include <libxml/xpathInternals.h> #include <libxml/c14n.h> -#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, "</"); @@ -1530,7 +1531,7 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) int visible; if ((ctx == NULL) || (cur == NULL)) { - xmlC14NErrParam("processing node"); + xmlC14NErrParam(ctx); return (-1); } @@ -1559,7 +1560,7 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) (const char *) buffer); xmlFree(buffer); } else { - xmlC14NErrInternal("normalizing text node"); + xmlC14NErrMemory(ctx); return (-1); } } @@ -1598,7 +1599,7 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) (const char *) buffer); xmlFree(buffer); } else { - xmlC14NErrInternal("normalizing pi node"); + xmlC14NErrMemory(ctx); return (-1); } } @@ -1643,7 +1644,7 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) (const char *) buffer); xmlFree(buffer); } else { - xmlC14NErrInternal("normalizing comment node"); + xmlC14NErrMemory(ctx); return (-1); } } @@ -1668,16 +1669,16 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) break; case XML_ATTRIBUTE_NODE: - xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node"); + xmlC14NErrInvalidNode(ctx, "XML_ATTRIBUTE_NODE", "processing node"); return (-1); case XML_NAMESPACE_DECL: - xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node"); + xmlC14NErrInvalidNode(ctx, "XML_NAMESPACE_DECL", "processing node"); return (-1); case XML_ENTITY_REF_NODE: - xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node"); + xmlC14NErrInvalidNode(ctx, "XML_ENTITY_REF_NODE", "processing node"); return (-1); case XML_ENTITY_NODE: - xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node"); + xmlC14NErrInvalidNode(ctx, "XML_ENTITY_NODE", "processing node"); return (-1); case XML_DOCUMENT_TYPE_NODE: @@ -1695,7 +1696,7 @@ xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) */ break; default: - xmlC14NErrUnknownNode(cur->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 b7837e3da755208a449284c4ce9c25a4ee707de0..27af95f47ab6cff24cc298ef7cf5c64f62df5367 100644 --- a/catalog.c +++ b/catalog.c @@ -16,16 +16,16 @@ #include "libxml.h" #ifdef LIBXML_CATALOG_ENABLED +#include <stdio.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> +#elif defined (_WIN32) +#include <io.h> #endif #ifdef HAVE_FCNTL_H #include <fcntl.h> @@ -37,9 +37,9 @@ #include <libxml/catalog.h> #include <libxml/xmlerror.h> #include <libxml/threads.h> -#include <libxml/globals.h> -#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 <richard@cogsci.ed.ac.uk> - *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with - *> values "system" and "public". I have made the default be "system" to - *> match yours. - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - #define XML_URN_PUBID "urn:publicid:" #define XML_CATAL_BREAK ((xmlChar *) -1) #ifndef XML_XML_DEFAULT_CATALOG @@ -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 f4fa44acbb805aa543b4384895a51ad79632a59e..fb2c715a875cba99920510d87f2d89d5aebcb7f1 100644 --- a/chvalid.c +++ b/chvalid.c @@ -14,6 +14,8 @@ #include "libxml.h" #include <libxml/chvalid.h> +#include <stddef.h> + /* * 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 1f8be710f535c29bcb4b4bec9748d10592ecb6ba..2f4aeba3b49d0c1326011d9fa0795e50b8eee7db 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 <arpa/inet.h> header file. */ #cmakedefine HAVE_ARPA_INET_H 1 -/* Define to 1 if you have the <arpa/nameser.h> 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 <dlfcn.h> 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 <inttypes.h> 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 <poll.h> header file. */ #cmakedefine HAVE_POLL_H 1 -/* Define if <pthread.h> is there */ +/* Define to 1 if you have the <pthread.h> 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 <resolv.h> 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 <sys/mman.h> header file. */ #cmakedefine HAVE_SYS_MMAN_H 1 +/* Define to 1 if you have the <sys/random.h> header file. */ +#cmakedefine HAVE_SYS_RANDOM_H 1 + /* Define to 1 if you have the <sys/select.h> header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 @@ -108,68 +87,20 @@ /* Define to 1 if you have the <sys/time.h> header file. */ #cmakedefine HAVE_SYS_TIME_H 1 -/* Define to 1 if you have the <sys/types.h> header file. */ -#cmakedefine HAVE_SYS_TYPES_H 1 - /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H 1 -/* Whether va_copy() is available */ -#cmakedefine HAVE_VA_COPY 1 - /* Define to 1 if you have the <zlib.h> 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 <sys/synch.h>, - <pthread.h>, or <semaphore.h> 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 4d8e0cb49b1adefda178e20b2daa541a34760251..36e74e4e967253c378cb0770181007a8914536bf 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 <sys/types.h> -# endif -]) -AC_CHECK_HEADERS([netinet/in.h], [], [], -[#if HAVE_SYS_TYPES_H -# include <sys/types.h> -# endif -]) -AC_CHECK_HEADERS([arpa/inet.h], [], [], -[#if HAVE_SYS_TYPES_H -# include <sys/types.h> -# endif -#if HAVE_ARPA_INET_H -# include <arpa/inet.h> -# 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 <sys/types.h> -# endif -]) -AC_CHECK_HEADERS([resolv.h], [], [], -[#if HAVE_SYS_TYPES_H -# include <sys/types.h> -# endif -#if HAVE_NETINET_IN_H -# include <netinet/in.h> -# endif -#if HAVE_ARPA_NAMESER_H -# include <arpa/nameser.h> -# 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 <stdarg.h> -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 <stdarg.h> - 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 <stdarg.h> -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 <sys/random.h>]) -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 <stddef.h> -#include <sys/types.h> -#include <sys/socket.h>],[ -(void)getsockopt (1, 1, 1, NULL, (socklen_t *)NULL)],[ - AC_MSG_RESULT(socklen_t *) - XML_SOCKLEN_T=socklen_t],[ - AC_TRY_COMPILE2([ -#include <stddef.h> -#include <sys/types.h> -#include <sys/socket.h>],[ -(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 <stddef.h> -#include <sys/types.h> -#include <sys/socket.h>],[ -(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 <netdb.h>]], - [[(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 <stddef.h> + #ifdef _WIN32 + #include <ws2tcpip.h> + #else + #include <sys/socket.h> + #endif],[ + (void)getsockopt (1, 1, 1, NULL, (socklen_t *)NULL)],[ + AC_MSG_RESULT(socklen_t *) + XML_SOCKLEN_T=socklen_t],[ + AC_TRY_COMPILE2([ + #include <stddef.h> + #include <sys/socket.h>],[ + (void)getsockopt (1, 1, 1, NULL, (size_t *)NULL)],[ + AC_MSG_RESULT(size_t *) + XML_SOCKLEN_T=size_t],[ + AC_TRY_COMPILE2([ + #include <stddef.h> + #include <sys/socket.h>],[ + (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 <winsock2.h> + #else + #include <sys/socket.h> + #ifdef HAVE_NETDB_H + #include <netdb.h> + #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 <sys/types.h> -#include <sys/socket.h>]], - [[(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 <sys/types.h> -# include <sys/socket.h> - ]], [[ - 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 <sys/types.h> -# include <sys/socket.h> - ]], [[ - 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 <sys/types.h> -# include <sys/socket.h> - ]], [[ - 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 <pthread.h> 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 <stdlib.h> -#include <iconv.h>]],[[ -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 <stdlib.h> -#include <iconv.h>]],[[ -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 <unicode/ucnv.h>]], [[ - 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 <unicode/ucnv.h>]], [[ - 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 <pthread.h> 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.h>], [iconv_open(0,0);]) + ], [ + WITH_ICONV=1 + AC_MSG_RESULT([none required]) + ], [ + LIBS="$LIBS -liconv" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([#include <iconv.h>], [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 f451c9d5c41ac778fdce8cd8b81381f90f8dfdb9..ed56b0f882ae22a76b5e57031b9096d8679576d9 100644 --- a/debugXML.c +++ b/debugXML.c @@ -18,18 +18,18 @@ #include <libxml/tree.h> #include <libxml/parser.h> #include <libxml/parserInternals.h> -#include <libxml/valid.h> #include <libxml/debugXML.h> #include <libxml/HTMLtree.h> #include <libxml/HTMLparser.h> #include <libxml/xmlerror.h> -#include <libxml/globals.h> #include <libxml/xpathInternals.h> #include <libxml/uri.h> #ifdef LIBXML_SCHEMAS_ENABLED #include <libxml/relaxng.h> #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 c29d2af77a771d22758904f5b9247defc7fc6c18..49e1c6bf760d9136ba0275728c5ee80142c33a2c 100644 --- a/dict.c +++ b/dict.c @@ -19,81 +19,28 @@ #define IN_LIBXML #include "libxml.h" +#include <errno.h> #include <limits.h> #include <stdlib.h> -#include <time.h> +#include <string.h> -/* - * 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 <string.h> -#ifdef HAVE_STDINT_H -#include <stdint.h> -#else -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#elif defined(_WIN32) -typedef unsigned __int32 uint32_t; -#endif -#endif -#include <libxml/tree.h> +#include <libxml/parser.h> #include <libxml/dict.h> #include <libxml/xmlmemory.h> -#include <libxml/xmlerror.h> -#include <libxml/globals.h> - -/* #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 <libxml/xmlstring.h> -/* - * 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 <windows.h> + #include <bcrypt.h> +#elif defined(HAVE_GETENTROPY) + #ifdef HAVE_UNISTD_H + #include <unistd.h> + #endif + #ifdef HAVE_SYS_RANDOM_H + #include <sys/random.h> + #endif +#else + #include <time.h> +#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 a69a5d03c8599b35a5e5c79473c9fd8afec0fa20..0000000000000000000000000000000000000000 --- 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 <libxml/tree.h> - -#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 5465359f244a67ab0ec72e0be45c5193ceb6ff4d..14ffafddbc02b0010fd0f9628a7c26710d219341 100644 --- a/encoding.c +++ b/encoding.c @@ -34,14 +34,15 @@ #include <libxml/encoding.h> #include <libxml/xmlmemory.h> +#include <libxml/parser.h> #ifdef LIBXML_HTML_ENABLED #include <libxml/HTMLparser.h> #endif -#include <libxml/globals.h> #include <libxml/xmlerror.h> -#include "buf.h" -#include "enc.h" +#include "private/buf.h" +#include "private/enc.h" +#include "private/error.h" #ifdef LIBXML_ICU_ENABLED #include <unicode/ucnv.h> @@ -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 '<?xml version="1.0" encoding="UCS4"?>' | 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 '<?xml version="1.0" encoding="UCS4"?>' | 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 84435515f733d346f0abfcf80fb4f725eafb0857..f7792a8138ec1956df5e6ff3240ef4ddb1c79fc3 100644 --- a/entities.c +++ b/entities.c @@ -23,10 +23,11 @@ #include <libxml/parser.h> #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> -#include <libxml/globals.h> #include <libxml/dict.h> +#include <libxml/xmlsave.h> -#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, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - xmlBufferWriteChar(buf, " "); - if (ent->orig != NULL) - xmlBufferWriteQuotedString(buf, ent->orig); - else - xmlDumpEntityContent(buf, ent->content); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_GENERAL_PARSED_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - if (ent->content != NULL) { /* Should be true ! */ - xmlBufferWriteChar(buf, " NDATA "); - if (ent->orig != NULL) - xmlBufferWriteCHAR(buf, ent->orig); - else - xmlBufferWriteCHAR(buf, ent->content); - } - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_INTERNAL_PARAMETER_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY % "); - xmlBufferWriteCHAR(buf, ent->name); - xmlBufferWriteChar(buf, " "); - if (ent->orig == NULL) - xmlDumpEntityContent(buf, ent->content); - else - xmlBufferWriteQuotedString(buf, ent->orig); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY % "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - xmlBufferWriteChar(buf, ">\n"); - break; - default: - xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY, - "xmlDumpEntitiesDecl: internal: unknown type entity type"); - } + xmlSaveCtxtPtr save; + + if ((buf == NULL) || (ent == NULL)) + return; + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) ent); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -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 5f42eadcc6d1e279b0b4c86a5e36ab03f9099b43..b678a0ee0048668f179a5713a165ee2a2319f256 100644 --- a/error.c +++ b/error.c @@ -11,46 +11,169 @@ #include <string.h> #include <stdarg.h> +#include <stdlib.h> #include <libxml/parser.h> #include <libxml/xmlerror.h> #include <libxml/xmlmemory.h> -#include <libxml/globals.h> - -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 '<?xml' required"; + break; + case XML_ERR_XMLDECL_NOT_FINISHED: + errmsg = "parsing XML declaration: '?>' expected"; + break; + case XML_ERR_EXT_ENTITY_STANDALONE: + errmsg = "external parsed entities cannot be standalone"; + break; + case XML_ERR_ENTITYREF_SEMICOL_MISSING: + errmsg = "EntityRef: expecting ';'"; + break; + case XML_ERR_DOCTYPE_NOT_FINISHED: + errmsg = "DOCTYPE improperly terminated"; + break; + case XML_ERR_LTSLASH_REQUIRED: + errmsg = "EndTag: '</' not found"; + break; + case XML_ERR_EQUAL_REQUIRED: + errmsg = "expected '='"; + break; + case XML_ERR_STRING_NOT_CLOSED: + errmsg = "String not closed expecting \" or '"; + break; + case XML_ERR_STRING_NOT_STARTED: + errmsg = "String not started expecting ' or \""; + break; + case XML_ERR_ENCODING_NAME: + errmsg = "Invalid XML encoding name"; + break; + case XML_ERR_STANDALONE_VALUE: + errmsg = "standalone accepts only 'yes' or 'no'"; + break; + case XML_ERR_DOCUMENT_EMPTY: + errmsg = "Document is empty"; + break; + case XML_ERR_DOCUMENT_END: + errmsg = "Extra content at the end of the document"; + break; + case XML_ERR_NOT_WELL_BALANCED: + errmsg = "chunk is not well balanced"; + break; + case XML_ERR_EXTRA_CONTENT: + errmsg = "extra content at the end of well balanced chunk"; + break; + case XML_ERR_VERSION_MISSING: + errmsg = "Malformed declaration expecting version"; + break; + case XML_ERR_NAME_TOO_LONG: + errmsg = "Name too long"; + break; + case XML_ERR_INVALID_ENCODING: + errmsg = "Invalid bytes in character encoding"; + break; + case XML_ERR_RESOURCE_LIMIT: + errmsg = "Resource limit exceeded"; + break; + case XML_ERR_ARGUMENT: + errmsg = "Invalid argument"; + break; + case XML_ERR_SYSTEM: + errmsg = "Out of system resources"; + break; + case XML_ERR_REDECL_PREDEF_ENTITY: + errmsg = "Invalid redeclaration of predefined entity"; + break; + case XML_ERR_UNSUPPORTED_ENCODING: + errmsg = "Unsupported encoding"; + break; + case XML_ERR_INVALID_CHAR: + errmsg = "Invalid character"; + break; + + case XML_IO_UNKNOWN: + errmsg = "Unknown IO error"; break; + case XML_IO_EACCES: + errmsg = "Permission denied"; break; + case XML_IO_EAGAIN: + errmsg = "Resource temporarily unavailable"; break; + case XML_IO_EBADF: + errmsg = "Bad file descriptor"; break; + case XML_IO_EBADMSG: + errmsg = "Bad message"; break; + case XML_IO_EBUSY: + errmsg = "Resource busy"; break; + case XML_IO_ECANCELED: + errmsg = "Operation canceled"; break; + case XML_IO_ECHILD: + errmsg = "No child processes"; break; + case XML_IO_EDEADLK: + errmsg = "Resource deadlock avoided"; break; + case XML_IO_EDOM: + errmsg = "Domain error"; break; + case XML_IO_EEXIST: + errmsg = "File exists"; break; + case XML_IO_EFAULT: + errmsg = "Bad address"; break; + case XML_IO_EFBIG: + errmsg = "File too large"; break; + case XML_IO_EINPROGRESS: + errmsg = "Operation in progress"; break; + case XML_IO_EINTR: + errmsg = "Interrupted function call"; break; + case XML_IO_EINVAL: + errmsg = "Invalid argument"; break; + case XML_IO_EIO: + errmsg = "Input/output error"; break; + case XML_IO_EISDIR: + errmsg = "Is a directory"; break; + case XML_IO_EMFILE: + errmsg = "Too many open files"; break; + case XML_IO_EMLINK: + errmsg = "Too many links"; break; + case XML_IO_EMSGSIZE: + errmsg = "Inappropriate message buffer length"; break; + case XML_IO_ENAMETOOLONG: + errmsg = "Filename too long"; break; + case XML_IO_ENFILE: + errmsg = "Too many open files in system"; break; + case XML_IO_ENODEV: + errmsg = "No such device"; break; + case XML_IO_ENOENT: + errmsg = "No such file or directory"; break; + case XML_IO_ENOEXEC: + errmsg = "Exec format error"; break; + case XML_IO_ENOLCK: + errmsg = "No locks available"; break; + case XML_IO_ENOMEM: + errmsg = "Not enough space"; break; + case XML_IO_ENOSPC: + errmsg = "No space left on device"; break; + case XML_IO_ENOSYS: + errmsg = "Function not implemented"; break; + case XML_IO_ENOTDIR: + errmsg = "Not a directory"; break; + case XML_IO_ENOTEMPTY: + errmsg = "Directory not empty"; break; + case XML_IO_ENOTSUP: + errmsg = "Not supported"; break; + case XML_IO_ENOTTY: + errmsg = "Inappropriate I/O control operation"; break; + case XML_IO_ENXIO: + errmsg = "No such device or address"; break; + case XML_IO_EPERM: + errmsg = "Operation not permitted"; break; + case XML_IO_EPIPE: + errmsg = "Broken pipe"; break; + case XML_IO_ERANGE: + errmsg = "Result too large"; break; + case XML_IO_EROFS: + errmsg = "Read-only file system"; break; + case XML_IO_ESPIPE: + errmsg = "Invalid seek"; break; + case XML_IO_ESRCH: + errmsg = "No such process"; break; + case XML_IO_ETIMEDOUT: + errmsg = "Operation timed out"; break; + case XML_IO_EXDEV: + errmsg = "Improper link"; break; + case XML_IO_NETWORK_ATTEMPT: + errmsg = "Attempt to load network entity"; break; + case XML_IO_ENCODER: + errmsg = "encoder error"; break; + case XML_IO_FLUSH: + errmsg = "flush error"; break; + case XML_IO_WRITE: + errmsg = "write error"; break; + case XML_IO_NO_INPUT: + errmsg = "no input"; break; + case XML_IO_BUFFER_FULL: + errmsg = "buffer full"; break; + case XML_IO_LOAD_ERROR: + errmsg = "loading error"; break; + case XML_IO_ENOTSOCK: + errmsg = "not a socket"; break; + case XML_IO_EISCONN: + errmsg = "already connected"; break; + case XML_IO_ECONNREFUSED: + errmsg = "connection refused"; break; + case XML_IO_ENETUNREACH: + errmsg = "unreachable network"; break; + case XML_IO_EADDRINUSE: + errmsg = "address in use"; break; + case XML_IO_EALREADY: + errmsg = "already in use"; break; + case XML_IO_EAFNOSUPPORT: + errmsg = "unknown address family"; break; + case XML_IO_UNSUPPORTED_PROTOCOL: + errmsg = "unsupported protocol"; break; + + default: + errmsg = "Unregistered error message"; + } + + return(errmsg); +} diff --git a/globals.c b/globals.c index a15ac3058ba7f3202fed3989cb723a48d10aac16..ff8fb4f3b0a3c60f8d8b7535d03f7d2424b6b77b 100644 --- a/globals.c +++ b/globals.c @@ -2,9 +2,6 @@ * globals.c: definition and handling of the set of global variables * of the library * - * The bottom of this file is automatically generated by build_glob.py - * based on the description file global.data - * * See Copyright for the status of this software. * * Gary Pennington <Gary.Pennington@uk.sun.com> @@ -14,42 +11,155 @@ #define IN_LIBXML #include "libxml.h" +#include <stdio.h> #include <stdlib.h> #include <string.h> +#define XML_GLOBALS_NO_REDEFINITION #include <libxml/globals.h> +#include <libxml/xmlerror.h> #include <libxml/xmlmemory.h> +#include <libxml/xmlIO.h> +#include <libxml/parser.h> #include <libxml/threads.h> +#include <libxml/tree.h> +#include <libxml/SAX.h> +#include <libxml/SAX2.h> -/* #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 <libxml/threads.h> -#include <libxml/globals.h> -#include <libxml/SAX.h> - -#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 894174fb99ad9be38519ecf4045f75a86624ddc6..6af8527eafbdb11fdd7da41fcd6ff955d9f72e73 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 <string.h> -#include <stdlib.h> -#include <time.h> - -/* - * 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 <limits.h> #include <libxml/parser.h> #include <libxml/hash.h> +#include <libxml/dict.h> #include <libxml/xmlmemory.h> -#include <libxml/xmlerror.h> -#include <libxml/globals.h> +#include <libxml/xmlstring.h> + +#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 1d4fec2f734375efe95363e268ae8618d660e2de..7be3d2b8a434ec7032faef1502a028865239bf23 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 c0e110330c5b03e38fcdd6bae5f131ac8a6b7d81..8e1ba90e9157b3bb7ad47b13f9ceae99cc748a13 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 fa50568f2539fc954c2af0b788d13943509473aa..eea1057bfcc533cd2309a4de73767f004c97380f 100644 --- a/include/libxml/SAX.h +++ b/include/libxml/SAX.h @@ -12,8 +12,6 @@ #ifndef __XML_SAX_H__ #define __XML_SAX_H__ -#include <stdio.h> -#include <stdlib.h> #include <libxml/xmlversion.h> #include <libxml/parser.h> @@ -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 8e9b0b95fe5610de138f849ecd4d4a75d12e3c88..4c4ecce8e598b2bb2011f9daf6367bcc8f028b88 100644 --- a/include/libxml/SAX2.h +++ b/include/libxml/SAX2.h @@ -12,63 +12,61 @@ #ifndef __XML_SAX2_H__ #define __XML_SAX2_H__ -#include <stdio.h> -#include <stdlib.h> #include <libxml/xmlversion.h> #include <libxml/parser.h> #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 af93de63a4c3a8ae20709a343c909d14d7b95056..8ccd1cef632e920751aefa6a8b112e2be660bc2d 100644 --- a/include/libxml/c14n.h +++ b/include/libxml/c14n.h @@ -20,7 +20,6 @@ #include <libxml/xmlversion.h> #ifdef LIBXML_C14N_ENABLED -#ifdef LIBXML_OUTPUT_ENABLED #include <libxml/tree.h> #include <libxml/xpath.h> @@ -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 26b178dbbc9caecc2bd6ef4f50f661d0772e0735..02fa7ab2a03a95563cf4ccdf7b644c95af1b15c2 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 fb43016982d3ed5d15afa461b744b90f0f8af69e..8225c95ee865f9639f46bd22db54932f257df52c 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 5b3be13d8572021404e69a261a4f6ece2fd22e62..1332dd73d9c774625c00560e9962cffc995f6059 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 91f74d1b8ffe05539a56334ceaf50f9ffd4e4984..22aa3d9db8b56b252b28c3ef17b814f6c6df44c0 100644 --- a/include/libxml/dict.h +++ b/include/libxml/dict.h @@ -13,6 +13,7 @@ #include <stddef.h> #include <libxml/xmlversion.h> +#include <libxml/xmlstring.h> #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 381e1886bf8f744012f18ec3e078ad20f0f2d692..599a03e12cd5c47d181500371ebe1e6579d4e02d 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 <libxml/tree.h> -#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 2b60d9e62284e70a79fc729005b1be365af3159a..a0cfca8133f660b2b93d069003c0f69ca36c34fc 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 <libxml/xmlversion.h> +#define XML_TREE_INTERNALS #include <libxml/tree.h> +#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 d57ccb05415ef8f7eda389765d60c7fe76e2336c..92f41312f549efa176e48dd719c1652cfc21ef34 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 <Gary.Pennington@uk.sun.com>, Daniel Veillard */ #ifndef __XML_GLOBALS_H #define __XML_GLOBALS_H #include <libxml/xmlversion.h> -#include <libxml/parser.h> -#include <libxml/xmlerror.h> -#include <libxml/SAX2.h> -#include <libxml/xmlmemory.h> - -#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 <libxml/HTMLparser.h> +#include <libxml/parser.h> +#include <libxml/xmlerror.h> +#include <libxml/xmlIO.h> +#include <libxml/xmlsave.h> #include <libxml/threads.h> + #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 b682b6b9403a0bed9da4d501e96d356eca8819f9..135b69669b38b65abc7ef51476ad532f2923042e 100644 --- a/include/libxml/hash.h +++ b/include/libxml/hash.h @@ -11,6 +11,10 @@ #ifndef __XML_HASH_H__ #define __XML_HASH_H__ +#include <libxml/xmlversion.h> +#include <libxml/dict.h> +#include <libxml/xmlstring.h> + #ifdef __cplusplus extern "C" { #endif @@ -21,18 +25,6 @@ extern "C" { typedef struct _xmlHashTable xmlHashTable; typedef xmlHashTable *xmlHashTablePtr; -#ifdef __cplusplus -} -#endif - -#include <libxml/xmlversion.h> -#include <libxml/parser.h> -#include <libxml/dict.h> - -#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 3211c755247b3d5d335dd8dcc82242d6ce58edef..1fa76aff0847fd3de18c942f5037bf6f12bbbb56 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 f39bde5be0729047748239003c3552dc96f49a38..ed3ac4f1fd2d68901d0066a5eae3dd904a8634ea 100644 --- a/include/libxml/nanoftp.h +++ b/include/libxml/nanoftp.h @@ -14,7 +14,7 @@ #include <libxml/xmlversion.h> -#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 22b8fb43381c816464bcf47715db7f80a62a95d6..c70d1c26bb880ccdfcee16d2c79f69d1d3472518 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 82c61d67e92967d5c9d6249238a0d810710b7b92..831aa53b42304187c2b9782939a91eba1234c535 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 <libxml/xmlversion.h> +#define XML_TREE_INTERNALS #include <libxml/tree.h> +#undef XML_TREE_INTERNALS #include <libxml/dict.h> #include <libxml/hash.h> #include <libxml/valid.h> #include <libxml/entities.h> #include <libxml/xmlerror.h> #include <libxml/xmlstring.h> +#include <libxml/xmlmemory.h> +#include <libxml/encoding.h> +#include <libxml/xmlIO.h> +/* for compatibility */ +#include <libxml/SAX2.h> +#include <libxml/threads.h> +/** 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 <libxml/encoding.h> -#include <libxml/xmlIO.h> -#include <libxml/globals.h> +#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 656ee4625c3f1c639eb1c954a19ac13ac3635181..c4d4363b53aa04269ac55c186c1d447494fded68 100644 --- a/include/libxml/parserInternals.h +++ b/include/libxml/parserInternals.h @@ -16,6 +16,7 @@ #include <libxml/parser.h> #include <libxml/HTMLparser.h> #include <libxml/chvalid.h> +#include <libxml/SAX2.h> #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 97d2cd2bc08521ad9f51063b5a9bef14d7ee9fb9..947f0900a23e0a7fb424d73fb31ddd9abaaf1656 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 6369785cef0ef58211c2f7a595ea281bf8c05a17..079b7f125d0d2d31b740faecd146bbd85705868e 100644 --- a/include/libxml/relaxng.h +++ b/include/libxml/relaxng.h @@ -11,8 +11,9 @@ #define __XML_RELAX_NG__ #include <libxml/xmlversion.h> -#include <libxml/hash.h> +#include <libxml/xmlerror.h> #include <libxml/xmlstring.h> +#include <libxml/tree.h> #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 c521d1c184cc998fb077eb7012f8408e926b2dee..e9d3b3c7abb1e5b6fa1b1f25fb9bc2ee5e46d56f 100644 --- a/include/libxml/schemasInternals.h +++ b/include/libxml/schemasInternals.h @@ -21,6 +21,7 @@ #include <libxml/xmlregexp.h> #include <libxml/hash.h> #include <libxml/dict.h> +#include <libxml/tree.h> #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 c61e61b3cf57a7a514330eace02de9c3afff3576..8dd8d25c451c3ee2fb988cc32f6d7f24492eb589 100644 --- a/include/libxml/schematron.h +++ b/include/libxml/schematron.h @@ -15,6 +15,7 @@ #ifdef LIBXML_SCHEMATRON_ENABLED +#include <libxml/xmlerror.h> #include <libxml/tree.h> #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 6eedac1f3746daaf3f4ea95f898981de15dee1bd..8f4b6e174fbac6e724e5a8da4ed65a8a297c0373 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 <libxml/globals.h> -#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 98e208745a923b50b8cf45f0472255304a2c5efd..f6b0b06301f8eaf4da348c876a3f1b1f22f85bff 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 <libxml/parser.h> + +#else /* XML_TREE_INTERNALS */ + #ifndef __XML_TREE_H__ #define __XML_TREE_H__ @@ -16,6 +25,8 @@ #include <limits.h> #include <libxml/xmlversion.h> #include <libxml/xmlstring.h> +#include <libxml/xmlmemory.h> +#include <libxml/xmlregexp.h> #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 <libxml/xmlregexp.h> -#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 <libxml/xmlmemory.h> -#endif #endif /* __XML_TREE_H__ */ +#endif /* XML_TREE_INTERNALS */ + diff --git a/include/libxml/uri.h b/include/libxml/uri.h index db48262b136f3c8895832a43cc5cad4c6b5edb9f..19980b711c56ef9c4b56c1f9f58e1c599d874008 100644 --- a/include/libxml/uri.h +++ b/include/libxml/uri.h @@ -11,8 +11,9 @@ #ifndef __XML_URI_H__ #define __XML_URI_H__ +#include <stdio.h> #include <libxml/xmlversion.h> -#include <libxml/tree.h> +#include <libxml/xmlstring.h> #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 3eaf84adcb4644a70c229df7437e21b9b09c7667..e1698d7a34025fe05b86d76ff1bd0ea873108523 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 <libxml/xmlversion.h> #include <libxml/xmlerror.h> +#define XML_TREE_INTERNALS #include <libxml/tree.h> +#undef XML_TREE_INTERNALS #include <libxml/list.h> #include <libxml/xmlautomata.h> #include <libxml/xmlregexp.h> +/** 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 a84beeb23e0cb6ebab3932ae8a743e75f3487a68..a598b67f6fab38d203701ec4ebb03d23c27605eb 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 863ab25ad9feeadf61be4c1fc761a8e396fc0644..71fa4c20dc2507242b50415f854c0362f913734c 100644 --- a/include/libxml/xinclude.h +++ b/include/libxml/xinclude.h @@ -14,6 +14,7 @@ #define __XML_XINCLUDE_H__ #include <libxml/xmlversion.h> +#include <libxml/xmlerror.h> #include <libxml/tree.h> #ifdef LIBXML_XINCLUDE_ENABLED @@ -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 04e4b32c015f6fc5f52f3c62b7e3d7cc9f386849..106573666ae462f2b4c1dafe86b39b1afb84530e 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 095b2f56d96c0ca448bb5f988e68959c021e808d..7810e42a86e41321a10493a4a295c8c28b720cae 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 <stdio.h> #include <libxml/xmlversion.h> +#include <libxml/encoding.h> +#define XML_TREE_INTERNALS +#include <libxml/tree.h> +#undef XML_TREE_INTERNALS +/** DOC_ENABLE */ #ifdef __cplusplus extern "C" { @@ -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 <libxml/globals.h> -#include <libxml/tree.h> -#include <libxml/parser.h> -#include <libxml/encoding.h> +/** + * 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 bf1b131c653427eff6989dfd8e57698411787da6..ea38eb37f09fe43a34d0d3f6fedbb8313d9b839f 100644 --- a/include/libxml/xmlautomata.h +++ b/include/libxml/xmlautomata.h @@ -11,11 +11,11 @@ #define __XML_AUTOMATA_H__ #include <libxml/xmlversion.h> -#include <libxml/tree.h> #ifdef LIBXML_REGEXP_ENABLED #ifdef LIBXML_AUTOMATA_ENABLED -#include <libxml/xmlregexp.h> + +#include <libxml/xmlstring.h> #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 ee95be9c9c21cf1dca42a7ae319196c1cd93034c..bd075b89c8118b4e74bddd011bbcd18143a135f4 100644 --- a/include/libxml/xmlerror.h +++ b/include/libxml/xmlerror.h @@ -7,11 +7,11 @@ * Author: Daniel Veillard */ -#include <libxml/parser.h> - #ifndef __XML_ERROR_H__ #define __XML_ERROR_H__ +#include <libxml/xmlversion.h> + #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 8831c54029e5399f7f948509b4354237aa6e7706..cc121f2f6ea2db61841a3e5dac0e8bda1348fb25 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 ae2a4275a3b1ddfb432fc9e7ee62e8ebea594547..0743bf08173ac634aebf7068235949dffcbd4a99 100644 --- a/include/libxml/xmlmemory.h +++ b/include/libxml/xmlmemory.h @@ -15,32 +15,6 @@ #include <stdio.h> #include <libxml/xmlversion.h> -/** - * 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 <libxml/threads.h> -#include <libxml/globals.h> -#endif -#endif - #endif /* __DEBUG_MEMORY_ALLOC__ */ diff --git a/include/libxml/xmlmodule.h b/include/libxml/xmlmodule.h index 9667820070af9341935bdaf57738a576c8308627..279986c1a9fe9c4025aa3f98cf5235018e5a22de 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 e8a8bcc9aab0041b5acabd8715952b078a36e674..5d4fc5d5a179fc7c128e44cf9aa9bf4b406ef8a8 100644 --- a/include/libxml/xmlreader.h +++ b/include/libxml/xmlreader.h @@ -12,11 +12,14 @@ #include <libxml/xmlversion.h> #include <libxml/tree.h> +#include <libxml/xmlerror.h> #include <libxml/xmlIO.h> #ifdef LIBXML_SCHEMAS_ENABLED #include <libxml/relaxng.h> #include <libxml/xmlschemas.h> #endif +/* for compatibility */ +#include <libxml/parser.h> #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 7009645a9252aa2b245c8fc247ab47adf4b3b3c9..2d66437a55b547fc809941ee0a9bafec722a432d 100644 --- a/include/libxml/xmlregexp.h +++ b/include/libxml/xmlregexp.h @@ -11,7 +11,9 @@ #ifndef __XML_REGEXP_H__ #define __XML_REGEXP_H__ +#include <stdio.h> #include <libxml/xmlversion.h> +#include <libxml/xmlstring.h> #ifdef LIBXML_REGEXP_ENABLED @@ -36,28 +38,19 @@ typedef xmlRegexp *xmlRegexpPtr; typedef struct _xmlRegExecCtxt xmlRegExecCtxt; typedef xmlRegExecCtxt *xmlRegExecCtxtPtr; -#ifdef __cplusplus -} -#endif -#include <libxml/tree.h> -#include <libxml/dict.h> -#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 fb329b22dbc2a8d113f34329ca9e44b410c5c7eb..e266e467c24b282a17818a013035cfe473fe50d8 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 b90e9d18c6e60de5291b3fe1a16a0400c7a72914..c2af3d7098b924f0ed7bc0ab37299ae3e06d204b 100644 --- a/include/libxml/xmlschemas.h +++ b/include/libxml/xmlschemas.h @@ -16,7 +16,10 @@ #ifdef LIBXML_SCHEMAS_ENABLED +#include <stdio.h> +#include <libxml/encoding.h> #include <libxml/tree.h> +#include <libxml/xmlerror.h> #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 5d588f92ea348d0bbaad2eeb06eebf0cbeff767c..e2cde35707c5d14f4bdab4d0a6750719d52edda6 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 2d0b2d1668eb7c9cd50cf54642577795e473c69e..db11a0b0e50482acf67efd6b9c7ca03879648d45 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 01ac8b61f56a8e6955ff1004c19d9b62fdfb4280..b6d795b267d50c22553caed286ec2aea1803a336 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 bdebfe3b0c9eaa35f8cd0e94ca10f69ade97605a..f153a942f262a6340d8c7a7244e7163ade66a6ab 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 <libxml/xmlexports.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * use those to be sure nothing nasty will happen if - * your library and includes mismatch - */ -#ifndef LIBXML2_COMPILING_MSCCDEF -XMLPUBFUN void 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 <libxml/xmlexports.h> -#ifdef __cplusplus -} -#endif /* __cplusplus */ #endif diff --git a/include/libxml/xmlwriter.h b/include/libxml/xmlwriter.h index dd5add341668c549aff41fead5a04c0e3fbdb97c..55f88bc71f0c55d0d162a398bc5300dc87290f1b 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 bfbc5d6d99517a045211349c82413ef22ba83f01..b89e105c08f8d0b815302aec689059306903f96f 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 76a6b481572d72a06c778ef949b0bf0df30382af..d1c90dff2aac24ba418503d433e7609661233060 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 <stdio.h> #include <libxml/xmlversion.h> #include <libxml/xpath.h> @@ -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 ca7bdbe085f936a3e88342eb7ef75d75197cfa33..a5260008fc09875d409c59d8c6099f97110ebd6f 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 0000000000000000000000000000000000000000..982b9eea00b132598c523c32c2b4ad3dee0788c4 --- /dev/null +++ b/include/private/buf.h @@ -0,0 +1,61 @@ +#ifndef XML_BUF_H_PRIVATE__ +#define XML_BUF_H_PRIVATE__ + +#include <libxml/tree.h> + +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 0000000000000000000000000000000000000000..826ac54a51f95720d7cff1394b1b1bdfe037fa83 --- /dev/null +++ b/include/private/dict.h @@ -0,0 +1,74 @@ +#ifndef XML_DICT_H_PRIVATE__ +#define XML_DICT_H_PRIVATE__ + +#include <libxml/dict.h> + +/* + * 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 0000000000000000000000000000000000000000..cd549145eb284ded3e9c7b7b4f8a396b888460db --- /dev/null +++ b/include/private/enc.h @@ -0,0 +1,18 @@ +#ifndef XML_ENC_H_PRIVATE__ +#define XML_ENC_H_PRIVATE__ + +#include <libxml/encoding.h> +#include <libxml/tree.h> + +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 0000000000000000000000000000000000000000..d262ef47f6545cc38cced4d510b1b87d1ef91e9a --- /dev/null +++ b/include/private/entities.h @@ -0,0 +1,27 @@ +#ifndef XML_ENTITIES_H_PRIVATE__ +#define XML_ENTITIES_H_PRIVATE__ + +#include <libxml/tree.h> +#include <libxml/xmlstring.h> + +/* + * 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 0000000000000000000000000000000000000000..506405a1f06fac44c6bfa295b9f5b9fefb5bcbbc --- /dev/null +++ b/include/private/error.h @@ -0,0 +1,34 @@ +#ifndef XML_ERROR_H_PRIVATE__ +#define XML_ERROR_H_PRIVATE__ + +#include <libxml/xmlerror.h> +#include <libxml/xmlversion.h> + +#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 0000000000000000000000000000000000000000..828b6d50fe7ded4baf6521f930fd35ab5e1e28ab --- /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 0000000000000000000000000000000000000000..6b499296a6b016e01093c358618de983617c5821 --- /dev/null +++ b/include/private/html.h @@ -0,0 +1,14 @@ +#ifndef XML_HTML_H_PRIVATE__ +#define XML_HTML_H_PRIVATE__ + +#include <libxml/xmlversion.h> + +#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 0000000000000000000000000000000000000000..a2535ae196193883805a8a41437118b42ad6732f --- /dev/null +++ b/include/private/io.h @@ -0,0 +1,35 @@ +#ifndef XML_IO_H_PRIVATE__ +#define XML_IO_H_PRIVATE__ + +#include <libxml/encoding.h> +#include <libxml/tree.h> +#include <libxml/xmlversion.h> + +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 0000000000000000000000000000000000000000..ef0497c65cf0ee5d172fa73aff6541f5f0f9d4f0 --- /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 0000000000000000000000000000000000000000..b14bebf918e0a0c182a1497721da978995905cab --- /dev/null +++ b/include/private/parser.h @@ -0,0 +1,121 @@ +#ifndef XML_PARSER_H_PRIVATE__ +#define XML_PARSER_H_PRIVATE__ + +#include <libxml/parser.h> +#include <libxml/xmlversion.h> + +/** + * 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 0000000000000000000000000000000000000000..b55c932bc0eaf80f220f783a93adc08bc6f6524c --- /dev/null +++ b/include/private/regexp.h @@ -0,0 +1,23 @@ +#ifndef XML_REGEXP_H_PRIVATE__ +#define XML_REGEXP_H_PRIVATE__ + +#include <libxml/xmlautomata.h> + +#ifdef LIBXML_REGEXP_ENABLED + +/* + * -2 and -3 are used by xmlValidateElementType for other things. + */ +#define XML_REGEXP_OK 0 +#define XML_REGEXP_NOT_FOUND (-1) +#define XML_REGEXP_INTERNAL_ERROR (-4) +#define XML_REGEXP_OUT_OF_MEMORY (-5) +#define XML_REGEXP_INTERNAL_LIMIT (-6) +#define XML_REGEXP_INVALID_UTF8 (-7) + +XML_HIDDEN void +xmlAutomataSetFlags(xmlAutomataPtr am, int flags); + +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /* XML_REGEXP_H_PRIVATE__ */ diff --git a/include/private/save.h b/include/private/save.h new file mode 100644 index 0000000000000000000000000000000000000000..5d4a753f1ac78e0cdfe815ecad34877291d2c24e --- /dev/null +++ b/include/private/save.h @@ -0,0 +1,24 @@ +#ifndef XML_SAVE_H_PRIVATE__ +#define XML_SAVE_H_PRIVATE__ + +#include <libxml/tree.h> +#include <libxml/xmlsave.h> +#include <libxml/xmlversion.h> + +#ifdef LIBXML_OUTPUT_ENABLED + +XML_HIDDEN int +xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur); +XML_HIDDEN int +xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur); + +XML_HIDDEN void +xmlBufAttrSerializeTxtContent(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 0000000000000000000000000000000000000000..34f4c96cb206abb0e78a1d01702f628b6e94c023 --- /dev/null +++ b/include/private/string.h @@ -0,0 +1,13 @@ +#ifndef XML_STRING_H_PRIVATE__ +#define XML_STRING_H_PRIVATE__ + +#include <libxml/xmlstring.h> + +XML_HIDDEN int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap); +XML_HIDDEN int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...); +XML_HIDDEN xmlChar * +xmlEscapeFormatString(xmlChar **msg); + +#endif /* XML_STRING_H_PRIVATE__ */ diff --git a/include/private/threads.h b/include/private/threads.h new file mode 100644 index 0000000000000000000000000000000000000000..473bc7c0bcb37bcc5d59765b7af1bd5044ca81e7 --- /dev/null +++ b/include/private/threads.h @@ -0,0 +1,35 @@ +#ifndef XML_THREADS_H_PRIVATE__ +#define XML_THREADS_H_PRIVATE__ + +#include <libxml/threads.h> + +#ifdef LIBXML_THREAD_ENABLED + #ifdef HAVE_PTHREAD_H + #include <pthread.h> + #define HAVE_POSIX_THREADS + #elif defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #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 0000000000000000000000000000000000000000..2d651d53f4bb3776b8661f393e72f602daebf3bb --- /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 0000000000000000000000000000000000000000..43c77e5061816f83afd6646a7f0d2a3e9d800744 --- /dev/null +++ b/include/private/xinclude.h @@ -0,0 +1,9 @@ +#ifndef XML_INCLUDE_H_PRIVATE__ +#define XML_INCLUDE_H_PRIVATE__ + +#include <libxml/xinclude.h> + +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 0000000000000000000000000000000000000000..72a69720332175e332f9b5417818f4fabd325fec --- /dev/null +++ b/include/private/xpath.h @@ -0,0 +1,16 @@ +#ifndef XML_XPATH_H_PRIVATE__ +#define XML_XPATH_H_PRIVATE__ + +#include <libxml/xpath.h> + +XML_HIDDEN void +xmlInitXPathInternal(void); + +#ifdef LIBXML_XPATH_ENABLED +XML_HIDDEN void +xmlXPathErrMemory(xmlXPathContextPtr ctxt); +XML_HIDDEN void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt); +#endif + +#endif /* XML_XPATH_H_PRIVATE__ */ diff --git a/include/private/xzlib.h b/include/private/xzlib.h new file mode 100644 index 0000000000000000000000000000000000000000..8505ef329e8f3dc19eb4747eaac0e3a8302fefdf --- /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 <afb@users.sourceforge.net> + */ + +#ifndef LIBXML2_XZLIB_H +#define LIBXML2_XZLIB_H + +#include <libxml/xmlversion.h> + +#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 4f99ae0b2ea6aa54e9996e4711ced7bc123d1833..a25e0385024fc080daf26adb6512da73bdf530eb 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 0000000000000000000000000000000000000000..141de0c6405b25c4b8c7c2065ffd31e1185b0bd6 --- /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 <errno.h> +#include <winsock2.h> + +/* 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 <ws2tcpip.h> + +/* Check if ws2tcpip.h is a recent version which provides getaddrinfo() */ +#if defined(GetAddrInfo) +#include <wspiapi.h> +#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 bde3854d92bb1cd896a1c2d02b289231d0072728..ac80c0e4df9f5f5a18764e7acd987bdb4ad0861c 100644 --- a/legacy.c +++ b/legacy.c @@ -11,6 +11,7 @@ #include "libxml.h" #ifdef LIBXML_LEGACY_ENABLED +#include <stdio.h> #include <string.h> #include <libxml/tree.h> @@ -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 <libxml/nanoftp.h> + +/** DOC_DISABLE */ + +#ifdef _WIN32 + #include <winsock2.h> +#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 <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/xpointer.h> + +/** 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 66f164d544b3a2a269846cce32f25cf6158e21e7..d94677b56693c759a5d1d35298ac1816800256a8 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 <libxml/xmlversion.h> -#include <libxml/xmlstring.h> +/* + * 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 <stdio.h> /* pull definition of size_t */ -#include <varargs.h> -int snprintf(char *, size_t, const char *, ...); -int vfprintf(FILE *, const char *, va_list); -#endif - -#ifndef WITH_TRIO -#include <stdio.h> +#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 12a7c009277cff091ccaf0ad090964e952ed2ba8..20df26c87c7c324fe85d6e835972bbf82780e19e 100644 --- a/list.c +++ b/list.c @@ -21,8 +21,8 @@ #include <stdlib.h> #include <string.h> #include <libxml/xmlmemory.h> +#include <libxml/xmlerror.h> #include <libxml/list.h> -#include <libxml/globals.h> /* * 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 6de7d300a3abce5e9a4894a378d512bcf0b683b7..fc8f8d751458a58b853da69b2cba05deb0e4e4e4 100644 --- a/nanoftp.c +++ b/nanoftp.c @@ -23,6 +23,8 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> +#elif defined (_WIN32) +#include <io.h> #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> @@ -48,24 +50,15 @@ #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #include <libxml/xmlmemory.h> #include <libxml/parser.h> #include <libxml/xmlerror.h> #include <libxml/uri.h> #include <libxml/nanoftp.h> -#include <libxml/globals.h> - -/* #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 <wsockcompat.h> @@ -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 <stdio.h> 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 2eafd3f4910f68990870bbf29b453c3af045d596..5c67893058433444da1345a5299eeed732a65341 100644 --- a/nanohttp.c +++ b/nanohttp.c @@ -16,14 +16,14 @@ #ifdef LIBXML_HTTP_ENABLED #include <string.h> +#include <ctype.h> #include <stdlib.h> #include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> +#elif defined (_WIN32) +#include <io.h> #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> @@ -37,12 +37,6 @@ #ifdef HAVE_NETDB_H #include <netdb.h> #endif -#ifdef HAVE_RESOLV_H -#ifdef HAVE_ARPA_NAMESER_H -#include <arpa/nameser.h> -#endif -#include <resolv.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -70,37 +64,32 @@ #include <wsockcompat.h> #endif -#include <libxml/globals.h> #include <libxml/xmlerror.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> /* for xmlStr(n)casecmp() */ #include <libxml/nanohttp.h> -#include <libxml/globals.h> #include <libxml/uri.h> +#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 <stdio.h> 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 93f031be863a7de2f814767a86721dadae14343b..365025c5eb94f3811e42d325a6e3b1173a67a032 100644 --- a/parser.c +++ b/parser.c @@ -51,11 +51,9 @@ #include <stddef.h> #include <ctype.h> #include <stdlib.h> +#include <libxml/parser.h> #include <libxml/xmlmemory.h> -#include <libxml/threads.h> -#include <libxml/globals.h> #include <libxml/tree.h> -#include <libxml/parser.h> #include <libxml/parserInternals.h> #include <libxml/valid.h> #include <libxml/entities.h> @@ -63,16 +61,27 @@ #include <libxml/encoding.h> #include <libxml/xmlIO.h> #include <libxml/uri.h> +#include <libxml/SAX2.h> #ifdef LIBXML_CATALOG_ENABLED #include <libxml/catalog.h> #endif -#ifdef LIBXML_SCHEMAS_ENABLED -#include <libxml/xmlschemastypes.h> -#include <libxml/relaxng.h> -#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 '<?xml' required"; - break; - case XML_ERR_XMLDECL_NOT_FINISHED: - errmsg = "parsing XML declaration: '?>' expected"; - break; - case XML_ERR_EXT_ENTITY_STANDALONE: - errmsg = "external parsed entities cannot be standalone"; - break; - case XML_ERR_ENTITYREF_SEMICOL_MISSING: - errmsg = "EntityRef: expecting ';'"; - break; - case XML_ERR_DOCTYPE_NOT_FINISHED: - errmsg = "DOCTYPE improperly terminated"; - break; - case XML_ERR_LTSLASH_REQUIRED: - errmsg = "EndTag: '</' not found"; - break; - case XML_ERR_EQUAL_REQUIRED: - errmsg = "expected '='"; - break; - case XML_ERR_STRING_NOT_CLOSED: - errmsg = "String not closed expecting \" or '"; - break; - case XML_ERR_STRING_NOT_STARTED: - errmsg = "String not started expecting ' or \""; - break; - case XML_ERR_ENCODING_NAME: - errmsg = "Invalid XML encoding name"; - break; - case XML_ERR_STANDALONE_VALUE: - errmsg = "standalone accepts only 'yes' or 'no'"; - break; - case XML_ERR_DOCUMENT_EMPTY: - errmsg = "Document is empty"; - break; - case XML_ERR_DOCUMENT_END: - errmsg = "Extra content at the end of the document"; - break; - case XML_ERR_NOT_WELL_BALANCED: - errmsg = "chunk is not well balanced"; - break; - case XML_ERR_EXTRA_CONTENT: - errmsg = "extra content at the end of well balanced chunk"; - break; - case XML_ERR_VERSION_MISSING: - errmsg = "Malformed declaration expecting version"; - break; - case XML_ERR_NAME_TOO_LONG: - errmsg = "Name too long use XML_PARSE_HUGE option"; - break; -#if 0 - case: - errmsg = ""; - break; -#endif - default: - errmsg = "Unregistered error message"; - } - if (ctxt != NULL) - ctxt->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 '<!'. + * * The spec says that "For compatibility, the string "--" (double-hyphen) * must not occur within comments. " * @@ -4875,22 +5225,22 @@ xmlParseComment(xmlParserCtxtPtr ctxt) { xmlChar *buf = NULL; size_t size = XML_PARSER_BUFFER_SIZE; size_t len = 0; - xmlParserInputState state; + size_t maxLength = (ctxt->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 ::= '<?' PITarget (S (Char* - (Char* '?>' 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 '<!'. * * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>' * @@ -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 '<!NOTATION'\n"); return; @@ -5343,7 +5640,7 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { "colons are forbidden from notation names '%s'\n", name, NULL, NULL); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the NOTATION name'\n"); return; @@ -5353,7 +5650,7 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { * Parse the IDs. */ Systemid = xmlParseExternalID(ctxt, &Pubid, 0); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW == '>') { if (inputid != ctxt->input->id) { @@ -5377,7 +5674,9 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { * xmlParseEntityDecl: * @ctxt: an XML parser context * - * parse <!ENTITY declarations + * DEPRECATED: Internal function, don't use. + * + * Parse an entity declaration. Always consumes '<!'. * * [70] EntityDecl ::= GEDecl | PEDecl * @@ -5404,19 +5703,22 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { int isParameter = 0; xmlChar *orig = NULL; + if ((CUR != '<') || (NXT(1) != '!')) + return; + SKIP(2); + /* GROW; done in the caller */ - if (CMP8(CUR_PTR, '<', '!', 'E', 'N', 'T', 'I', 'T', 'Y')) { + if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) { int inputid = ctxt->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 '<!ENTITY'\n"); } if (RAW == '%') { NEXT; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '%%'\n"); } @@ -5434,12 +5736,11 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { "colons are forbidden from entities names '%s'\n", name, NULL, NULL); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the entity name\n"); } - ctxt->instate = XML_PARSER_ENTITY_DECL; /* * handle the various case of definitions... */ @@ -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 '<!'. * * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' * @@ -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 '<!ATTLIST'\n"); } @@ -5982,9 +6269,9 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { "ATTLIST: no name for Element\n"); return; } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; - while ((RAW != '>') && (ctxt->instate != XML_PARSER_EOF)) { + while ((RAW != '>') && (PARSER_STOPPED(ctxt) == 0)) { int type; int def; xmlChar *defaultValue = NULL; @@ -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 '<!'. * * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' * @@ -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 '<!['. + * * [61] conditionalSect ::= includeSect | ignoreSect * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' @@ -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 '<!' or '<?'. * * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | * NotationDecl | PI | Comment @@ -6863,6 +7140,8 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { xmlParseElementDecl(ctxt); else if (NXT(3) == 'N') xmlParseEntityDecl(ctxt); + else + SKIP(2); break; case 'A': xmlParseAttributeListDecl(ctxt); @@ -6875,27 +7154,21 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { break; default: /* there is an error but it will be detected later */ + SKIP(2); break; } } else if (NXT(1) == '?') { xmlParsePI(ctxt); } } - - /* - * detect requirement to exit there and act accordingly - * and avoid having instate overridden later on - */ - if (ctxt->instate == XML_PARSER_EOF) - return; - - ctxt->instate = XML_PARSER_DTD; } /** * xmlParseTextDecl: * @ctxt: an XML parser context * + * DEPRECATED: Internal function, don't use. + * * parse an XML declaration header for external entities * * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>' @@ -6904,8 +7177,6 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { void xmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlChar *version; - const xmlChar *encoding; - int oldstate; /* * We know that '<?xml' is here. @@ -6917,10 +7188,6 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { return; } - /* Avoid expansion of parameter entities when skipping blanks. */ - oldstate = ctxt->instate; - ctxt->instate = XML_PARSER_START; - if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed after '<?xml'\n"); @@ -6930,9 +7197,13 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { * We may have the VersionInfo here. */ version = xmlParseVersionInfo(ctxt); - if (version == NULL) + if (version == NULL) { version = xmlCharStrdup(XML_DEFAULT_VERSION); - else { + if (version == NULL) { + xmlErrMemory(ctxt); + return; + } + } else { if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed here\n"); @@ -6943,18 +7214,7 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { /* * We must have the encoding declaration */ - encoding = xmlParseEncodingDecl(ctxt); - if (ctxt->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: + * + * <!DOCTYPE doc [ + * <!ENTITY ent "<ns:elem/>"> + * ]> + * <doc> + * <decl1 xmlns:ns="urn:ns1"> + * &ent; + * </decl1> + * <decl2 xmlns:ns="urn:ns2"> + * &ent; + * </decl2> + * </doc> + * + * 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 ::= '<!DOCTYPE' S Name (S ExternalID)? S? @@ -8312,8 +8181,6 @@ xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) { if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) && (!ctxt->disableSAX)) ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI); - if (ctxt->instate == XML_PARSER_EOF) - return; /* * Is there any internal subset declarations ? @@ -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 '</'. * * [42] ETag ::= '</' Name S? '>' * @@ -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 ::= '</' Name S? '>' @@ -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 '</'. * * [42] ETag ::= '</' Name S? '>' * @@ -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 '<!['. * * [18] CDSect ::= CDStart CData CDEnd * @@ -9762,81 +9587,67 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { int r, rl; int s, sl; int cur, l; - int count = 0; + int maxLength = (ctxt->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 '</'. - * - * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * Parse XML element content. This is useful if you're only interested + * in custom SAX callbacks. If you want a node list, use + * xmlParseInNodeContext. */ - void xmlParseContent(xmlParserCtxtPtr ctxt) { - int nameNr = ctxt->nameNr; + if ((ctxt == NULL) || (ctxt->input == NULL)) + return; + + xmlCtxtInitializeLate(ctxt); xmlParseContentInternal(ctxt); - if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->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 '</'. */ static void xmlParseElementEnd(xmlParserCtxtPtr ctxt) { - xmlParserNodeInfo node_info; - xmlNodePtr ret = ctxt->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: '</' should be here. @@ -10152,14 +9982,17 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt) { #endif /* LIBXML_SAX1_ENABLED */ /* - * Capture end position and add node + * Capture end position */ - 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 (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 ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' @@ -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 '<?xml' is here. @@ -10604,18 +10398,11 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n"); } xmlParseEncodingDecl(ctxt); - if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || - (ctxt->instate == XML_PARSER_EOF)) { - /* - * The XML REC instructs us to stop parsing right here - */ - return; - } /* * We may have the standalone status. */ - 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 "<?xml version="1.0" encoding="foo" - */ - if ((ctxt->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 "<!--" and "-->" + * 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 <libxml/xpath.h> -#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 31d94680a5541165862a8ed0a1e8eae395e28368..6ddd28e78581f446ff2ec684591fd5de991479b9 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -24,27 +24,35 @@ #include <libxml/tree.h> #include <libxml/parser.h> #include <libxml/parserInternals.h> -#include <libxml/valid.h> #include <libxml/entities.h> #include <libxml/xmlerror.h> #include <libxml/encoding.h> -#include <libxml/valid.h> #include <libxml/xmlIO.h> #include <libxml/uri.h> #include <libxml/dict.h> -#include <libxml/SAX.h> +#include <libxml/xmlsave.h> #ifdef LIBXML_CATALOG_ENABLED #include <libxml/catalog.h> #endif -#include <libxml/globals.h> #include <libxml/chvalid.h> +#include <libxml/nanohttp.h> #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 : "<null>")); + 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 - * '<?xml version="1.0" encoding="xxx"?>' - * 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, "<null>"); + xmlFreeInputStream(ret); + ret = NULL; + } else { + + mime = xmlNanoHTTPMimeType(ret->buf->context); + if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || + (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { + encoding = xmlNanoHTTPEncoding(ret->buf->context); + if (encoding != NULL) + xmlSwitchEncodingName(ctxt, encoding); +#if 0 + } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { +#endif + } + redir = xmlNanoHTTPRedir(ret->buf->context); + if (redir != NULL) { + if (ret->filename != NULL) + xmlFree((xmlChar *) ret->filename); + ret->filename = + (char *) xmlStrdup((const xmlChar *) redir); + } + } } - 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 cff4469c61daa62a9ae513b236a147aaa8c402c3..23b52744ac5a99334454521180d7aba3450056de 100644 --- a/pattern.c +++ b/pattern.c @@ -27,18 +27,15 @@ #include "libxml.h" #include <string.h> +#include <libxml/pattern.h> #include <libxml/xmlmemory.h> #include <libxml/tree.h> -#include <libxml/hash.h> #include <libxml/dict.h> #include <libxml/xmlerror.h> #include <libxml/parserInternals.h> -#include <libxml/pattern.h> #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 7f0f2e741ed180b5341c738d8bb0c6b7adea7ad4..24c3e51056cd840377afa3d41de79dab8e3c4a38 100644 --- a/relaxng.c +++ b/relaxng.c @@ -34,6 +34,10 @@ #include <libxml/xmlregexp.h> #include <libxml/xmlschemastypes.h> +#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 <include> start from %s\n", URL); - else - xmlGenericError(xmlGenericErrorContext, - "Elimination of <include> 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 <grammar> 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 <start>: %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 0000000000000000000000000000000000000000..799a60e6347a3ba15ab5da45b99808e4a64ebea8 --- /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 <veillard@redhat.com> + */ + +#include <string.h> + +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/relaxng.h> +#include <libxml/dict.h> + +#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 0000000000000000000000000000000000000000..75b8f3ad79707abb816bf5c3d1d38dfcabd11071 --- /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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/tree.h> +#include <libxml/uri.h> +#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#include <libxml/xmlreader.h> + +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#include <libxml/relaxng.h> +#include <libxml/xmlschemas.h> +#include <libxml/xmlschemastypes.h> + +#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 <resource> + */ +#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 <valid> 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 <valid> 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 <invalid> tests + */ + tmp = getNext(cur, "following-sibling::invalid[1]"); + while (tmp != NULL) { + test = getNext(tmp, "./*"); + if (test == NULL) { + fprintf(stderr, "Failed to find test in <invalid> 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 0000000000000000000000000000000000000000..26681a3c207cbc038e1ae58fea608179dced03d1 --- /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 <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#elif defined (_WIN32) +#include <io.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/tree.h> +#include <libxml/uri.h> +#include <libxml/encoding.h> + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef LIBXML_READER_ENABLED +#include <libxml/xmlreader.h> +#endif + +#ifdef LIBXML_XINCLUDE_ENABLED +#include <libxml/xinclude.h> +#endif + +#ifdef LIBXML_XPATH_ENABLED +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#ifdef LIBXML_XPTR_ENABLED +#include <libxml/xpointer.h> +#endif +#endif + +#ifdef LIBXML_SCHEMAS_ENABLED +#include <libxml/relaxng.h> +#include <libxml/xmlschemas.h> +#include <libxml/xmlschemastypes.h> +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#include <libxml/pattern.h> +#endif + +#ifdef LIBXML_C14N_ENABLED +#include <libxml/c14n.h> +#endif + +#ifdef LIBXML_HTML_ENABLED +#include <libxml/HTMLparser.h> +#include <libxml/HTMLtree.h> +#endif + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +#include <libxml/threads.h> +#include <libxml/parser.h> +#include <libxml/catalog.h> +#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 <windows.h> + +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 <glob.h> +#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<res; ix++) + if (bytes[ix] != mem[idx+ix]) + break; + fprintf(stderr,"Compare error at position %d\n", idx+ix); + close(fd); + return(1); + } + idx += res; + } + close(fd); + if (idx != size) { + fprintf(stderr,"Compare error index %d, size %d\n", idx, size); + } + return(idx != size); +} + +static int loadMem(const char *filename, const char **mem, int *size) { + int fd, res; + struct stat info; + char *base; + int siz = 0; + if (stat(filename, &info) < 0) + return(-1); + base = malloc(info.st_size + 1); + if (base == NULL) + return(-1); + if ((fd = open(filename, RD_FLAGS)) < 0) { + free(base); + return(-1); + } + while ((res = read(fd, &base[siz], info.st_size - siz)) > 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;(i<len) && (i < 30);i++) + output[i] = (char) ch[i]; + output[i] = 0; + + fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len); +} + +/** + * referenceDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * called when an entity reference is detected. + */ +static void +referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.reference(%s)\n", name); +} + +/** + * ignorableWhitespaceDebug: + * @ctxt: An XML parser context + * @ch: a xmlChar string + * @start: the first char in the string + * @len: the number of xmlChar + * + * receiving some ignorable whitespaces from the parser. + * Question: how much at a time ??? + */ +static void +ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + char output[40]; + int i; + + callbacks++; + if (quiet) + return; + for (i = 0;(i<len) && (i < 30);i++) + output[i] = (char) ch[i]; + output[i] = 0; + fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len); +} + +/** + * processingInstructionDebug: + * @ctxt: An XML parser context + * @target: the target name + * @data: the PI data's + * @len: the number of xmlChar + * + * A processing instruction has been parsed. + */ +static void +processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target, + const xmlChar *data) +{ + callbacks++; + if (quiet) + return; + if (data != NULL) + fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n", + (char *) target, (char *) data); + else + fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n", + (char *) target); +} + +/** + * cdataBlockDebug: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * called when a pcdata block has been parsed + */ +static void +cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n", + (char *) value, len); +} + +/** + * commentDebug: + * @ctxt: An XML parser context + * @value: the comment content + * + * A comment has been parsed. + */ +static void +commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.comment(%s)\n", value); +} + +/** + * warningDebug: + * @ctxt: 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 +warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (quiet) + return; + va_start(args, msg); + fprintf(SAXdebug, "SAX.warning: "); + vfprintf(SAXdebug, msg, args); + va_end(args); +} + +/** + * errorDebug: + * @ctxt: An XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a error messages, gives file, line, position and + * extra parameters. + */ +static void +errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (quiet) + return; + va_start(args, msg); + fprintf(SAXdebug, "SAX.error: "); + vfprintf(SAXdebug, msg, args); + va_end(args); +} + +/** + * fatalErrorDebug: + * @ctxt: An XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a fatalError messages, gives file, line, position and + * extra parameters. + */ +static void +fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (quiet) + return; + va_start(args, msg); + fprintf(SAXdebug, "SAX.fatalError: "); + vfprintf(SAXdebug, msg, args); + va_end(args); +} + +static xmlSAXHandler debugSAXHandlerStruct = { + internalSubsetDebug, + isStandaloneDebug, + hasInternalSubsetDebug, + hasExternalSubsetDebug, + resolveEntityDebug, + getEntityDebug, + entityDeclDebug, + notationDeclDebug, + attributeDeclDebug, + elementDeclDebug, + unparsedEntityDeclDebug, + setDocumentLocatorDebug, + startDocumentDebug, + endDocumentDebug, + startElementDebug, + endElementDebug, + referenceDebug, + charactersDebug, + ignorableWhitespaceDebug, + processingInstructionDebug, + commentDebug, + warningDebug, + errorDebug, + fatalErrorDebug, + getParameterEntityDebug, + cdataBlockDebug, + externalSubsetDebug, + 1, + NULL, + NULL, + NULL, + NULL +}; + +static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct; + +/* + * SAX2 specific callbacks + */ +/** + * startElementNsDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when an opening tag has been processed. + */ +static void +startElementNsDebug(void *ctx ATTRIBUTE_UNUSED, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + int i; + + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname); + if (prefix == NULL) + fprintf(SAXdebug, ", NULL"); + else + fprintf(SAXdebug, ", %s", (char *) prefix); + if (URI == NULL) + fprintf(SAXdebug, ", NULL"); + else + fprintf(SAXdebug, ", '%s'", (char *) URI); + fprintf(SAXdebug, ", %d", nb_namespaces); + + if (namespaces != NULL) { + for (i = 0;i < nb_namespaces * 2;i++) { + fprintf(SAXdebug, ", xmlns"); + if (namespaces[i] != NULL) + fprintf(SAXdebug, ":%s", namespaces[i]); + i++; + fprintf(SAXdebug, "='%s'", namespaces[i]); + } + } + fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted); + if (attributes != NULL) { + for (i = 0;i < nb_attributes * 5;i += 5) { + if (attributes[i + 1] != NULL) + fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]); + else + fprintf(SAXdebug, ", %s='", attributes[i]); + fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3], + (int)(attributes[i + 4] - attributes[i + 3])); + } + } + 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 +endElementNsDebug(void *ctx ATTRIBUTE_UNUSED, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname); + if (prefix == NULL) + fprintf(SAXdebug, ", NULL"); + else + fprintf(SAXdebug, ", %s", (char *) prefix); + if (URI == NULL) + fprintf(SAXdebug, ", NULL)\n"); + else + fprintf(SAXdebug, ", '%s')\n", (char *) URI); +} + +static xmlSAXHandler debugSAX2HandlerStruct = { + internalSubsetDebug, + isStandaloneDebug, + hasInternalSubsetDebug, + hasExternalSubsetDebug, + resolveEntityDebug, + getEntityDebug, + entityDeclDebug, + notationDeclDebug, + attributeDeclDebug, + elementDeclDebug, + unparsedEntityDeclDebug, + setDocumentLocatorDebug, + startDocumentDebug, + endDocumentDebug, + NULL, + NULL, + referenceDebug, + charactersDebug, + ignorableWhitespaceDebug, + processingInstructionDebug, + commentDebug, + warningDebug, + errorDebug, + fatalErrorDebug, + getParameterEntityDebug, + cdataBlockDebug, + externalSubsetDebug, + XML_SAX2_MAGIC, + NULL, + startElementNsDebug, + endElementNsDebug, + NULL +}; + +static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct; + +#ifdef LIBXML_HTML_ENABLED +/** + * htmlstartElementDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when an opening tag has been processed. + */ +static void +htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) +{ + int i; + + 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) { + unsigned char output[40]; + const unsigned char *att = atts[i]; + int outlen, attlen; + fprintf(SAXdebug, "='"); + while ((attlen = strlen((char*)att)) > 0) { + outlen = sizeof output - 1; + htmlEncodeEntities(output, &outlen, att, &attlen, '\''); + output[outlen] = 0; + fprintf(SAXdebug, "%s", (char *) output); + att += attlen; + } + fprintf(SAXdebug, "'"); + } + } + } + fprintf(SAXdebug, ")\n"); +} + +/** + * htmlcharactersDebug: + * @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 +htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + unsigned char output[40]; + int inlen = len, outlen = 30; + + htmlEncodeEntities(output, &outlen, ch, &inlen, 0); + output[outlen] = 0; + + fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len); +} + +/** + * htmlcdataDebug: + * @ctxt: An XML parser context + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some cdata chars from the parser. + * Question: how much at a time ??? + */ +static void +htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + unsigned char output[40]; + int inlen = len, outlen = 30; + + htmlEncodeEntities(output, &outlen, ch, &inlen, 0); + output[outlen] = 0; + + fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len); +} + +static xmlSAXHandler debugHTMLSAXHandlerStruct = { + internalSubsetDebug, + isStandaloneDebug, + hasInternalSubsetDebug, + hasExternalSubsetDebug, + resolveEntityDebug, + getEntityDebug, + entityDeclDebug, + notationDeclDebug, + attributeDeclDebug, + elementDeclDebug, + unparsedEntityDeclDebug, + setDocumentLocatorDebug, + startDocumentDebug, + endDocumentDebug, + htmlstartElementDebug, + endElementDebug, + referenceDebug, + htmlcharactersDebug, + ignorableWhitespaceDebug, + processingInstructionDebug, + commentDebug, + warningDebug, + errorDebug, + fatalErrorDebug, + getParameterEntityDebug, + htmlcdataDebug, + externalSubsetDebug, + 1, + NULL, + NULL, + NULL, + NULL +}; + +static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct; +#endif /* LIBXML_HTML_ENABLED */ + +static void +hashFreeEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xmlEntityPtr ent = payload; + + xmlFreeEntity(ent); +} + +/** + * saxParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the SAX API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +saxParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options) { + int ret; + char *temp; + + nb_tests++; + temp = resultFilename(filename, temp_directory, ".res"); + if (temp == NULL) { + fprintf(stderr, "out of memory\n"); + fatalError(); + } + SAXdebug = fopen(temp, "wb"); + if (SAXdebug == NULL) { + fprintf(stderr, "Failed to write to %s\n", temp); + free(temp); + return(-1); + } + +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + htmlParserCtxtPtr ctxt; + + ctxt = htmlNewSAXParserCtxt(emptySAXHandler, NULL); + htmlCtxtReadFile(ctxt, filename, NULL, options); + htmlFreeParserCtxt(ctxt); + ret = 0; + } else +#endif + { + xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename); + memcpy(ctxt->sax, 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 = "<list/>"; +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 <windows.h> +#include <string.h> + +#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 <pthread.h> + +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 0000000000000000000000000000000000000000..18893039da2e25017fb3c12b923430fefeb277fb --- /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 <stdio.h> +#include <libxml/xmlversion.h> + +#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_VALID_ENABLED) + +#include <string.h> +#include <sys/stat.h> + +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/tree.h> +#include <libxml/uri.h> +#include <libxml/xmlreader.h> + +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#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 192b6741335800e62d55d92dd69bb87a42465f5f..0000000000000000000000000000000000000000 --- 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 <libxml/tree.h> - -#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 68a4c622ebd346d749432962f8e7b8e06531f02d..1de25deb971cbac6addbf6841994d8b1c87fc5c6 100644 --- a/schematron.c +++ b/schematron.c @@ -25,6 +25,7 @@ #ifdef LIBXML_SCHEMATRON_ENABLED +#include <stdlib.h> #include <string.h> #include <libxml/parser.h> #include <libxml/tree.h> @@ -34,6 +35,8 @@ #include <libxml/pattern.h> #include <libxml/schematron.h> +#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 06191f2052f59c4b3844f20e51f89c5352b6f11d..9ecfd81319bb616d6bb8f1795168fa14b3c700a7 100644 --- a/threads.c +++ b/threads.c @@ -14,43 +14,62 @@ #include <stdlib.h> #include <libxml/threads.h> -#include <libxml/globals.h> - -#ifdef HAVE_PTHREAD_H -#include <pthread.h> -#elif defined HAVE_WIN32_THREADS -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#ifndef HAVE_COMPILER_TLS -#include <process.h> +#include <libxml/parser.h> +#ifdef LIBXML_CATALOG_ENABLED +#include <libxml/catalog.h> #endif -#endif - -#ifdef HAVE_BEOS_THREADS -#include <OS.h> -#include <TLS.h> +#ifdef LIBXML_SCHEMAS_ENABLED +#include <libxml/xmlschemastypes.h> +#include <libxml/relaxng.h> #endif #if defined(SOLARIS) #include <note.h> #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 <sys/single_threaded.h> -#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 df27aa11abab5d7d6ffcb421147c0e8ee9cd8ff6..53eae8e3b46078a5052e2c8b9f9f89708f6508f0 100644 --- a/tree.c +++ b/tree.c @@ -28,15 +28,13 @@ #include <vtk_zlib.h> #endif -#include <libxml/xmlmemory.h> #include <libxml/tree.h> +#include <libxml/xmlmemory.h> #include <libxml/parser.h> #include <libxml/uri.h> #include <libxml/entities.h> -#include <libxml/valid.h> #include <libxml/xmlerror.h> #include <libxml/parserInternals.h> -#include <libxml/globals.h> #ifdef LIBXML_HTML_ENABLED #include <libxml/HTMLtree.h> #endif @@ -44,8 +42,10 @@ #include <libxml/debugXML.h> #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 e101f6df5607686d8c992a92c5b817a34e39b4bd..0000000000000000000000000000000000000000 --- a/triodef.h +++ /dev/null @@ -1,228 +0,0 @@ -/************************************************************************* - * - * $Id$ - * - * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net> - * - * 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 8767a9fe6485b03a8a86c807acfcd186fe4812e2..0000000000000000000000000000000000000000 --- a/trionan.c +++ /dev/null @@ -1,914 +0,0 @@ -/************************************************************************* - * - * $Id$ - * - * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net> - * - * 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 <math.h> -#include <string.h> -#include <limits.h> -#include <float.h> -#if defined(TRIO_PLATFORM_UNIX) -# include <signal.h> -#endif -#if defined(TRIO_COMPILER_DECC) -# if defined(__linux__) -# include <cpml.h> -# else -# include <fp_class.h> -# endif -#endif -#include <assert.h> - -#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 <stdio.h> - -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 eac0e6f168628d8bc31779ebf855391a5b1aaac1..0000000000000000000000000000000000000000 --- a/trionan.h +++ /dev/null @@ -1,84 +0,0 @@ -/************************************************************************* - * - * $Id$ - * - * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net> - * - * 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 e5c790ebd91cbc5505a42ccd29c47b7e4f05163f..3b986532aeceba33f1e88525c0a1550f8e8b0468 100644 --- a/uri.c +++ b/uri.c @@ -16,9 +16,10 @@ #include <libxml/xmlmemory.h> #include <libxml/uri.h> -#include <libxml/globals.h> #include <libxml/xmlerror.h> +#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 "<segment>/../", where <segment> is a - * complete path segment not equal to "..", are removed from the - * buffer string. Removal of these path segments is performed - * iteratively, removing the leftmost matching pattern on each - * iteration, until no matching pattern remains. - * - * f) If the buffer string ends with "<segment>/..", where <segment> - * is a complete path segment not equal to "..", that - * "<segment>/.." is removed. - * - * To satisfy the "iterative" clause in (e), we need to collapse the - * string every time we find something that needs to be removed. Thus, - * we don't need to keep two pointers into the string: we only need a - * "current position" pointer. - */ - while (1) { - char *segp, *tmp; - - /* At the beginning of each iteration of this loop, "cur" points to - * the first character of the segment we want to examine. - */ - - /* Find the end of the current segment. */ - segp = cur; - while ((segp[0] != '/') && (segp[0] != '\0')) - ++segp; - - /* If this is the last segment, we're done (we need at least two - * segments to meet the criteria for the (e) and (f) cases). - */ - if (segp[0] == '\0') - break; - /* If the first segment is "..", or if the next segment _isn't_ "..", - * keep this segment and try the next one. + while (*cur != 0) { + /* + * At this point, out is either empty or ends with a separator. + * Collapse multiple separators first. */ - ++segp; - if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3)) - || ((segp[0] != '.') || (segp[1] != '.') - || ((segp[2] != '/') && (segp[2] != '\0')))) { - cur = segp; - continue; + while (xmlIsPathSeparator(*cur, isFile)) { +#if defined(_WIN32) || defined(__CYGWIN__) + /* Allow two separators at start of path */ + if ((isFile) && (out == path + 1)) + *out++ = '/'; +#endif + cur++; } - /* If we get here, remove this segment and the next one and back up - * to the previous segment (if there is one), to implement the - * "iteratively" clause. It's pretty much impossible to back up - * while maintaining two pointers into the buffer, so just compact - * the whole buffer now. - */ + if (*cur == '.') { + if (cur[1] == 0) { + /* Ignore "." at end of path */ + break; + } else if (xmlIsPathSeparator(cur[1], isFile)) { + /* Skip "./" */ + cur += 2; + continue; + } else if ((cur[1] == '.') && + ((cur[2] == 0) || xmlIsPathSeparator(cur[2], isFile))) { + if (numSeg > 0) { + /* Handle ".." by removing last segment */ + do { + out--; + } while ((out > path) && + !xmlIsPathSeparator(out[-1], isFile)); + numSeg--; + + if (cur[2] == 0) + break; + cur += 3; + continue; + } else if (out[0] == '/') { + /* Ignore extraneous ".." in absolute paths */ + if (cur[2] == 0) + break; + cur += 3; + continue; + } else { + /* Keep "../" at start of relative path */ + numSeg--; + } + } + } - /* If this is the end of the buffer, we're done. */ - if (segp[2] == '\0') { - cur[0] = '\0'; - break; + /* Copy segment */ + while ((*cur != 0) && !xmlIsPathSeparator(*cur, isFile)) { + *out++ = *cur++; } - /* Valgrind complained, strcpy(cur, segp + 3); */ - /* string will overlap, do not use strcpy */ - tmp = cur; - segp += 3; - while ((*tmp++ = *segp++) != 0) - ; - - /* If there are no previous segments, then keep going from here. */ - segp = cur; - while ((segp > path) && ((--segp)[0] == '/')) - ; - if (segp == path) - continue; - - /* "segp" is pointing to the end of a previous segment; find it's - * start. We need to back up to the previous segment and start - * over with that to handle things like "foo/bar/../..". If we - * don't do this, then on the first pass we'll remove the "bar/..", - * but be pointing at the second ".." so we won't realize we can also - * remove the "foo/..". - */ - cur = segp; - while ((cur > path) && (cur[-1] != '/')) - --cur; - } - out[0] = '\0'; - /* - * g) If the resulting buffer string still begins with one or more - * complete path segments of "..", then the reference is - * considered to be in error. Implementations may handle this - * error by retaining these components in the resolved path (i.e., - * treating them as part of the final URI), by removing them from - * the resolved path (i.e., discarding relative levels above the - * root), or by avoiding traversal of the reference. - * - * We discard them from the final path. - */ - if (path[0] == '/') { - cur = path; - while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') - && ((cur[3] == '/') || (cur[3] == '\0'))) - cur += 3; + /* Copy separator */ + if (*cur != 0) { + cur++; + *out++ = '/'; + } - if (cur != path) { - out = path; - while (cur[0] != '\0') - (out++)[0] = (cur++)[0]; - out[0] = 0; - } + numSeg++; } + /* Keep "." if output is empty and it's a file */ + if ((isFile) && (out <= path)) + *out++ = '.'; + *out = 0; + return(0); } +/** + * xmlNormalizeURIPath: + * @path: pointer to the path string + * + * Applies the 5 normalization steps to a path string--that is, RFC 2396 + * Section 5.2, steps 6.c through 6.g. + * + * Normalization occurs directly on the string, no new allocation is done + * + * Returns 0 or an error code + */ +int +xmlNormalizeURIPath(char *path) { + return(xmlNormalizePath(path, 0)); +} + static int is_hex(char c) { if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || @@ -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 1da812ea8c339561365d20dc8498e24a0ed06baa..0e4a9c299471c6348e3dcc9467b12d11e1a5bc69 100644 --- a/valid.c +++ b/valid.c @@ -21,17 +21,16 @@ #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> #include <libxml/list.h> -#include <libxml/globals.h> +#include <libxml/xmlsave.h> -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, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " EMPTY>\n"); - break; - case XML_ELEMENT_TYPE_ANY: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " ANY>\n"); - break; - case XML_ELEMENT_TYPE_MIXED: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_ELEMENT_TYPE_ELEMENT: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content); - xmlBufferWriteChar(buf, ">\n"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT struct corrupted invalid type\n", - NULL); - } + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) elem); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -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, "<!ATTLIST "); - xmlBufferWriteCHAR(buf, attr->elem); - xmlBufferWriteChar(buf, " "); - if (attr->prefix != NULL) { - xmlBufferWriteCHAR(buf, attr->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, attr->name); - switch (attr->atype) { - case XML_ATTRIBUTE_CDATA: - xmlBufferWriteChar(buf, " CDATA"); - break; - case XML_ATTRIBUTE_ID: - xmlBufferWriteChar(buf, " ID"); - break; - case XML_ATTRIBUTE_IDREF: - xmlBufferWriteChar(buf, " IDREF"); - break; - case XML_ATTRIBUTE_IDREFS: - xmlBufferWriteChar(buf, " IDREFS"); - break; - case XML_ATTRIBUTE_ENTITY: - xmlBufferWriteChar(buf, " ENTITY"); - break; - case XML_ATTRIBUTE_ENTITIES: - xmlBufferWriteChar(buf, " ENTITIES"); - break; - case XML_ATTRIBUTE_NMTOKEN: - xmlBufferWriteChar(buf, " NMTOKEN"); - break; - case XML_ATTRIBUTE_NMTOKENS: - xmlBufferWriteChar(buf, " NMTOKENS"); - break; - case XML_ATTRIBUTE_ENUMERATION: - xmlBufferWriteChar(buf, " ("); - xmlDumpEnumeration(buf, attr->tree); - break; - case XML_ATTRIBUTE_NOTATION: - xmlBufferWriteChar(buf, " NOTATION ("); - xmlDumpEnumeration(buf, attr->tree); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid type\n", - NULL); - } - switch (attr->def) { - case XML_ATTRIBUTE_NONE: - break; - case XML_ATTRIBUTE_REQUIRED: - xmlBufferWriteChar(buf, " #REQUIRED"); - break; - case XML_ATTRIBUTE_IMPLIED: - xmlBufferWriteChar(buf, " #IMPLIED"); - break; - case XML_ATTRIBUTE_FIXED: - xmlBufferWriteChar(buf, " #FIXED"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid def\n", - NULL); - } - if (attr->defaultValue != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, attr->defaultValue); - } - xmlBufferWriteChar(buf, ">\n"); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) attr); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -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, "<!NOTATION "); - xmlBufferWriteCHAR(buf, nota->name); - if (nota->PublicID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, nota->PublicID); - if (nota->SystemID != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - xmlBufferWriteChar(buf, " >\n"); -} -/** - * xmlDumpNotationDeclScan: - * @nota: A notation declaration - * @buf: the XML buffer output - * - * This is called with the hash scan function, and just reverses args - */ -static void -xmlDumpNotationDeclScan(void *nota, void *buf, - const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota); + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveNotationDecl(save, nota); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } /** @@ -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 0c6b3f296bf46cbf625e0c1aac9884320355e068..6c1e3ace64f7c838ca819631a91e2fb9e58b1963 100644 --- a/xinclude.c +++ b/xinclude.c @@ -22,22 +22,17 @@ #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> #include <libxml/encoding.h> -#include <libxml/globals.h> #ifdef LIBXML_XINCLUDE_ENABLED #include <libxml/xinclude.h> -#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 <libxml/debugXML.h> -#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: + * + * <doc xmlns:xi="http://www.w3.org/2001/XInclude"> + * <xi:include xpointer="xpointer(//e)"/> + * <e> + * <e> + * <e> + * <!-- more nested elements --> + * </e> + * </e> + * </e> + * </doc> + */ + 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 65715cb3a8fb6178c3e9a5f662ab506b52bae25e..3a77b1999de53e633a77b2aef23a54bf8329a6ad 100644 --- a/xlink.c +++ b/xlink.c @@ -19,9 +19,7 @@ #include <libxml/xmlmemory.h> #include <libxml/tree.h> #include <libxml/parser.h> -#include <libxml/valid.h> #include <libxml/xlink.h> -#include <libxml/globals.h> #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 e47e2b15274e05716978e5e9bebecbcee4f75e7b..353771b7f2535111193f0e23072f970711c82d3e 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 <stdlib.h> #include <errno.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -41,22 +36,8 @@ #include <direct.h> #endif -#ifndef S_ISDIR -# ifdef _S_ISDIR -# define S_ISDIR(x) _S_ISDIR(x) -# elif defined(S_IFDIR) -# ifdef S_IFMT -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -# elif defined(_S_IFMT) -# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) -# endif -# endif -#endif - -#include <libxml/xmlmemory.h> -#include <libxml/parser.h> -#include <libxml/parserInternals.h> #include <libxml/xmlIO.h> +#include <libxml/xmlmemory.h> #include <libxml/uri.h> #include <libxml/nanohttp.h> #include <libxml/nanoftp.h> @@ -64,19 +45,31 @@ #ifdef LIBXML_CATALOG_ENABLED #include <libxml/catalog.h> #endif -#include <libxml/globals.h> -#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 0000000000000000000000000000000000000000..cfc55132f3f05b8e94577cbf8aee5440715e0e95 --- /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 <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +#ifdef HAVE_LIBREADLINE +#include <readline/readline.h> +#ifdef HAVE_LIBHISTORY +#include <readline/history.h> +#endif +#endif + +#include <libxml/xmlmemory.h> +#include <libxml/uri.h> +#include <libxml/catalog.h> +#include <libxml/parser.h> + +#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 0000000000000000000000000000000000000000..3a7a8a002e96bf65918d14dc813667aaf97ca8dd --- /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 <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <time.h> +#include <errno.h> +#include <limits.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_TIMEB_H +#include <sys/timeb.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#elif defined (_WIN32) +#include <io.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +/* seems needed for Solaris */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif +#endif +#ifdef HAVE_LIBREADLINE +#include <readline/readline.h> +#ifdef HAVE_LIBHISTORY +#include <readline/history.h> +#endif +#endif + +#include <libxml/xmlmemory.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/HTMLparser.h> +#include <libxml/HTMLtree.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/debugXML.h> +#include <libxml/xmlerror.h> +#ifdef LIBXML_XINCLUDE_ENABLED +#include <libxml/xinclude.h> +#endif +#ifdef LIBXML_CATALOG_ENABLED +#include <libxml/catalog.h> +#endif +#include <libxml/xmlreader.h> +#ifdef LIBXML_SCHEMATRON_ENABLED +#include <libxml/schematron.h> +#endif +#ifdef LIBXML_SCHEMAS_ENABLED +#include <libxml/relaxng.h> +#include <libxml/xmlschemas.h> +#endif +#ifdef LIBXML_PATTERN_ENABLED +#include <libxml/pattern.h> +#endif +#ifdef LIBXML_C14N_ENABLED +#include <libxml/c14n.h> +#endif +#ifdef LIBXML_OUTPUT_ENABLED +#include <libxml/xmlsave.h> +#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, "<p>"); + + 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, "<pre>\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, "</pre>"); +} + +/** + * 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, "<b>error</b>: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "</p>\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, "<b>warning</b>: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "</p>\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, "<b>validity error</b>: "); + len = strlen(buffer); + va_start(args, msg); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "</p>\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, "<b>validity warning</b>: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + fprintf(ERR_STREAM, "</p>\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<len) && (i < 30);i++) + out[i] = (char) ch[i]; + out[i] = 0; + + fprintf(stdout, "SAX.characters(%s, %d)\n", out, len); +} + +/** + * referenceDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * called when an entity reference is detected. + */ +static void +referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.reference(%s)\n", name); +} + +/** + * ignorableWhitespaceDebug: + * @ctxt: An XML parser context + * @ch: a xmlChar string + * @start: the first char in the string + * @len: the number of xmlChar + * + * receiving some ignorable whitespaces from the parser. + * Question: how much at a time ??? + */ +static void +ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + char out[40]; + int i; + + callbacks++; + if (noout) + return; + for (i = 0;(i<len) && (i < 30);i++) + out[i] = ch[i]; + out[i] = 0; + fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", out, len); +} + +/** + * processingInstructionDebug: + * @ctxt: An XML parser context + * @target: the target name + * @data: the PI data's + * @len: the number of xmlChar + * + * A processing instruction has been parsed. + */ +static void +processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target, + const xmlChar *data) +{ + callbacks++; + if (noout) + return; + if (data != NULL) + fprintf(stdout, "SAX.processingInstruction(%s, %s)\n", + (char *) target, (char *) data); + else + fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n", + (char *) target); +} + +/** + * cdataBlockDebug: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * called when a pcdata block has been parsed + */ +static void +cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.pcdata(%.20s, %d)\n", + (char *) value, len); +} + +/** + * commentDebug: + * @ctxt: An XML parser context + * @value: the comment content + * + * A comment has been parsed. + */ +static void +commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.comment(%s)\n", value); +} + +/** + * warningDebug: + * @ctxt: 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) +warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (noout) + return; + va_start(args, msg); + fprintf(stdout, "SAX.warning: "); + vfprintf(stdout, msg, args); + va_end(args); +} + +/** + * errorDebug: + * @ctxt: An XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a error messages, gives file, line, position and + * extra parameters. + */ +static void LIBXML_ATTR_FORMAT(2,3) +errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (noout) + return; + va_start(args, msg); + fprintf(stdout, "SAX.error: "); + vfprintf(stdout, msg, args); + va_end(args); +} + +/** + * fatalErrorDebug: + * @ctxt: An XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a fatalError messages, gives file, line, position and + * extra parameters. + */ +static void LIBXML_ATTR_FORMAT(2,3) +fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) +{ + va_list args; + + callbacks++; + if (noout) + return; + va_start(args, msg); + fprintf(stdout, "SAX.fatalError: "); + vfprintf(stdout, msg, args); + va_end(args); +} + +static xmlSAXHandler debugSAXHandlerStruct = { + internalSubsetDebug, + isStandaloneDebug, + hasInternalSubsetDebug, + hasExternalSubsetDebug, + resolveEntityDebug, + getEntityDebug, + entityDeclDebug, + notationDeclDebug, + attributeDeclDebug, + elementDeclDebug, + unparsedEntityDeclDebug, + setDocumentLocatorDebug, + startDocumentDebug, + endDocumentDebug, + startElementDebug, + endElementDebug, + referenceDebug, + charactersDebug, + ignorableWhitespaceDebug, + processingInstructionDebug, + commentDebug, + warningDebug, + errorDebug, + fatalErrorDebug, + getParameterEntityDebug, + cdataBlockDebug, + externalSubsetDebug, + 1, + NULL, + NULL, + NULL, + NULL +}; + +xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct; + +/* + * SAX2 specific callbacks + */ +/** + * startElementNsDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when an opening tag has been processed. + */ +static void +startElementNsDebug(void *ctx ATTRIBUTE_UNUSED, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + int i; + + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.startElementNs(%s", (char *) localname); + if (prefix == NULL) + fprintf(stdout, ", NULL"); + else + fprintf(stdout, ", %s", (char *) prefix); + if (URI == NULL) + fprintf(stdout, ", NULL"); + else + fprintf(stdout, ", '%s'", (char *) URI); + fprintf(stdout, ", %d", nb_namespaces); + + if (namespaces != NULL) { + for (i = 0;i < nb_namespaces * 2;i++) { + fprintf(stdout, ", xmlns"); + if (namespaces[i] != NULL) + fprintf(stdout, ":%s", namespaces[i]); + i++; + fprintf(stdout, "='%s'", namespaces[i]); + } + } + fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted); + if (attributes != NULL) { + for (i = 0;i < nb_attributes * 5;i += 5) { + if (attributes[i + 1] != NULL) + fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]); + else + fprintf(stdout, ", %s='", attributes[i]); + fprintf(stdout, "%.4s...', %d", attributes[i + 3], + (int)(attributes[i + 4] - attributes[i + 3])); + } + } + 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 +endElementNsDebug(void *ctx ATTRIBUTE_UNUSED, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.endElementNs(%s", (char *) localname); + if (prefix == NULL) + fprintf(stdout, ", NULL"); + else + fprintf(stdout, ", %s", (char *) prefix); + if (URI == NULL) + fprintf(stdout, ", NULL)\n"); + else + fprintf(stdout, ", '%s')\n", (char *) URI); +} + +static xmlSAXHandler debugSAX2HandlerStruct = { + internalSubsetDebug, + isStandaloneDebug, + hasInternalSubsetDebug, + hasExternalSubsetDebug, + resolveEntityDebug, + getEntityDebug, + entityDeclDebug, + notationDeclDebug, + attributeDeclDebug, + elementDeclDebug, + unparsedEntityDeclDebug, + setDocumentLocatorDebug, + startDocumentDebug, + endDocumentDebug, + NULL, + NULL, + referenceDebug, + charactersDebug, + ignorableWhitespaceDebug, + processingInstructionDebug, + commentDebug, + warningDebug, + errorDebug, + fatalErrorDebug, + getParameterEntityDebug, + cdataBlockDebug, + externalSubsetDebug, + XML_SAX2_MAGIC, + NULL, + startElementNsDebug, + endElementNsDebug, + NULL +}; + +static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct; + +static void +testSAX(const char *filename) { + xmlSAXHandlerPtr handler; + const char *user_data = "user_data"; /* mostly for debugging */ + + callbacks = 0; + + if (noout) { + handler = emptySAXHandler; +#ifdef LIBXML_SAX1_ENABLED + } else if (options & XML_PARSE_SAX1) { + handler = debugSAXHandler; +#endif + } else { + handler = debugSAX2Handler; + } + +#ifdef LIBXML_SCHEMAS_ENABLED + if (wxschemas != NULL) { + int ret; + xmlSchemaValidCtxtPtr vctxt; + xmlParserInputBufferPtr buf; + + if (strcmp(filename, "-") == 0) + buf = xmlParserInputBufferCreateFd(STDIN_FILENO, + XML_CHAR_ENCODING_NONE); + else + buf = xmlParserInputBufferCreateFilename(filename, + XML_CHAR_ENCODING_NONE); + if (buf == NULL) + return; + + vctxt = xmlSchemaNewValidCtxt(wxschemas); + if (vctxt == NULL) { + progresult = XMLLINT_ERR_MEM; + xmlFreeParserInputBuffer(buf); + return; + } + xmlSchemaValidateSetFilename(vctxt, filename); + + ret = xmlSchemaValidateStream(vctxt, buf, 0, handler, + (void *)user_data); + if (repeat == 0) { + 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(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, + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n"); + fprintf(ERR_STREAM, + "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"); + fprintf(ERR_STREAM, + "<html><head><title>%s output</title></head>\n", + argv[0]); + fprintf(ERR_STREAM, + "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\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, "</body></html>\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 892d50c306dc3b94120107ea4c334ceb7d0672aa..f0628e2a83a7e623a81a91a621c4b671bceb3423 100644 --- a/xmlmemory.c +++ b/xmlmemory.c @@ -12,32 +12,17 @@ #include <ctype.h> #include <time.h> -/* #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 <libxml/globals.h> /* must come before xmlmemory.h */ #include <libxml/xmlmemory.h> #include <libxml/xmlerror.h> +#include <libxml/parser.h> #include <libxml/threads.h> -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 44eba066977b527a0b14a0424b375257a9fefd2f..dd2fd7a53932674a846a2f96c83ed9fe0253660f 100644 --- a/xmlmodule.c +++ b/xmlmodule.c @@ -17,10 +17,12 @@ #include "libxml.h" #include <string.h> +#include <libxml/xmlmodule.h> #include <libxml/xmlmemory.h> #include <libxml/xmlerror.h> -#include <libxml/xmlmodule.h> -#include <libxml/globals.h> +#include <libxml/xmlstring.h> + +#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 <kernel/image.h> - -/* - * 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 <os2.h> - -/* - * 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 b3299cedfccebb74c9a57f3e5a6e093b99376df5..3528d7d8f0c179d401c4a454a43c1a290ddae0c1 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -39,9 +39,13 @@ #include <libxml/pattern.h> #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 <string.h> - #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list)) - #endif - #endif + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) #endif #endif -/* #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 a2a36c499183064621457d8d6175aa5722214840..31e3d1a6229df16d91b98ad869a3ae63ac561b26 100644 --- a/xmlregexp.c +++ b/xmlregexp.c @@ -19,8 +19,6 @@ #ifdef LIBXML_REGEXP_ENABLED -/* #define DEBUG_ERR */ - #include <stdio.h> #include <string.h> #include <limits.h> @@ -31,15 +29,13 @@ #include <libxml/xmlautomata.h> #include <libxml/xmlunicode.h> +#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 9b42c66cac9a562e1c5f50c04b535c537ff70aa0..16b71d0a50aeb32c6c684111cd9512d13932bf7c 100644 --- a/xmlsave.c +++ b/xmlsave.c @@ -9,6 +9,8 @@ #define IN_LIBXML #include "libxml.h" +#include <limits.h> +#include <stdlib.h> #include <string.h> #include <libxml/xmlmemory.h> #include <libxml/parserInternals.h> @@ -19,61 +21,15 @@ #include <libxml/HTMLtree.h> -#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, "<!NOTATION "); + xmlOutputBufferWriteString(buf, (const char *) nota->name); + + if (nota->PublicID != NULL) { + xmlOutputBufferWrite(buf, 8, " PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, nota->PublicID); + if (nota->SystemID != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + } else { + xmlOutputBufferWrite(buf, 8, " SYSTEM "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + + xmlOutputBufferWrite(buf, 3, " >\n"); +} + +/** + * xmlBufDumpNotationDeclScan: + * @nota: A notation declaration + * @buf: the XML buffer output + * + * This is called with the hash scan function, and just reverses args + */ +static void +xmlBufDumpNotationDeclScan(void *nota, void *buf, + const xmlChar *name ATTRIBUTE_UNUSED) { + xmlBufDumpNotationDecl((xmlOutputBufferPtr) buf, (xmlNotationPtr) nota); +} + /** * xmlBufDumpNotationTable: * @buf: an xmlBufPtr output @@ -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, "<!ELEMENT "); + if (elem->prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) elem->prefix); + xmlOutputBufferWrite(buf, 1, ":"); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpElementDecl(buffer, elem); - xmlBufMergeBuffer(buf, buffer); + xmlOutputBufferWriteString(buf, (const char *) elem->name); + xmlOutputBufferWrite(buf, 1, " "); + + switch (elem->etype) { + case XML_ELEMENT_TYPE_EMPTY: + xmlOutputBufferWrite(buf, 5, "EMPTY"); + break; + case XML_ELEMENT_TYPE_ANY: + xmlOutputBufferWrite(buf, 3, "ANY"); + break; + case XML_ELEMENT_TYPE_MIXED: + case XML_ELEMENT_TYPE_ELEMENT: + xmlBufDumpElementContent(buf, elem->content); + break; + default: + /* assert(0); */ + break; + } + + xmlOutputBufferWrite(buf, 2, ">\n"); } +/** + * xmlBufDumpEnumeration: + * @buf: output buffer + * @enum: An enumeration + * + * This will dump the content of the enumeration + */ +static void +xmlBufDumpEnumeration(xmlOutputBufferPtr buf, xmlEnumerationPtr cur) { + while (cur != NULL) { + xmlOutputBufferWriteString(buf, (const char *) cur->name); + if (cur->next != NULL) + xmlOutputBufferWrite(buf, 3, " | "); + + cur = cur->next; + } + + xmlOutputBufferWrite(buf, 1, ")"); +} /** * xmlBufDumpAttributeDecl: - * @buf: an xmlBufPtr output + * @buf: output buffer * @attr: An attribute declaration * * This will dump the content of the attribute declaration as an XML * DTD definition */ -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, "<!ATTLIST "); + xmlOutputBufferWriteString(buf, (const char *) attr->elem); + xmlOutputBufferWrite(buf, 1, " "); + if (attr->prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) attr->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *) attr->name); + + switch (attr->atype) { + case XML_ATTRIBUTE_CDATA: + xmlOutputBufferWrite(buf, 6, " CDATA"); + break; + case XML_ATTRIBUTE_ID: + xmlOutputBufferWrite(buf, 3, " ID"); + break; + case XML_ATTRIBUTE_IDREF: + xmlOutputBufferWrite(buf, 6, " IDREF"); + break; + case XML_ATTRIBUTE_IDREFS: + xmlOutputBufferWrite(buf, 7, " IDREFS"); + break; + case XML_ATTRIBUTE_ENTITY: + xmlOutputBufferWrite(buf, 7, " ENTITY"); + break; + case XML_ATTRIBUTE_ENTITIES: + xmlOutputBufferWrite(buf, 9, " ENTITIES"); + break; + case XML_ATTRIBUTE_NMTOKEN: + xmlOutputBufferWrite(buf, 8, " NMTOKEN"); + break; + case XML_ATTRIBUTE_NMTOKENS: + xmlOutputBufferWrite(buf, 9, " NMTOKENS"); + break; + case XML_ATTRIBUTE_ENUMERATION: + xmlOutputBufferWrite(buf, 2, " ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + case XML_ATTRIBUTE_NOTATION: + xmlOutputBufferWrite(buf, 11, " NOTATION ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + default: + /* assert(0); */ + break; + } + + switch (attr->def) { + case XML_ATTRIBUTE_NONE: + break; + case XML_ATTRIBUTE_REQUIRED: + xmlOutputBufferWrite(buf, 10, " #REQUIRED"); + break; + case XML_ATTRIBUTE_IMPLIED: + xmlOutputBufferWrite(buf, 9, " #IMPLIED"); + break; + case XML_ATTRIBUTE_FIXED: + xmlOutputBufferWrite(buf, 7, " #FIXED"); + break; + default: + /* assert(0); */ + break; + } + + if (attr->defaultValue != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, attr->defaultValue); + } + + xmlOutputBufferWrite(buf, 2, ">\n"); +} + +/** + * xmlBufDumpEntityContent: + * @buf: output buffer + * @content: entity content. + * + * This will dump the quoted string value, taking care of the special + * treatment required by % + */ +static void +xmlBufDumpEntityContent(xmlOutputBufferPtr buf, const xmlChar *content) { + if (xmlStrchr(content, '%')) { + const char * base, *cur; + + xmlOutputBufferWrite(buf, 1, "\""); + base = cur = (const char *) content; + while (*cur != 0) { + if (*cur == '"') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } else if (*cur == '%') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, "%"); + cur++; + base = cur; + } else { + cur++; + } + } + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 1, "\""); + } else { + xmlOutputBufferWriteQuotedString(buf, content); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpAttributeDecl(buffer, attr); - xmlBufMergeBuffer(buf, buffer); } /** @@ -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, "<!ENTITY % "); + else + xmlOutputBufferWrite(buf, 9, "<!ENTITY "); + xmlOutputBufferWriteString(buf, (const char *) ent->name); + xmlOutputBufferWrite(buf, 1, " "); + + if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + if (ent->ExternalID != NULL) { + xmlOutputBufferWrite(buf, 7, "PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, ent->ExternalID); + xmlOutputBufferWrite(buf, 1, " "); + } else { + xmlOutputBufferWrite(buf, 7, "SYSTEM "); + } + xmlOutputBufferWriteQuotedString(buf, ent->SystemID); } - 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, "<?xml version="); if (cur->version != NULL) - xmlBufWriteQuotedString(buf->buffer, cur->version); + xmlOutputBufferWriteQuotedString(buf, cur->version); else xmlOutputBufferWrite(buf, 5, "\"1.0\""); if (encoding != NULL) { xmlOutputBufferWrite(buf, 10, " encoding="); - xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding); + xmlOutputBufferWriteQuotedString(buf, (xmlChar *) encoding); } switch (cur->standalone) { case 0: @@ -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 f31d3d1f618f7f8419f2d38fb5270000f3fe53a3..48b4e328ab83df28d0a94ba2050d5c32e63120a2 100644 --- a/xmlschemas.c +++ b/xmlschemas.c @@ -76,28 +76,11 @@ #include <libxml/xmlreader.h> #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 26c033d411dede163b3272307309f3af8feba712..5c6db292725da5a3b8a04ab90accabb511dd89dc 100644 --- a/xmlschemastypes.c +++ b/xmlschemastypes.c @@ -17,6 +17,7 @@ #ifdef LIBXML_SCHEMAS_ENABLED +#include <stdlib.h> #include <string.h> #include <math.h> #include <float.h> @@ -25,15 +26,15 @@ #include <libxml/parser.h> #include <libxml/parserInternals.h> #include <libxml/hash.h> -#include <libxml/valid.h> #include <libxml/xpath.h> #include <libxml/uri.h> +#include <string.h> #include <libxml/xmlschemas.h> #include <libxml/schemasInternals.h> #include <libxml/xmlschemastypes.h> -#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 46301c3b2b76650e87df2a759231bcac8ef046bd..258ecc92c3bfe2fec9ce195f9882e86ff1b055d1 100644 --- a/xmlstring.c +++ b/xmlstring.c @@ -23,6 +23,17 @@ #include <libxml/parserInternals.h> #include <libxml/xmlstring.h> +#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 85c19558d9db2a6c19d13f668843c9ca80c8230b..f648dc0520b388addc28d0fdc3b23681b9059f7a 100644 --- a/xmlwriter.c +++ b/xmlwriter.c @@ -11,43 +11,32 @@ #define IN_LIBXML #include "libxml.h" #include <string.h> +#include <stdarg.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> +#include <libxml/parserInternals.h> #include <libxml/uri.h> #include <libxml/HTMLtree.h> +#include <libxml/SAX2.h> #ifdef LIBXML_WRITER_ENABLED #include <libxml/xmlwriter.h> -#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 <string.h> - #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list)) - #endif - #endif + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) #endif #endif @@ -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 4a6f0e216e7e823397efaee21be5bbd760ead525..033de6219d8e14135e02bef55ed190e6f3fa633d 100644 --- a/xpath.c +++ b/xpath.c @@ -31,7 +31,6 @@ #include <libxml/xmlmemory.h> #include <libxml/tree.h> -#include <libxml/valid.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/parserInternals.h> @@ -44,21 +43,20 @@ #endif #include <libxml/xmlerror.h> #include <libxml/threads.h> -#include <libxml/globals.h> #ifdef LIBXML_PATTERN_ENABLED #include <libxml/pattern.h> #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;i<ns->nodeNr;i++) { str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); xmlXPathNumberFunction(ctxt, 1); + CHECK_ERROR0; 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 ba1e31e0d0b1df0353059660350691e9295cf541..87ea85bbf7034086264e41b0080e3c7a84c6b5ff 100644 --- a/xpointer.c +++ b/xpointer.c @@ -38,29 +38,14 @@ #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/xmlerror.h> -#include <libxml/globals.h> #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 <libxml/debugXML.h> -#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 b2350b9053609135cf6db1cde3d2a27342155160..9a106b90e2c31549618f5e730f91200eed44d9da 100644 --- a/xzlib.c +++ b/xzlib.c @@ -14,9 +14,6 @@ #include <stdlib.h> #include <errno.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -25,6 +22,8 @@ #endif #ifdef HAVE_UNISTD_H #include <unistd.h> +#elif defined (_WIN32) +#include <io.h> #endif #ifdef LIBXML_ZLIB_ENABLED #include <vtk_zlib.h> @@ -33,7 +32,7 @@ #include <lzma.h> #endif -#include "xzlib.h" +#include "private/xzlib.h" #include <libxml/xmlmemory.h> /* 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:%d>", 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) {