diff --git a/dlls/msxml3/main.c b/dlls/msxml3/main.c
index 358a5cb3af..c31a53a887 100644
--- a/dlls/msxml3/main.c
+++ b/dlls/msxml3/main.c
@@ -32,6 +32,7 @@
#include "msxml.h"
#include "msxml2.h"
+#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/library.h"
@@ -39,6 +40,68 @@
WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+#ifdef HAVE_LIBXML2
+
+/* Support for loading xml files from a Wine Windows drive */
+static int wineXmlMatchCallback (char const * filename)
+{
+ int nRet = 0;
+
+ TRACE("%s\n", filename);
+
+ /*
+ * We will deal with loading XML files from the file system
+ * We only care about files that linux cannot find.
+ * e.g. C:,D: etc
+ */
+ if(isalpha(filename[0]) && filename[1] == ':')
+ nRet = 1;
+
+ return nRet;
+}
+
+static void *wineXmlOpenCallback (char const * filename)
+{
+ BSTR sFilename = bstr_from_xmlChar( (xmlChar*)filename);
+ HANDLE hFile;
+
+ TRACE("%s\n", debugstr_w(sFilename));
+
+ hFile = CreateFileW(sFilename, GENERIC_READ,FILE_SHARE_READ, NULL,
+ OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
+ if(hFile == INVALID_HANDLE_VALUE) hFile = 0;
+ SysFreeString(sFilename);
+ return hFile;
+}
+
+static int wineXmlReadCallback(void * context, char * buffer, int len)
+{
+ DWORD dwBytesRead;
+
+ TRACE("%p %s %d\n", context, buffer, len);
+
+ if ((context == NULL) || (buffer == NULL))
+ return(-1);
+
+ if(!ReadFile( context, buffer,len, &dwBytesRead, NULL))
+ {
+ ERR("Failed to read file\n");
+ return -1;
+ }
+
+ TRACE("Read %d\n", dwBytesRead);
+
+ return dwBytesRead;
+}
+
+static int wineXmlFileCloseCallback (void * context)
+{
+ return CloseHandle(context) ? 0 : -1;
+}
+
+#endif
+
+
HRESULT WINAPI DllCanUnloadNow(void)
{
FIXME("\n");
@@ -96,6 +159,12 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
for this thread and as default for new threads */
xmlTreeIndentString = "\t";
xmlThrDefTreeIndentString("\t");
+
+ /* Register callbacks for loading XML files */
+ if(xmlRegisterInputCallbacks(wineXmlMatchCallback, wineXmlOpenCallback,
+ wineXmlReadCallback, wineXmlFileCloseCallback) == -1)
+ WARN("Failed to register callbacks\n");
+
#endif
init_libxslt();
DisableThreadLibraryCalls(hInstDLL);
@@ -110,6 +179,10 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
}
#endif
#ifdef HAVE_LIBXML2
+ /* Restore default Callbacks */
+ xmlCleanupInputCallbacks();
+ xmlRegisterDefaultInputCallbacks();
+
xmlCleanupParser();
#endif
release_typelib();
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 0eddb38a22..2d831dd7fb 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -150,6 +150,37 @@ static const CHAR szTypeValueXML[] =
""
"Wine";
+static const CHAR szBasicTransformSSXMLPart1[] =
+""
+""
+"\n"
+""
+""
+""
+""
+"
"
+""
+""
+" | "
+""
+""
+" | "
+""
+"";
+
+static const CHAR szBasicTransformXML[] =
+"Wine$25.00";
+
+static const CHAR szBasicTransformOutput[] =
+"
";
+
static const WCHAR szNonExistentFile[] = {
'c', ':', '\\', 'N', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 'x', 'm', 'l', 0
};
@@ -3952,6 +3983,98 @@ static void test_NodeTypeValue(void)
free_bstrs();
}
+static void test_TransformWithLoadingLocalFile(void)
+{
+ IXMLDOMDocument2 *doc = NULL;
+ IXMLDOMDocument2 *xsl = NULL;
+ IXMLDOMNode *pNode;
+ VARIANT_BOOL bSucc;
+ HRESULT hr;
+ HANDLE file;
+ DWORD dwWritten;
+ char lpPathBuffer[MAX_PATH];
+ int i;
+
+ /* Create a Temp File. */
+ GetTempPathA(MAX_PATH, lpPathBuffer);
+ strcat(lpPathBuffer, "customers.xml" );
+
+ file = CreateFile(lpPathBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
+ if(file == INVALID_HANDLE_VALUE)
+ return;
+
+ WriteFile(file, szBasicTransformXML, strlen(szBasicTransformXML), &dwWritten, NULL);
+ CloseHandle(file);
+
+ /* Correct path to not include a escape character. */
+ for(i=0; i < strlen(lpPathBuffer); i++)
+ {
+ if(lpPathBuffer[i] == '\\')
+ lpPathBuffer[i] = '/';
+ }
+
+ hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc );
+ if( hr != S_OK )
+ return;
+
+ hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&xsl );
+ if( hr != S_OK )
+ {
+ IXMLDOMDocument2_Release(doc);
+ return;
+ }
+
+ hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szTypeValueXML), &bSucc);
+ ok(hr == S_OK, "ret %08x\n", hr );
+ ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n");
+ if(bSucc == VARIANT_TRUE)
+ {
+ BSTR sXSL;
+ BSTR sPart1 = _bstr_(szBasicTransformSSXMLPart1);
+ BSTR sPart2 = _bstr_(szBasicTransformSSXMLPart2);
+ BSTR sFileName = _bstr_(lpPathBuffer);
+ int nLegnth = lstrlenW(sPart1) + lstrlenW(sPart2) + lstrlenW(sFileName) + 1;
+
+ sXSL = SysAllocStringLen(NULL, nLegnth);
+ lstrcpyW(sXSL, sPart1);
+ lstrcatW(sXSL, sFileName);
+ lstrcatW(sXSL, sPart2);
+
+ hr = IXMLDOMDocument2_loadXML(xsl, sXSL, &bSucc);
+ ok(hr == S_OK, "ret %08x\n", hr );
+ ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n");
+ if(bSucc == VARIANT_TRUE)
+ {
+ BSTR sResult;
+
+ hr = IXMLDOMDocument_QueryInterface(xsl, &IID_IXMLDOMNode, (LPVOID*)&pNode );
+ ok(hr == S_OK, "ret %08x\n", hr );
+ if(hr == S_OK)
+ {
+ /* This will load the temp file via the XSL */
+ hr = IXMLDOMDocument2_transformNode(doc, pNode, &sResult);
+ ok(hr == S_OK, "ret %08x\n", hr );
+ if(hr == S_OK)
+ {
+ ok( compareIgnoreReturns( sResult, _bstr_(szBasicTransformOutput)), "Stylesheet output not correct\n");
+ SysFreeString(sResult);
+ }
+
+ IXMLDOMNode_Release(pNode);
+ }
+ }
+
+ SysFreeString(sXSL);
+ }
+
+ IXMLDOMDocument2_Release(doc);
+ IXMLDOMDocument2_Release(xsl);
+
+ DeleteFile(lpPathBuffer);
+ free_bstrs();
+}
+
START_TEST(domdoc)
{
HRESULT r;
@@ -3981,6 +4104,7 @@ START_TEST(domdoc)
test_Namespaces();
test_FormattingXML();
test_NodeTypeValue();
+ test_TransformWithLoadingLocalFile();
CoUninitialize();
}