From 92513a9edd0d4cab1583dee4f69366d90250ba67 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 23 Jan 2018 11:27:55 +0300 Subject: [PATCH] msxml3: Implement custom document importing callback. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/msxml3/domdoc.c | 1 + dlls/msxml3/main.c | 6 ++ dlls/msxml3/msxml_private.h | 12 ++- dlls/msxml3/node.c | 189 +++++++++++++++++++++++++++++++++++- 4 files changed, 204 insertions(+), 4 deletions(-) diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 87a167e46e0..ddd756582ba 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -2308,6 +2308,7 @@ static HRESULT WINAPI domdoc_load( This->error = E_FAIL; else { + get_doc(This)->name = (char *)xmlchar_from_wcharn(filename, -1, TRUE); This->properties->uri = uri; hr = This->error = S_OK; *isSuccessful = VARIANT_TRUE; diff --git a/dlls/msxml3/main.c b/dlls/msxml3/main.c index 1905f57be4f..311fd66e0ab 100644 --- a/dlls/msxml3/main.c +++ b/dlls/msxml3/main.c @@ -39,6 +39,7 @@ # include # include # include +# include # endif #endif @@ -176,6 +177,7 @@ DECL_FUNCPTR(xsltNextImport); DECL_FUNCPTR(xsltParseStylesheetDoc); DECL_FUNCPTR(xsltQuoteUserParams); DECL_FUNCPTR(xsltSaveResultTo); +DECL_FUNCPTR(xsltSetLoaderFunc); # undef DECL_FUNCPTR #endif @@ -202,10 +204,14 @@ static void init_libxslt(void) LOAD_FUNCPTR(xsltParseStylesheetDoc, 1); LOAD_FUNCPTR(xsltQuoteUserParams, 1); LOAD_FUNCPTR(xsltSaveResultTo, 1); + LOAD_FUNCPTR(xsltSetLoaderFunc, 1); #undef LOAD_FUNCPTR if (pxsltInit) pxsltInit(); + + pxsltSetLoaderFunc(xslt_doc_default_loader); + return; sym_not_found: diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 8d7833b0833..1c052152be2 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -379,6 +379,12 @@ extern BSTR EnsureCorrectEOL(BSTR) DECLSPEC_HIDDEN; extern xmlChar* tagName_to_XPath(const BSTR tagName) DECLSPEC_HIDDEN; +#ifdef SONAME_LIBXSLT +# include +extern xmlDocPtr xslt_doc_default_loader(const xmlChar *uri, xmlDictPtr dict, int options, + void *_ctxt, xsltLoadType type) DECLSPEC_HIDDEN; +#endif /* SONAME_LIBXSLT */ + static inline BSTR bstr_from_xmlChar(const xmlChar *str) { BSTR ret = NULL; @@ -395,12 +401,12 @@ static inline BSTR bstr_from_xmlChar(const xmlChar *str) return ret; } -static inline xmlChar *xmlchar_from_wcharn(const WCHAR *str, int nchars) +static inline xmlChar *xmlchar_from_wcharn(const WCHAR *str, int nchars, BOOL use_xml_alloc) { xmlChar *xmlstr; DWORD len = WideCharToMultiByte( CP_UTF8, 0, str, nchars, NULL, 0, NULL, NULL ); - xmlstr = heap_alloc( len+1 ); + xmlstr = use_xml_alloc ? xmlMalloc( len + 1 ) : heap_alloc( len + 1 ); if ( xmlstr ) { WideCharToMultiByte( CP_UTF8, 0, str, nchars, (LPSTR) xmlstr, len+1, NULL, NULL ); @@ -411,7 +417,7 @@ static inline xmlChar *xmlchar_from_wcharn(const WCHAR *str, int nchars) static inline xmlChar *xmlchar_from_wchar( const WCHAR *str ) { - return xmlchar_from_wcharn(str, -1); + return xmlchar_from_wcharn(str, -1, FALSE); } static inline xmlChar *heap_strdupxmlChar(const xmlChar *str) diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index ece82efa10e..bcb41813743 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -26,6 +26,7 @@ #ifdef HAVE_LIBXML2 # include +# include # include # include # ifdef SONAME_LIBXSLT @@ -39,6 +40,7 @@ # include # include # include +# include # endif #endif @@ -1313,7 +1315,192 @@ static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr return hr; } -#endif +struct import_buffer +{ + char *data; + int cur; + int len; +}; + +static int XMLCALL import_loader_io_read(void *context, char *out, int len) +{ + struct import_buffer *buffer = (struct import_buffer *)context; + + TRACE("%p, %p, %d\n", context, out, len); + + if (buffer->cur == buffer->len) + return 0; + + len = min(len, buffer->len - buffer->cur); + memcpy(out, &buffer->data[buffer->cur], len); + buffer->cur += len; + + TRACE("read %d\n", len); + + return len; +} + +static int XMLCALL import_loader_io_close(void * context) +{ + struct import_buffer *buffer = (struct import_buffer *)context; + + TRACE("%p\n", context); + + heap_free(buffer->data); + heap_free(buffer); + return 0; +} + +static HRESULT import_loader_onDataAvailable(void *ctxt, char *ptr, DWORD len) +{ + xmlParserInputPtr *input = (xmlParserInputPtr *)ctxt; + xmlParserInputBufferPtr inputbuffer; + struct import_buffer *buffer; + + buffer = heap_alloc(sizeof(*buffer)); + + buffer->data = heap_alloc(len); + memcpy(buffer->data, ptr, len); + buffer->cur = 0; + buffer->len = len; + + inputbuffer = xmlParserInputBufferCreateIO(import_loader_io_read, import_loader_io_close, buffer, + XML_CHAR_ENCODING_NONE); + *input = xmlNewIOInputStream(ctxt, inputbuffer, XML_CHAR_ENCODING_NONE); + if (!*input) + xmlFreeParserInputBuffer(inputbuffer); + + return *input ? S_OK : E_FAIL; +} + +static HRESULT xslt_doc_get_uri(const xmlChar *uri, void *_ctxt, xsltLoadType type, IUri **doc_uri) +{ + xsltStylesheetPtr style = (xsltStylesheetPtr)_ctxt; + IUri *href_uri; + HRESULT hr; + BSTR uriW; + + *doc_uri = NULL; + + uriW = bstr_from_xmlChar(uri); + hr = CreateUri(uriW, Uri_CREATE_ALLOW_RELATIVE | Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &href_uri); + SysFreeString(uriW); + if (FAILED(hr)) + { + WARN("Failed to create href uri, %#x.\n", hr); + return hr; + } + + if (type == XSLT_LOAD_STYLESHEET && style->doc && style->doc->name) + { + IUri *base_uri; + BSTR baseuriW; + + baseuriW = bstr_from_xmlChar((xmlChar *)style->doc->name); + hr = CreateUri(baseuriW, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &base_uri); + SysFreeString(baseuriW); + if (FAILED(hr)) + { + WARN("Failed to create base uri, %#x.\n", hr); + return hr; + } + + hr = CoInternetCombineIUri(base_uri, href_uri, 0, doc_uri, 0); + IUri_Release(base_uri); + if (FAILED(hr)) + WARN("Failed to combine uris, %#x.\n", hr); + } + else + { + *doc_uri = href_uri; + IUri_AddRef(*doc_uri); + } + + IUri_Release(href_uri); + + return hr; +} + +xmlDocPtr xslt_doc_default_loader(const xmlChar *uri, xmlDictPtr dict, int options, + void *_ctxt, xsltLoadType type) +{ + IUri *import_uri = NULL; + xmlParserInputPtr input; + xmlParserCtxtPtr pctxt; + xmlDocPtr doc = NULL; + IMoniker *moniker; + HRESULT hr; + bsc_t *bsc; + BSTR uriW; + + TRACE("%s, %p, %#x, %p, %d\n", debugstr_a((const char *)uri), dict, options, _ctxt, type); + + pctxt = xmlNewParserCtxt(); + if (!pctxt) + return NULL; + + if (dict && pctxt->dict) + { + xmlDictFree(pctxt->dict); + pctxt->dict = NULL; + } + + if (dict) + { + pctxt->dict = dict; + xmlDictReference(pctxt->dict); + } + + xmlCtxtUseOptions(pctxt, options); + + hr = xslt_doc_get_uri(uri, _ctxt, type, &import_uri); + if (FAILED(hr)) + goto failed; + + hr = CreateURLMonikerEx2(NULL, import_uri, &moniker, 0); + if (FAILED(hr)) + goto failed; + + hr = bind_url(moniker, import_loader_onDataAvailable, &input, &bsc); + IMoniker_Release(moniker); + if (FAILED(hr)) + goto failed; + + if (FAILED(detach_bsc(bsc))) + goto failed; + + if (!input) + goto failed; + + inputPush(pctxt, input); + xmlParseDocument(pctxt); + + if (pctxt->wellFormed) + { + doc = pctxt->myDoc; + /* Set imported uri, to give nested imports a chance. */ + if (IUri_GetPropertyBSTR(import_uri, Uri_PROPERTY_ABSOLUTE_URI, &uriW, 0) == S_OK) + { + doc->name = (char *)xmlchar_from_wcharn(uriW, SysStringLen(uriW), TRUE); + SysFreeString(uriW); + } + } + else + { + doc = NULL; + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } + +failed: + xmlFreeParserCtxt(pctxt); + if (import_uri) + IUri_Release(import_uri); + + return doc; +} + +#endif /* SONAME_LIBXSLT */ HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p, ISequentialStream *stream, const struct xslprocessor_params *params)