From f5e9a1ea6f6eb7e750ff09060937ea91012b8985 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Thu, 24 May 2007 11:13:06 -0700 Subject: [PATCH] msxml3: Add initial implementation of IXMLDocument. --- dlls/msxml3/Makefile.in | 1 + dlls/msxml3/factory.c | 10 +- dlls/msxml3/msxml_private.h | 1 + dlls/msxml3/xmldoc.c | 655 ++++++++++++++++++++++++++++++++++++ 4 files changed, 666 insertions(+), 1 deletion(-) create mode 100644 dlls/msxml3/xmldoc.c diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index 870034df9e8..ad5d9bc75e6 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -25,6 +25,7 @@ C_SRCS = \ schema.c \ text.c \ uuid.c \ + xmldoc.c \ xmlelem.c RC_SRCS = version.rc diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index ebc342f86f4..334906fd008 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -134,6 +134,7 @@ static const struct IClassFactoryVtbl xmlcf_vtbl = static xmlcf domdoccf = { &xmlcf_vtbl, DOMDocument_create }; static xmlcf schemacf = { &xmlcf_vtbl, SchemaCache_create }; +static xmlcf xmldoccf = { &xmlcf_vtbl, XMLDocument_create }; /****************************************************************** * DllGetClassObject (MSXML3.@) @@ -147,11 +148,18 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID iid, LPVOID *ppv ) if( IsEqualCLSID( rclsid, &CLSID_DOMDocument ) || /* Version indep. v 2.x */ IsEqualCLSID( rclsid, &CLSID_DOMDocument2 ) || /* Version indep. v 3.0 */ IsEqualCLSID( rclsid, &CLSID_DOMDocument30 ) ) /* Version dep. v 3.0 */ + { cf = (IClassFactory*) &domdoccf.lpVtbl; - + } else if( IsEqualCLSID( rclsid, &CLSID_XMLSchemaCache ) || IsEqualCLSID( rclsid, &CLSID_XMLSchemaCache30 ) ) + { cf = (IClassFactory*) &schemacf.lpVtbl; + } + else if( IsEqualCLSID( rclsid, &CLSID_XMLDocument ) ) + { + cf = (IClassFactory*) &xmldoccf.lpVtbl; + } if ( !cf ) return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 74f061a437d..3c6badb9348 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -63,6 +63,7 @@ extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, B LONG line, LONG linepos, LONG filepos ); extern HRESULT DOMDocument_create( IUnknown *pUnkOuter, LPVOID *ppObj ); extern HRESULT SchemaCache_create( IUnknown *pUnkOuter, LPVOID *ppObj ); +extern HRESULT XMLDocument_create( IUnknown *pUnkOuter, LPVOID *ppObj ); extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj ); extern HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj ); diff --git a/dlls/msxml3/xmldoc.c b/dlls/msxml3/xmldoc.c new file mode 100644 index 00000000000..e387921c55a --- /dev/null +++ b/dlls/msxml3/xmldoc.c @@ -0,0 +1,655 @@ +/* + * XML Document implementation + * + * Copyright 2007 James Hawkins + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "config.h" + +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "msxml2.h" +#include "wininet.h" +#include "winreg.h" +#include "shlwapi.h" +#include "ocidl.h" + +#include "wine/debug.h" + +#include "msxml_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msxml); + +#ifdef HAVE_LIBXML2 + +/* FIXME: IXMLDocument needs to implement + * - IXMLError + * - IPersistMoniker + * - IPersistStream + */ + +typedef struct _xmldoc +{ + const IXMLDocumentVtbl *lpVtbl; + const IPersistStreamInitVtbl *lpvtblIPersistStreamInit; + LONG ref; + HRESULT error; + + /* IXMLDocument */ + IXMLElement *root; + xmlDocPtr xmldoc; + + /* IPersistStream */ + IStream *stream; +} xmldoc; + +static inline xmldoc *impl_from_IXMLDocument(IXMLDocument *iface) +{ + return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpVtbl)); +} + +static inline xmldoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface) +{ + return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpvtblIPersistStreamInit)); +} + +static HRESULT WINAPI xmldoc_QueryInterface(IXMLDocument *iface, REFIID riid, void** ppvObject) +{ + xmldoc *This = impl_from_IXMLDocument(iface); + + TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IXMLDocument)) + { + *ppvObject = iface; + } + else if (IsEqualGUID(&IID_IPersistStreamInit, riid)) + { + *ppvObject = (IPersistStreamInit *)&(This->lpvtblIPersistStreamInit); + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IXMLDocument_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI xmldoc_AddRef(IXMLDocument *iface) +{ + xmldoc *This = impl_from_IXMLDocument(iface); + TRACE("%p\n", This); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI xmldoc_Release(IXMLDocument *iface) +{ + xmldoc *This = impl_from_IXMLDocument(iface); + LONG ref; + + TRACE("%p\n", This); + + ref = InterlockedDecrement(&This->ref); + if (ref == 0) + { + xmlFreeDoc(This->xmldoc); + if (This->stream) IStream_Release(This->stream); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI xmldoc_GetTypeInfoCount(IXMLDocument *iface, UINT* pctinfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_GetTypeInfo(IXMLDocument *iface, UINT iTInfo, + LCID lcid, ITypeInfo** ppTInfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_GetIDsOfNames(IXMLDocument *iface, REFIID riid, + LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgDispId) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_Invoke(IXMLDocument *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS* pDispParams, VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_root(IXMLDocument *iface, IXMLElement **p) +{ + xmldoc *This = impl_from_IXMLDocument(iface); + + TRACE("(%p, %p)\n", iface, p); + + if (!p) + return E_INVALIDARG; + + *p = This->root; + if (!*p) + return E_FAIL; + + return S_OK; +} + +static HRESULT WINAPI xmldoc_get_fileSize(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_put_fileModifiedDate(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_fileUpdatedDate(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_URL(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +typedef struct { + const struct IBindStatusCallbackVtbl *lpVtbl; +} bsc; + +static HRESULT WINAPI bsc_QueryInterface( + IBindStatusCallback *iface, + REFIID riid, + LPVOID *ppobj ) +{ + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IBindStatusCallback)) + { + IBindStatusCallback_AddRef( iface ); + *ppobj = iface; + return S_OK; + } + + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI bsc_AddRef( + IBindStatusCallback *iface ) +{ + return 2; +} + +static ULONG WINAPI bsc_Release( + IBindStatusCallback *iface ) +{ + return 1; +} + +static HRESULT WINAPI bsc_OnStartBinding( + IBindStatusCallback* iface, + DWORD dwReserved, + IBinding* pib) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_GetPriority( + IBindStatusCallback* iface, + LONG* pnPriority) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_OnLowResource( + IBindStatusCallback* iface, + DWORD reserved) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_OnProgress( + IBindStatusCallback* iface, + ULONG ulProgress, + ULONG ulProgressMax, + ULONG ulStatusCode, + LPCWSTR szStatusText) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_OnStopBinding( + IBindStatusCallback* iface, + HRESULT hresult, + LPCWSTR szError) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_GetBindInfo( + IBindStatusCallback* iface, + DWORD* grfBINDF, + BINDINFO* pbindinfo) +{ + *grfBINDF = BINDF_RESYNCHRONIZE; + + return S_OK; +} + +static HRESULT WINAPI bsc_OnDataAvailable( + IBindStatusCallback* iface, + DWORD grfBSCF, + DWORD dwSize, + FORMATETC* pformatetc, + STGMEDIUM* pstgmed) +{ + return S_OK; +} + +static HRESULT WINAPI bsc_OnObjectAvailable( + IBindStatusCallback* iface, + REFIID riid, + IUnknown* punk) +{ + return S_OK; +} + +static const struct IBindStatusCallbackVtbl bsc_vtbl = +{ + bsc_QueryInterface, + bsc_AddRef, + bsc_Release, + bsc_OnStartBinding, + bsc_GetPriority, + bsc_OnLowResource, + bsc_OnProgress, + bsc_OnStopBinding, + bsc_GetBindInfo, + bsc_OnDataAvailable, + bsc_OnObjectAvailable +}; + +static bsc xmldoc_bsc = { &bsc_vtbl }; + +static HRESULT WINAPI xmldoc_put_URL(IXMLDocument *iface, BSTR p) +{ + WCHAR url[INTERNET_MAX_URL_LENGTH]; + IStream *stream; + IBindCtx *bctx; + IMoniker *moniker; + IPersistStreamInit *persist; + HRESULT hr; + + TRACE("(%p, %s)\n", iface, debugstr_w(p)); + + if (!p) + return E_INVALIDARG; + + if (!PathIsURLW(p)) + { + WCHAR fullpath[MAX_PATH]; + DWORD needed = sizeof(url) / sizeof(WCHAR); + + if (!PathSearchAndQualifyW(p, fullpath, sizeof(fullpath) / sizeof(WCHAR))) + { + ERR("can't find path\n"); + return E_FAIL; + } + + if (FAILED(UrlCreateFromPathW(fullpath, url, &needed, 0))) + { + ERR("can't create url from path\n"); + return E_FAIL; + } + + p = url; + } + + hr = CreateURLMoniker(NULL, p, &moniker); + if (FAILED(hr)) + return hr; + + CreateAsyncBindCtx(0, (IBindStatusCallback *)&xmldoc_bsc, 0, &bctx); + + hr = IMoniker_BindToStorage(moniker, bctx, NULL, &IID_IStream, (LPVOID *)&stream); + IBindCtx_Release(bctx); + IMoniker_Release(moniker); + if (FAILED(hr)) + return hr; + + hr = IXMLDocument_QueryInterface(iface, &IID_IPersistStreamInit, (LPVOID *)&persist); + if (FAILED(hr)) + { + IStream_Release(stream); + return hr; + } + + hr = IPersistStreamInit_Load(persist, stream); + IPersistStreamInit_Release(persist); + IStream_Release(stream); + + return hr; +} + +static HRESULT WINAPI xmldoc_get_mimeType(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_readyState(IXMLDocument *iface, long *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_charset(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_put_charset(IXMLDocument *iface, BSTR p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_version(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_doctype(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_get_dtdURl(IXMLDocument *iface, BSTR *p) +{ + FIXME("(%p, %p): stub\n", iface, p); + return E_NOTIMPL; +} + +static xmlElementType type_msxml_to_libxml(long type) +{ + switch (type) + { + case XMLELEMTYPE_ELEMENT: + return XML_ELEMENT_NODE; + case XMLELEMTYPE_TEXT: + return XML_TEXT_NODE; + case XMLELEMTYPE_COMMENT: + return XML_COMMENT_NODE; + case XMLELEMTYPE_DOCUMENT: + return XML_DOCUMENT_NODE; + case XMLELEMTYPE_DTD: + return XML_DTD_NODE; + case XMLELEMTYPE_PI: + return XML_PI_NODE; + default: + break; + } + + return -1; /* FIXME: what is OTHER in msxml? */ +} + +static HRESULT WINAPI xmldoc_createElement(IXMLDocument *iface, VARIANT vType, + VARIANT var1, IXMLElement **ppElem) +{ + xmlNodePtr node; + static const xmlChar empty[] = "\0"; + + TRACE("(%p, %p)\n", iface, ppElem); + + if (!ppElem) + return E_INVALIDARG; + + *ppElem = NULL; + + node = xmlNewNode(NULL, empty); + + if (V_VT(&vType) != VT_I4) + return E_INVALIDARG; + + node->type = type_msxml_to_libxml(V_I4(&vType)); + + /* FIXME: create xmlNodePtr based on vType and var1 */ + return XMLElement_create((IUnknown *)iface, node, (LPVOID *)ppElem); +} + +static const struct IXMLDocumentVtbl xmldoc_vtbl = +{ + xmldoc_QueryInterface, + xmldoc_AddRef, + xmldoc_Release, + xmldoc_GetTypeInfoCount, + xmldoc_GetTypeInfo, + xmldoc_GetIDsOfNames, + xmldoc_Invoke, + xmldoc_get_root, + xmldoc_get_fileSize, + xmldoc_put_fileModifiedDate, + xmldoc_get_fileUpdatedDate, + xmldoc_get_URL, + xmldoc_put_URL, + xmldoc_get_mimeType, + xmldoc_get_readyState, + xmldoc_get_charset, + xmldoc_put_charset, + xmldoc_get_version, + xmldoc_get_doctype, + xmldoc_get_dtdURl, + xmldoc_createElement +}; + +/************************************************************************ + * xmldoc implementation of IPersistStreamInit. + */ +static HRESULT WINAPI xmldoc_IPersistStreamInit_QueryInterface( + IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj) +{ + xmldoc *this = impl_from_IPersistStreamInit(iface); + return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj); +} + +static ULONG WINAPI xmldoc_IPersistStreamInit_AddRef( + IPersistStreamInit *iface) +{ + xmldoc *this = impl_from_IPersistStreamInit(iface); + return IXMLDocument_AddRef((IXMLDocument *)this); +} + +static ULONG WINAPI xmldoc_IPersistStreamInit_Release( + IPersistStreamInit *iface) +{ + xmldoc *this = impl_from_IPersistStreamInit(iface); + return IXMLDocument_Release((IXMLDocument *)this); +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_GetClassID( + IPersistStreamInit *iface, CLSID *classid) +{ + FIXME("(%p,%p): stub!\n", iface, classid); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_IsDirty( + IPersistStreamInit *iface) +{ + FIXME("(%p): stub!\n", iface); + return E_NOTIMPL; +} + +static xmlDocPtr parse_xml(char *ptr, int len) +{ +#ifdef HAVE_XMLREADMEMORY + return xmlReadMemory(ptr, len, NULL, NULL, + XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS); +#else + return xmlParseMemory(ptr, len); +#endif +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_Load( + IPersistStreamInit *iface, LPSTREAM pStm) +{ + xmldoc *This = impl_from_IPersistStreamInit(iface); + xmlNodePtr xmlnode; + HRESULT hr; + HGLOBAL hglobal; + DWORD read, written, len; + BYTE buf[4096]; + char *ptr; + + TRACE("(%p, %p)\n", iface, pStm); + + if (!pStm) + return E_INVALIDARG; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream); + if (FAILED(hr)) + return hr; + + do + { + IStream_Read(pStm, buf, sizeof(buf), &read); + hr = IStream_Write(This->stream, buf, read, &written); + } while(SUCCEEDED(hr) && written != 0 && read != 0); + + if (FAILED(hr)) + { + ERR("Failed to copy stream\n"); + return hr; + } + + hr = GetHGlobalFromStream(This->stream, &hglobal); + if (FAILED(hr)) + return hr; + + len = GlobalSize(hglobal); + ptr = GlobalLock(hglobal); + if (len != 0) + This->xmldoc = parse_xml(ptr, len); + GlobalUnlock(hglobal); + + if (!This->xmldoc) + { + ERR("Failed to parse xml\n"); + return E_FAIL; + } + + xmlnode = xmlDocGetRootElement(This->xmldoc); + return XMLElement_create((IUnknown *)This, xmlnode, (LPVOID *)&This->root); +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_Save( + IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty) +{ + FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_GetSizeMax( + IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize) +{ + FIXME("(%p, %p): stub!\n", iface, pcbSize); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmldoc_IPersistStreamInit_InitNew( + IPersistStreamInit *iface) +{ + FIXME("(%p): stub!\n", iface); + return E_NOTIMPL; +} + +static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable = +{ + xmldoc_IPersistStreamInit_QueryInterface, + xmldoc_IPersistStreamInit_AddRef, + xmldoc_IPersistStreamInit_Release, + xmldoc_IPersistStreamInit_GetClassID, + xmldoc_IPersistStreamInit_IsDirty, + xmldoc_IPersistStreamInit_Load, + xmldoc_IPersistStreamInit_Save, + xmldoc_IPersistStreamInit_GetSizeMax, + xmldoc_IPersistStreamInit_InitNew +}; + +HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj) +{ + xmldoc *doc; + + TRACE("(%p,%p)\n", pUnkOuter, ppObj); + + doc = HeapAlloc(GetProcessHeap(), 0, sizeof (*doc)); + if(!doc) + return E_OUTOFMEMORY; + + doc->lpVtbl = &xmldoc_vtbl; + doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable; + doc->ref = 1; + doc->error = S_OK; + doc->root = NULL; + doc->xmldoc = NULL; + doc->stream = NULL; + + *ppObj = &doc->lpVtbl; + + TRACE("returning iface %p\n", *ppObj); + return S_OK; +} + +#else + +HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj) +{ + MESSAGE("This program tried to use an XMLDocument object, but\n" + "libxml2 support was not present at compile time.\n"); + return E_NOTIMPL; +} + +#endif