* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
+#include "precomp.h"
-#define COBJMACROS
-#define NONAMELESSUNION
-
-#include <config.h>
-
-//#include <stdarg.h>
#include <assert.h>
+
#ifdef HAVE_LIBXML2
-# include <libxml/parser.h>
-//# include <libxml/xmlerror.h>
# include <libxml/xpathInternals.h>
# include <libxml/xmlsave.h>
# include <libxml/SAX2.h>
# include <libxml/parserInternals.h>
#endif
-#include <windef.h>
-#include <winbase.h>
-//#include "winuser.h"
-//#include "winnls.h"
-#include <ole2.h>
#include <olectl.h>
-#include <msxml6.h>
-//#include "wininet.h"
-//#include "winreg.h"
-//#include "shlwapi.h"
-//#include "ocidl.h"
#include <objsafe.h>
-#include <wine/debug.h>
-#include <wine/list.h>
-
-#include "msxml_private.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msxml);
-
#ifdef HAVE_LIBXML2
/* not defined in older versions */
xmlChar const* selectNsStr;
LONG selectNsStr_len;
BOOL XPath;
+ WCHAR *url;
} domdoc_properties;
typedef struct ConnectionPoint ConnectionPoint;
VARIANT_BOOL validating;
VARIANT_BOOL resolving;
domdoc_properties* properties;
- bsc_t *bsc;
HRESULT error;
- /* IPersistStream */
- IStream *stream;
-
- /* IObjectWithSite*/
+ /* IObjectWithSite */
IUnknown *site;
/* IObjectSafety */
properties->version = version;
properties->XPath = (version == MSXML4 || version == MSXML6);
+ /* document url */
+ properties->url = NULL;
+
return properties;
}
list_add_tail(&pcopy->selectNsList, &new_ns->entry);
}
+ if (properties->url)
+ {
+ int len = strlenW(properties->url);
+
+ pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
+ memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
+ pcopy->url[len] = 0;
+ }
+ else
+ pcopy->url = NULL;
}
return pcopy;
IXMLDOMSchemaCollection2_Release(properties->schemaCache);
clear_selectNsList(&properties->selectNsList);
heap_free((xmlChar*)properties->selectNsStr);
+ CoTaskMemFree(properties->url);
heap_free(properties);
}
}
if (ctxt->node)
{
- /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
+ xmlChar cur = *(ctxt->input->cur);
+
+ /* Characters are reported with multiple calls, for example each charref is reported with a separate
+ call and then parser appends it to a single text node or creates a new node if not created.
+ It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
+ space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
+ or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
+ contains text node pointer if already created, trailing spaces are detected directly looking at parser input
+ for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
+ chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
+ a text node it's safe to ignore.
+
+ Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
+
if (!This->properties->preserving &&
!is_preserving_whitespace(ctxt->node) &&
- strn_isspace(ch, len))
+ strn_isspace(ch, len) &&
+ (!ctxt->node->last ||
+ ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
+ )))
return;
}
priv_from_xmlDocPtr(doc)->properties = create_properties(version);
}
-LONG xmldoc_add_ref(xmlDocPtr doc)
+LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
{
- LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
+ LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
TRACE("(%p)->(%d)\n", doc, ref);
return ref;
}
-LONG xmldoc_release(xmlDocPtr doc)
+LONG xmldoc_add_ref(xmlDocPtr doc)
+{
+ return xmldoc_add_refs(doc, 1);
+}
+
+LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
{
xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
- LONG ref = InterlockedDecrement(&priv->refs);
+ LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
TRACE("(%p)->(%d)\n", doc, ref);
- if(ref == 0)
+
+ if (ref < 0)
+ WARN("negative refcount, expect troubles\n");
+
+ if (ref == 0)
{
orphan_entry *orphan, *orphan2;
TRACE("freeing docptr %p\n", doc);
return ref;
}
+LONG xmldoc_release(xmlDocPtr doc)
+{
+ return xmldoc_release_refs(doc, 1);
+}
+
HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
{
xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
static inline xmlDocPtr get_doc( domdoc *This )
{
- return (xmlDocPtr)This->node.node;
+ return This->node.node->doc;
}
static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
return S_FALSE;
}
-static HRESULT WINAPI PersistStreamInit_Load(
- IPersistStreamInit *iface, LPSTREAM pStm)
+static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
{
- domdoc *This = impl_from_IPersistStreamInit(iface);
- HRESULT hr;
- HGLOBAL hglobal;
DWORD read, written, len;
+ xmlDocPtr xmldoc = NULL;
+ IStream *hstream;
+ HGLOBAL hglobal;
BYTE buf[4096];
+ HRESULT hr;
char *ptr;
- xmlDocPtr xmldoc = NULL;
-
- TRACE("(%p)->(%p)\n", This, pStm);
- if (!pStm)
- return E_INVALIDARG;
-
- hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
+ hstream = NULL;
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
if (FAILED(hr))
return hr;
do
{
- IStream_Read(pStm, buf, sizeof(buf), &read);
- hr = IStream_Write(This->stream, buf, read, &written);
+ ISequentialStream_Read(stream, buf, sizeof(buf), &read);
+ hr = IStream_Write(hstream, buf, read, &written);
} while(SUCCEEDED(hr) && written != 0 && read != 0);
if (FAILED(hr))
{
- ERR("Failed to copy stream\n");
+ ERR("failed to copy stream 0x%08x\n", hr);
+ IStream_Release(hstream);
return hr;
}
- hr = GetHGlobalFromStream(This->stream, &hglobal);
+ hr = GetHGlobalFromStream(hstream, &hglobal);
if (FAILED(hr))
return hr;
len = GlobalSize(hglobal);
ptr = GlobalLock(hglobal);
- if (len != 0)
- xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
+ if (len)
+ xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
GlobalUnlock(hglobal);
if (!xmldoc)
xmldoc->_private = create_priv();
- return attach_xmldoc(This, xmldoc);
+ return attach_xmldoc(doc, xmldoc);
+}
+
+static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
+{
+ domdoc *This = impl_from_IPersistStreamInit(iface);
+
+ TRACE("(%p)->(%p)\n", This, stream);
+
+ if (!stream)
+ return E_INVALIDARG;
+
+ return domdoc_load_from_stream(This, (ISequentialStream*)stream);
}
static HRESULT WINAPI PersistStreamInit_Save(
IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
{
domdoc *This = impl_from_IPersistStreamInit(iface);
- TRACE("(%p)->(%p): stub!\n", This, pcbSize);
+ TRACE("(%p)->(%p)\n", This, pcbSize);
return E_NOTIMPL;
}
IXMLDOMDocument_tid,
IXMLDOMDocument2_tid,
IXMLDOMDocument3_tid,
- 0
+ NULL_tid
};
static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
{
int eid;
- if(This->bsc)
- detach_bsc(This->bsc);
-
if (This->site)
IUnknown_Release( This->site );
destroy_xmlnode(&This->node);
- if (This->stream)
- IStream_Release(This->stream);
for (eid = 0; eid < EVENTID_LAST; eid++)
if (This->events[eid]) IDispatch_Release(This->events[eid]);
IXMLDOMNode** outNewChild )
{
domdoc *This = impl_from_IXMLDOMDocument3( iface );
+ DOMNodeType type;
+ HRESULT hr;
TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
- return node_insert_before(&This->node, newChild, &refChild, outNewChild);
-}
+ hr = IXMLDOMNode_get_nodeType(newChild, &type);
+ if (hr != S_OK) return hr;
+ TRACE("new node type %d\n", type);
+ switch (type)
+ {
+ case NODE_ATTRIBUTE:
+ case NODE_DOCUMENT:
+ case NODE_CDATA_SECTION:
+ if (outNewChild) *outNewChild = NULL;
+ return E_FAIL;
+ default:
+ return node_insert_before(&This->node, newChild, &refChild, outNewChild);
+ }
+}
static HRESULT WINAPI domdoc_replaceChild(
IXMLDOMDocument3 *iface,
domdoc *This = impl_from_IXMLDOMDocument3( iface );
IXMLDOMNode *elementNode;
xmlNodePtr oldRoot;
+ xmlDocPtr old_doc;
xmlnode *xmlNode;
+ int refcount = 0;
HRESULT hr;
TRACE("(%p)->(%p)\n", This, DOMElement);
if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
+ old_doc = xmlNode->node->doc;
+ if (old_doc != get_doc(This))
+ refcount = xmlnode_get_inst_cnt(xmlNode);
+
+ /* old root is still orphaned by its document, update refcount from new root */
+ if (refcount) xmldoc_add_refs(get_doc(This), refcount);
oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
+ if (refcount) xmldoc_release_refs(old_doc, refcount);
IXMLDOMNode_Release( elementNode );
if(oldRoot)
xmlChar* tagName_to_XPath(const BSTR tagName)
{
xmlChar *query, *tmp;
+ static const xmlChar everything[] = "/descendant::node()";
static const xmlChar mod_pre[] = "*[local-name()='";
static const xmlChar mod_post[] = "']";
static const xmlChar prefix[] = "descendant::";
const WCHAR *tokBegin, *tokEnd;
int len;
+ /* Special case - empty tagname - means select all nodes,
+ except document itself. */
+ if (!*tagName)
+ return xmlStrdup(everything);
+
query = xmlStrdup(prefix);
tokBegin = tagName;
hr = get_node_type(Type, &node_type);
if(FAILED(hr)) return hr;
- if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
- FIXME("nodes with namespaces currently not supported.\n");
-
TRACE("node_type %d\n", node_type);
/* exit earlier for types that need name */
}
xml_name = xmlchar_from_wchar(name);
- /* prevent empty href to be allocated */
+ /* prevent empty href from being allocated */
href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
switch(node_type)
xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
- /* allow to create default namespace xmlns= */
+ /* allow creating the default namespace xmlns= */
if (local || (href && *href))
{
xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
break;
}
case NODE_ATTRIBUTE:
- xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
+ {
+ xmlChar *local, *prefix;
+
+ local = xmlSplitQName2(xml_name, &prefix);
+
+ xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
+
+ if (local || (href && *href))
+ {
+ /* we need a floating namespace here, it can't be created linked to attribute from
+ a start */
+ xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
+ xmlSetNs(xmlnode, ns);
+ }
+
+ xmlFree(local);
+ xmlFree(prefix);
+
break;
+ }
case NODE_TEXT:
xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
break;
return attach_xmldoc(This, xmldoc);
}
- return S_OK;
+ return E_FAIL;
}
static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
if(FAILED(hr))
return hr;
- if(This->bsc) {
- hr = detach_bsc(This->bsc);
- if(FAILED(hr))
- return hr;
- }
-
- This->bsc = bsc;
- return S_OK;
+ return detach_bsc(bsc);
}
static HRESULT WINAPI domdoc_load(
domdoc *This = impl_from_IXMLDOMDocument3( iface );
LPWSTR filename = NULL;
HRESULT hr = S_FALSE;
- IXMLDOMDocument3 *pNewDoc = NULL;
- IStream *pStream = NULL;
xmlDocPtr xmldoc;
TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
case 1:
/* Only takes UTF-8 strings.
* NOT NULL-terminated. */
- SafeArrayAccessData(psa, (void**)&str);
+ hr = SafeArrayAccessData(psa, (void**)&str);
+ if (FAILED(hr))
+ {
+ This->error = hr;
+ WARN("failed to access array data, 0x%08x\n", hr);
+ break;
+ }
SafeArrayGetUBound(psa, 1, &len);
if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
}
break;
case VT_UNKNOWN:
+ {
+ ISequentialStream *stream = NULL;
+ IXMLDOMDocument3 *newdoc = NULL;
+
if (!V_UNKNOWN(&source)) return E_INVALIDARG;
- hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
+
+ hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
if(hr == S_OK)
{
- if(pNewDoc)
+ if(newdoc)
{
- domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
+ domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
xmldoc->_private = create_priv();
return hr;
}
}
- hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
- if(hr == S_OK)
- {
- IPersistStream *pDocStream;
- hr = IXMLDOMDocument3_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
- if(hr == S_OK)
- {
- hr = IPersistStream_Load(pDocStream, pStream);
- IStream_Release(pStream);
- if(hr == S_OK)
- {
- *isSuccessful = VARIANT_TRUE;
- TRACE("Using IStream to load Document\n");
- return S_OK;
- }
- else
- {
- ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
- }
- }
- else
- {
- ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
- }
- }
- else
+ hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
+ if (FAILED(hr))
+ hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
+
+ if (hr == S_OK)
{
- /* ISequentialStream */
- FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
+ hr = domdoc_load_from_stream(This, stream);
+ if (hr == S_OK)
+ *isSuccessful = VARIANT_TRUE;
+ ISequentialStream_Release(stream);
+ return hr;
}
+
+ FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
break;
- default:
- FIXME("VT type not supported (%d)\n", V_VT(&source));
+ }
+ default:
+ FIXME("VT type not supported (%d)\n", V_VT(&source));
}
if ( filename )
{
IMoniker *mon;
+ CoTaskMemFree(This->properties->url);
+ This->properties->url = NULL;
+
hr = create_moniker_from_url( filename, &mon);
if ( SUCCEEDED(hr) )
{
hr = domdoc_load_moniker( This, mon );
+ if (hr == S_OK)
+ IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
IMoniker_Release(mon);
}
static HRESULT WINAPI domdoc_get_url(
IXMLDOMDocument3 *iface,
- BSTR* urlString )
+ BSTR* url )
{
domdoc *This = impl_from_IXMLDOMDocument3(iface);
- FIXME("(%p)->(%p)\n", This, urlString);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%p)\n", This, url);
+
+ if (!url)
+ return E_INVALIDARG;
+
+ if (This->properties->url)
+ {
+ *url = SysAllocString(This->properties->url);
+ if (!*url)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+ }
+ else
+ return return_null_bstr(url);
}
if (!This->namespaces)
{
- hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
+ hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
if (hr != S_OK) return hr;
hr = cache_from_doc_ns(This->namespaces, &This->node);
lstrcmpiW(p, PropertyResolveExternalsW) == 0)
{
/* Ignore */
- FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
+ FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
return S_OK;
}
return S_OK;
}
-static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
- DWORD *pdwCookie)
+static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
+ DWORD *cookie)
{
ConnectionPoint *This = impl_from_IConnectionPoint(iface);
- FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
- return E_NOTIMPL;
+ IUnknown *sink;
+ HRESULT hr;
+ DWORD i;
+
+ TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
+
+ hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
+ if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
+ hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
+ if(FAILED(hr))
+ return CONNECT_E_CANNOTCONNECT;
+
+ if(This->sinks)
+ {
+ for (i = 0; i < This->sinks_size; i++)
+ if (!This->sinks[i].unk)
+ break;
+
+ if (i == This->sinks_size)
+ This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
+ }
+ else
+ {
+ This->sinks = heap_alloc(sizeof(*This->sinks));
+ This->sinks_size = 1;
+ i = 0;
+ }
+
+ This->sinks[i].unk = sink;
+ if (cookie)
+ *cookie = i+1;
+
+ return S_OK;
}
static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
doc->resolving = 0;
doc->properties = properties_from_xmlDocPtr(xmldoc);
doc->error = S_OK;
- doc->stream = NULL;
doc->site = NULL;
doc->safeopt = 0;
- doc->bsc = NULL;
doc->cp_list = NULL;
doc->namespaces = NULL;
memset(doc->events, 0, sizeof(doc->events));
return S_OK;
}
-HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
+HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
{
xmlDocPtr xmldoc;
HRESULT hr;
- TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
+ TRACE("(%d, %p)\n", version, ppObj);
xmldoc = xmlNewDoc(NULL);
if(!xmldoc)
#else
-HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
+HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
{
MESSAGE("This program tried to use a DOMDocument object, but\n"
"libxml2 support was not present at compile time.\n");