From 199307251b3c0cbfdf8f58ae8112b8907b9af49e Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 27 May 2019 17:13:43 +0000 Subject: Windows platform: Provide a native XML parser implementation based on XmlLite [1]. Start using it by default if we weren't explicitly told to build with either libxml2 or expat. (This is a merge of the `xmllite` branch.) Doing so reduces the amount of dependencies required for building and using APR, which I believe to be a good thing in this particular case. And it also means that by default we would be relying on the native component of the OS rather than on a 3rd-party library. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1860150 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 + CMakeLists.txt | 44 +++- include/apr.hwc | 1 + xml/apr_xml_xmllite.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 679 insertions(+), 12 deletions(-) create mode 100644 xml/apr_xml_xmllite.c diff --git a/CHANGES b/CHANGES index 93fc4d4b0..f46f91924 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes for APR 2.0.0 + *) Windows platform: Use the native XML parser implementation (XmlLite) + by default instead of libxml2 and expat. [Ivan Zhakov] + *) Fix handle leak in the Win32 apr_uid_current implementation. PR 61165. [Ivan Zhakov] diff --git a/CMakeLists.txt b/CMakeLists.txt index ef29a7618..61eb436b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,16 +24,28 @@ FIND_PACKAGE(Expat) FIND_PACKAGE(LibXml2) FIND_PACKAGE(OpenSSL) -IF(NOT EXPAT_FOUND AND NOT LIBXML2_FOUND) - MESSAGE(FATAL_ERROR "Either Expat or LibXml2 is required, but neither was found") +IF(NOT APU_USE_EXPAT AND NOT APU_USE_LIBXML2 AND NOT APU_USE_XMLLITE) + IF(EXPAT_FOUND) + OPTION(APU_USE_EXPAT "Use Expat" ON) + OPTION(APU_USE_LIBXML2 "Use LibXml2" OFF) + OPTION(APU_USE_XMLLITE "Use XmlLite" OFF) + ELSEIF(LIBXML2_FOUND) + OPTION(APU_USE_EXPAT "Use Expat" OFF) + OPTION(APU_USE_LIBXML2 "Use LibXml2" ON) + OPTION(APU_USE_XMLLITE "Use XmlLite" OFF) + ELSE() + OPTION(APU_USE_EXPAT "Use Expat" OFF) + OPTION(APU_USE_LIBXML2 "Use LibXml2" OFF) + OPTION(APU_USE_XMLLITE "Use XmlLite" ON) + ENDIF() ENDIF() -IF(EXPAT_FOUND) - OPTION(APU_USE_EXPAT "Use Expat" ON) - OPTION(APU_USE_LIBXML2 "Use LibXml2" OFF) -ELSE() - OPTION(APU_USE_EXPAT "Use Expat" OFF) - OPTION(APU_USE_LIBXML2 "Use LibXml2" ON) +IF(APU_USE_EXPAT AND NOT EXPAT_FOUND) + MESSAGE(FATAL_ERROR "Expat not found") +ENDIF() + +IF(APU_USE_LIBXML2 AND NOT LIBXML2_FOUND) + MESSAGE(FATAL_ERROR "LibXml2 not found") ENDIF() OPTION(APR_INSTALL_PRIVATE_H "Install selected private .h files (for httpd)" OFF) @@ -50,8 +62,8 @@ SET(LIBXML2_ICONV_INCLUDE_DIR "" SET(LIBXML2_ICONV_LIBRARIES "" CACHE STRING "iconv libraries to link with for libxml2") -IF(NOT APU_USE_EXPAT AND NOT APU_USE_LIBXML2) - MESSAGE(FATAL_ERROR "Either Expat or LibXml2 must be selected") +IF(NOT APU_USE_EXPAT AND NOT APU_USE_LIBXML2 AND NOT APU_USE_XMLLITE) + MESSAGE(FATAL_ERROR "Either Expat or LibXml2 or XmlLite must be selected") ENDIF() IF(APU_USE_EXPAT AND APU_USE_LIBXML2) MESSAGE(FATAL_ERROR "Only one of Expat and LibXml2 can be selected") @@ -69,6 +81,7 @@ SET(apr_have_ipv6_10 0) SET(apu_have_crypto_10 0) SET(apu_use_libxml2_10 0) SET(apu_use_expat_10 0) +SET(apu_use_xmllite_10 0) IF(APR_HAVE_IPV6) SET(apr_have_ipv6_10 1) @@ -80,8 +93,10 @@ ENDIF() IF(APU_USE_EXPAT) SET(apu_use_expat_10 1) -ELSE() +ELSEIF(APU_USE_LIBXML2) SET(apu_use_libxml2_10 1) +ELSE(APU_USE_XMLLITE) + SET(apu_use_xmllite_10 1) ENDIF() IF("${MIN_WINDOWS_VER}" STREQUAL "") @@ -120,9 +135,12 @@ ADD_CUSTOM_TARGET( IF(APU_USE_EXPAT) SET(XMLLIB_INCLUDE_DIR ${EXPAT_INCLUDE_DIRS}) SET(XMLLIB_LIBRARIES ${EXPAT_LIBRARIES}) -ELSE() +ELSEIF(APU_USE_LIBXML2) SET(XMLLIB_INCLUDE_DIR "${LIBXML2_INCLUDE_DIR};${LIBXML2_ICONV_INCLUDE_DIR}") SET(XMLLIB_LIBRARIES "${LIBXML2_LIBRARIES};${LIBXML2_ICONV_LIBRARIES}") +ELSEIF(APU_USE_XMLLITE) + SET(XMLLIB_INCLUDE_DIR "") + SET(XMLLIB_LIBRARIES "xmllite.lib") ENDIF() # Generated .h files are stored in PROJECT_BINARY_DIR, not the @@ -354,6 +372,7 @@ SET(APR_SOURCES xml/apr_xml.c xml/apr_xml_expat.c xml/apr_xml_libxml2.c + xml/apr_xml_xmllite.c ) SET(APR_TEST_SOURCES @@ -634,6 +653,7 @@ MESSAGE(STATUS " IPv6 ............................ : ${APR_HAVE_IPV6}") MESSAGE(STATUS " DBD ODBC driver ................. : ${APU_HAVE_ODBC}") MESSAGE(STATUS " Use Expat ....................... : ${APU_USE_EXPAT}") MESSAGE(STATUS " Use LibXml2 ..................... : ${APU_USE_LIBXML2}") +MESSAGE(STATUS " Use XmlLite ..................... : ${APU_USE_XMLLITE}") MESSAGE(STATUS " Minimum Windows version ......... : ${MIN_WINDOWS_VER}") MESSAGE(STATUS " Library files for XML ........... : ${XMLLIB_LIBRARIES}") MESSAGE(STATUS " Build test suite ................ : ${APR_BUILD_TESTAPR}") diff --git a/include/apr.hwc b/include/apr.hwc index 6f242a0ed..1ced0d11f 100644 --- a/include/apr.hwc +++ b/include/apr.hwc @@ -686,6 +686,7 @@ typedef int apr_wait_t; #define APU_USE_EXPAT @apu_use_expat_10@ #define APU_USE_LIBXML2 @apu_use_libxml2_10@ +#define APU_USE_XMLLITE @apu_use_xmllite_10@ /** @} */ diff --git a/xml/apr_xml_xmllite.c b/xml/apr_xml_xmllite.c new file mode 100644 index 000000000..883081894 --- /dev/null +++ b/xml/apr_xml_xmllite.c @@ -0,0 +1,643 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_arch_utf8.h" + +#if APU_USE_XMLLITE +#include "apr_xml.h" + +typedef struct xmllite_parser_s* XML_Parser; +typedef int XML_Error; + +#include "apr_xml_internal.h" + +#define CINTERFACE +#define COBJMACROS +#define interface struct +typedef void * LPMSG; + +#include + +#include "apr_xml_internal.h" + +typedef struct xml_stream_t { + ISequentialStream sequental_stream; + ULONG refcount; + const char *data; + apr_size_t remaining; + int is_final; +} xml_stream_t; + +struct xmllite_parser_s +{ + IXmlReader *xml_reader; + xml_stream_t *input_stream; + apr_pool_t *iterpool; + apr_status_t (*current_state)(apr_xml_parser *parser, apr_pool_t *scratch_pool); + + void (*start_func)(void *userdata, const char *name, const char **attrs); + void (*end_func)(void *userdata, const char *name); + void (*cdata_func)(void *userdata, const char *data, int len); +}; + +static HRESULT STDMETHODCALLTYPE +stream_QueryInterface(ISequentialStream * This, REFIID riid, void **ppvObject) +{ + xml_stream_t *obj = CONTAINING_RECORD(This, xml_stream_t, sequental_stream); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_ISequentialStream)) + { + InterlockedIncrement(&obj->refcount); + *ppvObject = &obj->sequental_stream; + return S_OK; + } + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } +} + +static ULONG STDMETHODCALLTYPE +stream_AddRef(ISequentialStream * This) +{ + xml_stream_t *obj = CONTAINING_RECORD(This, xml_stream_t, sequental_stream); + return InterlockedIncrement(&obj->refcount); +} + +static ULONG STDMETHODCALLTYPE +stream_Release(ISequentialStream * This) +{ + xml_stream_t *obj = CONTAINING_RECORD(This, xml_stream_t, sequental_stream); + ULONG refcount = InterlockedDecrement(&obj->refcount); + + if (refcount == 0) { + free(obj); + } + + return refcount; +} + +static HRESULT STDMETHODCALLTYPE +stream_Read(ISequentialStream * This, + void *pv, + ULONG cb, + ULONG *pcbRead) +{ + xml_stream_t *obj = CONTAINING_RECORD(This, xml_stream_t, sequental_stream); + ULONG read = cb; + + if (read > obj->remaining) { + read = (ULONG) obj->remaining; + } + + memcpy(pv, obj->data, read); + obj->data += read; + obj->remaining -= read; + *pcbRead = read; + + if (read == cb) { + return S_OK; + } + else if (read < cb && !obj->is_final) { + return E_PENDING; + } + else + { + return S_FALSE; + } +} + +static HRESULT STDMETHODCALLTYPE +stream_Write(ISequentialStream * This, + const void *pv, + ULONG cb, + ULONG *pcbWritten) +{ + xml_stream_t *obj = CONTAINING_RECORD(This, xml_stream_t, sequental_stream); + + return E_NOTIMPL; +} + +static ISequentialStreamVtbl stream_vtable = +{ + stream_QueryInterface, + stream_AddRef, + stream_Release, + stream_Read, + stream_Write +}; + +static apr_status_t cleanup_xml_stream(void *ctx) +{ + xml_stream_t *xml_stream = ctx; + + ISequentialStream_Release(&xml_stream->sequental_stream); + + return APR_SUCCESS; +} + +static xml_stream_t *create_xml_stream(apr_pool_t *pool) +{ + xml_stream_t *xml_stream = malloc(sizeof(*xml_stream)); + if (xml_stream == NULL) { + return NULL; + } + + memset(xml_stream, 0, sizeof(*xml_stream)); + xml_stream->sequental_stream.lpVtbl = &stream_vtable; + xml_stream->refcount = 1; + + apr_pool_cleanup_register(pool, xml_stream, cleanup_xml_stream, + apr_pool_cleanup_null); + + return xml_stream; +} + +static apr_status_t cleanup_parser(void *ctx) +{ + apr_xml_parser *parser = ctx; + + if (parser->xp->xml_reader) { + IXmlReader_Release(parser->xp->xml_reader); + parser->xp->xml_reader = NULL; + } + + return APR_SUCCESS; +} + +static apr_status_t wstr2utf(const char **utf_p, apr_size_t *utf_len_p, + LPCWSTR wstr, apr_size_t wlen, + apr_pool_t *pool) +{ + apr_size_t result_len; + char *result; + + if (wlen > 0) { + apr_status_t status; + apr_size_t bufsize = wlen * 3; + apr_size_t outbytes = bufsize; + + result = apr_palloc(pool, outbytes + 1); + if (!result) { + return APR_ENOMEM; + } + + status = apr_conv_ucs2_to_utf8(wstr, &wlen, result, &outbytes); + if (status) { + return status; + } + + result_len = bufsize - outbytes; + result[result_len] = 0; + } + else { + result = ""; + result_len = 0; + } + + *utf_p = result; + if (utf_len_p) { + *utf_len_p = result_len; + } + + return APR_SUCCESS; +} + +static char * get_xmllite_errmsg(HRESULT hr) +{ + switch(hr) + { + case MX_E_INPUTEND: + return "unexpected end of input"; + case MX_E_ENCODING: + return "unrecognized encoding"; + case MX_E_ENCODINGSWITCH: + return "unable to switch the encoding"; + case MX_E_ENCODINGSIGNATURE: + return "unrecognized input signature"; + case WC_E_WHITESPACE: + return "whitespace expected"; + case WC_E_SEMICOLON: + return "semicolon expected"; + case WC_E_GREATERTHAN: + return "'>' expected"; + case WC_E_QUOTE: + return "quote expected"; + case WC_E_EQUAL: + return "equal expected"; + case WC_E_LESSTHAN: + return "well-formedness constraint: no '<' in attribute value"; + case WC_E_HEXDIGIT: + return "hexadecimal digit expected"; + case WC_E_DIGIT: + return "decimal digit expected"; + case WC_E_LEFTBRACKET: + return "'[' expected"; + case WC_E_LEFTPAREN: + return "'(' expected"; + case WC_E_XMLCHARACTER: + return "illegal xml character"; + case WC_E_NAMECHARACTER: + return "illegal name character"; + case WC_E_SYNTAX: + return "incorrect document syntax"; + case WC_E_CDSECT: + return "incorrect CDATA section syntax"; + case WC_E_COMMENT: + return "incorrect comment syntax"; + case WC_E_CONDSECT: + return "incorrect conditional section syntax"; + case WC_E_DECLATTLIST: + return "incorrect ATTLIST declaration syntax"; + case WC_E_DECLDOCTYPE: + return "incorrect DOCTYPE declaration syntax"; + case WC_E_DECLELEMENT: + return "incorrect ELEMENT declaration syntax"; + case WC_E_DECLENTITY: + return "incorrect ENTITY declaration syntax"; + case WC_E_DECLNOTATION: + return "incorrect NOTATION declaration syntax"; + case WC_E_NDATA: + return "NDATA expected"; + case WC_E_PUBLIC: + return "PUBLIC expected"; + case WC_E_SYSTEM: + return "SYSTEM expected"; + case WC_E_NAME: + return "name expected"; + case WC_E_ROOTELEMENT: + return "one root element"; + case WC_E_ELEMENTMATCH: + return "well-formedness constraint: element type match"; + case WC_E_UNIQUEATTRIBUTE: + return "well-formedness constraint: unique attribute spec"; + case WC_E_TEXTXMLDECL: + return "text/xmldecl not at the beginning of input"; + case WC_E_LEADINGXML: + return "leading \"xml\""; + case WC_E_TEXTDECL: + return "incorrect text declaration syntax"; + case WC_E_XMLDECL: + return "incorrect xml declaration syntax"; + case WC_E_ENCNAME: + return "incorrect encoding name syntax"; + case WC_E_PUBLICID: + return "incorrect public identifier syntax"; + case WC_E_PESINTERNALSUBSET: + return "well-formedness constraint: pes in internal subset"; + case WC_E_PESBETWEENDECLS: + return "well-formedness constraint: pes between declarations"; + case WC_E_NORECURSION: + return "well-formedness constraint: no recursion"; + case WC_E_ENTITYCONTENT: + return "entity content not well formed"; + case WC_E_UNDECLAREDENTITY: + return "well-formedness constraint: undeclared entity"; + case WC_E_PARSEDENTITY: + return "well-formedness constraint: parsed entity"; + case WC_E_NOEXTERNALENTITYREF: + return "well-formedness constraint: no external entity references"; + case WC_E_PI: + return "incorrect processing instruction syntax"; + case WC_E_SYSTEMID: + return "incorrect system identifier syntax"; + case WC_E_QUESTIONMARK: + return "'?' expected"; + case WC_E_CDSECTEND: + return "no ']]>' in element content"; + case WC_E_MOREDATA: + return "not all chunks of value have been read"; + case WC_E_DTDPROHIBITED: + return "DTD was found but is prohibited"; + case WC_E_INVALIDXMLSPACE: + return "xml:space attribute with invalid value"; + case NC_E_QNAMECHARACTER: + return "illegal qualified name character"; + case NC_E_QNAMECOLON: + return "multiple colons in qualified name"; + case NC_E_NAMECOLON: + return "colon in name"; + case NC_E_DECLAREDPREFIX: + return "declared prefix"; + case NC_E_UNDECLAREDPREFIX: + return "undeclared prefix"; + case NC_E_EMPTYURI: + return "non default namespace with empty uri"; + case NC_E_XMLPREFIXRESERVED: + return "\"xml\" prefix is reserved and must have the " + "http://www.w3.org/XML/1998/namespace URI"; + case NC_E_XMLNSPREFIXRESERVED: + return "\"xmlns\" prefix is reserved for use by XML"; + case NC_E_XMLURIRESERVED: + return "xml namespace URI (http://www.w3.org/XML/1998/namespace) must " + "be assigned only to prefix \"xml\""; + case NC_E_XMLNSURIRESERVED: + return "xmlns namespace URI (http://www.w3.org/2000/xmlns/) is " + "reserved and must not be used"; + case SC_E_MAXELEMENTDEPTH: + return "element depth exceeds limit"; + case SC_E_MAXENTITYEXPANSION: + return "entity expansion exceeds limit"; + case XML_E_INVALID_DECIMAL: + return "character in character entity is not a decimal digit " + "as was expected."; + case XML_E_INVALID_HEXIDECIMAL: + return "character in character entity is not a hexadecimal " + "digit as was expected."; + case XML_E_INVALID_UNICODE: + return "character entity has invalid Unicode value."; + default: + return ""; + } +} + +static apr_status_t handle_xmllite_err(apr_xml_parser *parser, HRESULT hr) +{ + parser->xp_err = hr; + + parser->xp_msg = get_xmllite_errmsg(hr); + /* this misnomer is used as a test for (any) parser error. */ + parser->error = APR_XML_ERROR_EXPAT; + + return APR_EGENERAL; +} + +static apr_status_t +cdata_state(apr_xml_parser *parser, + apr_pool_t *scratch_pool); + +static apr_status_t +read_state(apr_xml_parser *parser, + apr_pool_t *scratch_pool) +{ + HRESULT hr; + XmlNodeType node_type; + apr_status_t status; + + hr = IXmlReader_Read(parser->xp->xml_reader, &node_type); + if (hr == E_PENDING) { + return APR_EAGAIN; + } + else if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + if (node_type == XmlNodeType_Element) { + LPCWSTR wname; + UINT wname_len; + ULONG attr_count; + char **attrs; + const char* elem_name; + + hr = IXmlReader_GetQualifiedName(parser->xp->xml_reader, + &wname, &wname_len); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + status = wstr2utf(&elem_name, NULL, wname, wname_len, scratch_pool); + if (status) { + return status; + } + + hr = IXmlReader_GetAttributeCount(parser->xp->xml_reader, &attr_count); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + if (attr_count > 0) { + ULONG i; + + attrs = apr_palloc(parser->p, sizeof(char*) * (attr_count + 1) * 2); + + hr = IXmlReader_MoveToFirstAttribute(parser->xp->xml_reader); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + for (i = 0; i < attr_count; i++) { + hr = IXmlReader_GetQualifiedName(parser->xp->xml_reader, + &wname, &wname_len); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + status = wstr2utf(&attrs[i * 2], NULL, wname, wname_len, + scratch_pool); + if (status) { + return status; + } + + hr = IXmlReader_GetValue(parser->xp->xml_reader, + &wname, &wname_len); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + status = wstr2utf(&attrs[i * 2 + 1], NULL, wname, wname_len, + scratch_pool); + if (status) { + return status; + } + + hr = IXmlReader_MoveToNextAttribute(parser->xp->xml_reader); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + } + + attrs[i * 2] = NULL; + attrs[i * 2 + 1] = NULL; + + hr = IXmlReader_MoveToElement(parser->xp->xml_reader); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + } + else { + static char* no_attrs[] = { NULL, NULL }; + attrs = no_attrs; + } + + parser->xp->start_func(parser, elem_name, attrs); + + if (IXmlReader_IsEmptyElement(parser->xp->xml_reader)) { + parser->xp->end_func(parser, elem_name); + } + } + else if (node_type == XmlNodeType_EndElement) { + LPCWSTR wname; + UINT wname_len; + const char *elem_name; + + hr = IXmlReader_GetQualifiedName(parser->xp->xml_reader, + &wname, &wname_len); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + status = wstr2utf(&elem_name, NULL, wname, wname_len, scratch_pool); + if (status) { + return status; + } + + parser->xp->end_func(parser, elem_name); + } + else if (node_type == XmlNodeType_CDATA || + node_type == XmlNodeType_Text) { + parser->xp->current_state = cdata_state; + } + else if (node_type == XmlNodeType_Whitespace) { + UINT depth; + hr = IXmlReader_GetDepth(parser->xp->xml_reader, &depth); + if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + /* Report whitespaces as cdata (the same as Expat does), but + ignore them when depth == 0. */ + if (depth > 0) { + parser->xp->current_state = cdata_state; + } + } + else if (node_type == XmlNodeType_None) + { + return APR_EOF; + } + + return APR_SUCCESS; +} + +static apr_status_t +cdata_state(apr_xml_parser *parser, + apr_pool_t *scratch_pool) +{ + HRESULT hr; + apr_status_t status; + WCHAR buf[4000]; + UINT read_count; + + hr = IXmlReader_ReadValueChunk(parser->xp->xml_reader, buf, + sizeof(buf) / sizeof(buf[0]), + &read_count); + if (hr == E_PENDING) { + return APR_EAGAIN; + } + else if (FAILED(hr)) { + return handle_xmllite_err(parser, hr); + } + + if (read_count > 0) { + const char *cdata; + apr_size_t cdata_len; + + status = wstr2utf(&cdata, &cdata_len, buf, read_count, scratch_pool); + if (status) { + return status; + } + + parser->xp->cdata_func(parser, cdata, (int) cdata_len); + } + + if (hr == S_FALSE) { + parser->xp->current_state = read_state; + } + + return APR_SUCCESS; +} + + +static apr_status_t do_parse(apr_xml_parser *parser, + const char *data, apr_size_t len, + int is_final) +{ + apr_status_t status; + apr_pool_t *iterpool = parser->xp->iterpool; + + parser->xp->input_stream->data = data; + parser->xp->input_stream->remaining = len; + parser->xp->input_stream->is_final = is_final; + + while (TRUE) { + apr_pool_clear(iterpool); + + status = parser->xp->current_state(parser, iterpool); + if (status != APR_SUCCESS) { + break; + } + } + + if (status == APR_EAGAIN || status == APR_EOF) { + status = APR_SUCCESS; + } + + return status; +} + +static XMLParserImpl xml_parser_xmllite = { + do_parse, + cleanup_parser +}; + +XMLParserImpl* apr_xml_get_parser_impl(void) { return &xml_parser_xmllite; } +static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' }; + +apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t *pool, + void *start_func, + void *end_func, + void *cdata_func) +{ + apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser)); + HRESULT hr; + + parser->impl = apr_xml_get_parser_impl(); + parser->p = pool; + parser->doc = apr_pcalloc(pool, sizeof(*parser->doc)); + parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *)); + + /* ### is there a way to avoid hard-coding this? */ + apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV); + parser->xp = apr_pcalloc(pool, sizeof(struct xmllite_parser_s)); + parser->xp->current_state = read_state; + parser->xp->start_func = start_func; + parser->xp->end_func = end_func; + parser->xp->cdata_func = cdata_func; + apr_pool_create(&parser->xp->iterpool, pool); + + parser->xp->input_stream = create_xml_stream(pool); + if (parser->xp->input_stream == NULL) { + (*apr_pool_abort_get(pool))(APR_ENOMEM); + return NULL; + } + + hr = CreateXmlReader(&IID_IXmlReader, &parser->xp->xml_reader, NULL); + if (FAILED(hr)) { + return NULL; + } + apr_pool_cleanup_register(pool, parser, cleanup_parser, apr_pool_cleanup_null); + + hr = IXmlReader_SetInput(parser->xp->xml_reader, + (IUnknown*) &parser->xp->input_stream->sequental_stream); + if (FAILED(hr)) { + return NULL; + } + + return parser; +} +#endif -- cgit v1.2.1