diff --git "a/dll/win32/msxml3/domdoc.c" "b/dll/win32/msxml3/domdoc.c" index 76d3fdb6018..aa2c12b1b25 100644 --- "a/dll/win32/msxml3/domdoc.c" +++ "b/dll/win32/msxml3/domdoc.c" @@ -80,6 +80,7 @@ static const WCHAR PropertyNormalizeAttributeValuesW[] = {'N','o','r','m','a','l * We need to preserve this when reloading a document, * and also need access to it from the libxml backend. */ typedef struct { + LONG refs; MSXML_VERSION version; VARIANT_BOOL preserving; IXMLDOMSchemaCollection2* schemaCache; @@ -135,6 +136,7 @@ struct domdoc /* IObjectWithSite */ IUnknown *site; + IUri *base_uri; /* IObjectSafety */ DWORD safeopt; @@ -289,6 +291,7 @@ static domdoc_properties *create_properties(MSXML_VERSION version) { domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties)); + properties->refs = 1; list_init(&properties->selectNsList); properties->preserving = VARIANT_FALSE; properties->schemaCache = NULL; @@ -315,6 +318,7 @@ static domdoc_properties* copy_properties(domdoc_properties const* properties) if (pcopy) { + pcopy->refs = 1; pcopy->version = properties->version; pcopy->preserving = properties->preserving; pcopy->schemaCache = properties->schemaCache; @@ -344,9 +348,31 @@ static domdoc_properties* copy_properties(domdoc_properties const* properties) return pcopy; } -static void free_properties(domdoc_properties* properties) +static domdoc_properties * properties_add_ref(domdoc_properties *properties) { - if (properties) + LONG ref; + + if (!properties) return NULL; + + ref = InterlockedIncrement(&properties->refs); + TRACE("%p, %ld.\n", properties, ref); + return properties; +} + +static void properties_release(domdoc_properties *properties) +{ + LONG ref; + + if (!properties) return; + + ref = InterlockedDecrement(&properties->refs); + + TRACE("%p, %ld.\n", properties, ref); + + if (ref < 0) + WARN("negative refcount, expect troubles\n"); + + if (ref == 0) { if (properties->schemaCache) IXMLDOMSchemaCollection2_Release(properties->schemaCache); @@ -593,7 +619,7 @@ void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version) LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs) { LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs; - TRACE("(%p)->(%d)\n", doc, ref); + TRACE("%p, refcount %ld.\n", doc, ref); return ref; } @@ -606,7 +632,7 @@ LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs) { xmldoc_priv *priv = priv_from_xmlDocPtr(doc); LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs; - TRACE("(%p)->(%d)\n", doc, ref); + TRACE("%p, refcount %ld.\n", doc, ref); if (ref < 0) WARN("negative refcount, expect troubles\n"); @@ -621,7 +647,7 @@ LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs) xmlFreeNode( orphan->node ); heap_free( orphan ); } - free_properties(priv->properties); + properties_release(priv->properties); heap_free(doc->_private); xmlFreeDoc(doc); @@ -678,10 +704,16 @@ static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml ) if(This->node.node) { + properties_release(properties_from_xmlDocPtr(get_doc(This))); priv_from_xmlDocPtr(get_doc(This))->properties = NULL; if (xmldoc_release(get_doc(This)) != 0) + { + /* The xmlDocPtr object can no longer use the properties of this + * domdoc object. So give it its own copy. + */ priv_from_xmlDocPtr(get_doc(This))->properties = copy_properties(This->properties); + } } This->node.node = (xmlNodePtr) xml; @@ -689,7 +721,10 @@ static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml ) if(This->node.node) { xmldoc_add_ref(get_doc(This)); - priv_from_xmlDocPtr(get_doc(This))->properties = This->properties; + /* Only attach new xmlDocPtr objects, i.e. ones for which properties + * is still NULL. + */ + priv_from_xmlDocPtr(get_doc(This))->properties = properties_add_ref(This->properties); } return S_OK; @@ -789,20 +824,24 @@ static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream) if (FAILED(hr)) { - ERR("failed to copy stream 0x%08x\n", hr); + ERR("failed to copy stream, hr %#lx.\n", hr); IStream_Release(hstream); return hr; } hr = GetHGlobalFromStream(hstream, &hglobal); if (FAILED(hr)) + { + IStream_Release(hstream); return hr; + } len = GlobalSize(hglobal); ptr = GlobalLock(hglobal); if (len) xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE); GlobalUnlock(hglobal); + IStream_Release(hstream); if (!xmldoc) { @@ -824,7 +863,7 @@ static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream if (!stream) return E_INVALIDARG; - return domdoc_load_from_stream(This, (ISequentialStream*)stream); + return This->error = domdoc_load_from_stream(This, (ISequentialStream*)stream); } static HRESULT WINAPI PersistStreamInit_Save( @@ -845,7 +884,7 @@ static HRESULT WINAPI PersistStreamInit_Save( SysFreeString(xmlString); } - TRACE("ret 0x%08x\n", hr); + TRACE("hr %#lx.\n", hr); return hr; } @@ -944,9 +983,9 @@ static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID rii static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface ) { - domdoc *This = impl_from_IXMLDOMDocument3( iface ); - ULONG ref = InterlockedIncrement( &This->ref ); - TRACE("(%p)->(%d)\n", This, ref ); + domdoc *doc = impl_from_IXMLDOMDocument3(iface); + ULONG ref = InterlockedIncrement(&doc->ref); + TRACE("%p, refcount %ld.\n", iface, ref); return ref; } @@ -955,19 +994,22 @@ static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface ) domdoc *This = impl_from_IXMLDOMDocument3( iface ); LONG ref = InterlockedDecrement( &This->ref ); - TRACE("(%p)->(%d)\n", This, ref ); + TRACE("%p, refcount %ld.\n", iface, ref); - if ( ref == 0 ) + if (!ref) { int eid; if (This->site) IUnknown_Release( This->site ); + if (This->base_uri) + IUri_Release( This->base_uri ); destroy_xmlnode(&This->node); for (eid = 0; eid < EVENTID_LAST; eid++) if (This->events[eid]) IDispatch_Release(This->events[eid]); + properties_release(This->properties); release_namespaces(This); heap_free(This); } @@ -1168,6 +1210,8 @@ static HRESULT WINAPI domdoc_insertBefore( TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild); + if (!newChild) return E_INVALIDARG; + hr = IXMLDOMNode_get_nodeType(newChild, &type); if (hr != S_OK) return hr; @@ -1517,8 +1561,10 @@ static HRESULT WINAPI domdoc_transformNodeToObject( case VT_UNKNOWN: case VT_DISPATCH: { + ISequentialStream *stream; IXMLDOMDocument *doc; HRESULT hr; + BSTR str; if (!V_UNKNOWN(&output)) return E_INVALIDARG; @@ -1528,7 +1574,6 @@ static HRESULT WINAPI domdoc_transformNodeToObject( if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IXMLDOMDocument, (void **)&doc) == S_OK) { VARIANT_BOOL b; - BSTR str; if (FAILED(hr = node_transform_node(&This->node, stylesheet, &str))) return hr; @@ -1537,6 +1582,12 @@ static HRESULT WINAPI domdoc_transformNodeToObject( SysFreeString(str); return hr; } + else if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_ISequentialStream, (void**)&stream) == S_OK) + { + hr = node_transform_node_params(&This->node, stylesheet, NULL, stream, NULL); + ISequentialStream_Release(stream); + return hr; + } else { FIXME("Unsupported destination type.\n"); @@ -2214,7 +2265,7 @@ static HRESULT WINAPI domdoc_load( if (FAILED(hr)) { This->error = hr; - WARN("failed to access array data, 0x%08x\n", hr); + WARN("failed to access array data, hr %#lx.\n", hr); break; } SafeArrayGetUBound(psa, 1, &len); @@ -2276,14 +2327,14 @@ static HRESULT WINAPI domdoc_load( if (hr == S_OK) { - hr = domdoc_load_from_stream(This, stream); + hr = This->error = 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); + FIXME("unsupported IUnknown type (%#lx) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl); break; } default: @@ -2333,7 +2384,7 @@ static HRESULT WINAPI domdoc_load( hr = S_FALSE; } - TRACE("ret (%d)\n", hr); + TRACE("hr %#lx.\n", hr); return hr; } @@ -2447,9 +2498,9 @@ static HRESULT WINAPI domdoc_loadXML( /* skip leading spaces if needed */ if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26) - while (*ptr && isspaceW(*ptr)) ptr++; + while (*ptr && iswspace(*ptr)) ptr++; - xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE); + xmldoc = doparse(This, (char*)ptr, lstrlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE); if ( !xmldoc ) { This->error = E_FAIL; @@ -2498,10 +2549,10 @@ static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffe HRESULT hr; hr = IStream_Write((IStream*)ctx, buffer, len, &written); - TRACE("0x%08x %p %d %u\n", hr, buffer, len, written); + TRACE("hr %#lx, %p, %d, %lu.\n", hr, buffer, len, written); if (hr != S_OK) { - WARN("stream write error: 0x%08x\n", hr); + WARN("stream write error, hr %#lx.\n", hr); return -1; } else @@ -2514,13 +2565,72 @@ static int XMLCALL domdoc_stream_save_closecallback(void *ctx) return 0; } +static char *xmldoc_encoding(IXMLDOMDocument3 *doc) +{ + HRESULT hr; + IXMLDOMNode *node; + char *encoding = NULL; + + hr = IXMLDOMDocument3_get_firstChild(doc, &node); + if (hr == S_OK) + { + DOMNodeType type; + + hr = IXMLDOMNode_get_nodeType(node, &type); + if (hr == S_OK && type == NODE_PROCESSING_INSTRUCTION) + { + IXMLDOMProcessingInstruction *pi; + IXMLDOMNode *item; + IXMLDOMNamedNodeMap *node_map; + + hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void **)&pi); + if (hr == S_OK) + { + hr = IXMLDOMNode_get_attributes(node, &node_map); + if (hr == S_OK) + { + static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0}; + BSTR bstr; + + bstr = SysAllocString(encodingW); + hr = IXMLDOMNamedNodeMap_getNamedItem(node_map, bstr, &item); + SysFreeString(bstr); + if (hr == S_OK) + { + VARIANT var; + + hr = IXMLDOMNode_get_nodeValue(item, &var); + if (hr == S_OK) + { + if (V_VT(&var) == VT_BSTR) + encoding = (char *)xmlchar_from_wchar(V_BSTR(&var)); + + VariantClear(&var); + } + } + + IXMLDOMNamedNodeMap_Release(node_map); + } + + IXMLDOMProcessingInstruction_Release(pi); + } + } + + IXMLDOMNode_Release(node); + } + + if (!encoding && (encoding = heap_alloc(sizeof("UTF-8")))) + strcpy(encoding, "UTF-8"); + + return encoding; +} + static HRESULT WINAPI domdoc_save( IXMLDOMDocument3 *iface, VARIANT destination ) { domdoc *This = impl_from_IXMLDOMDocument3( iface ); xmlSaveCtxtPtr ctx = NULL; - xmlNodePtr xmldecl; HRESULT ret = S_OK; TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination)); @@ -2553,9 +2663,12 @@ static HRESULT WINAPI domdoc_save( ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream); if(ret == S_OK) { - int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0; + char *encoding = xmldoc_encoding(iface); + + TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default"); ctx = xmlSaveToIO(domdoc_stream_save_writecallback, - domdoc_stream_save_closecallback, stream, NULL, options); + domdoc_stream_save_closecallback, stream, encoding, XML_SAVE_NO_DECL); + heap_free(encoding); if(!ctx) { @@ -2569,8 +2682,7 @@ static HRESULT WINAPI domdoc_save( case VT_BSTR: case VT_BSTR | VT_BYREF: { - int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0; - + char *encoding; /* save with file path */ HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); @@ -2580,9 +2692,12 @@ static HRESULT WINAPI domdoc_save( return E_FAIL; } - /* disable top XML declaration */ + encoding = xmldoc_encoding(iface); + TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default"); ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback, - handle, NULL, options); + handle, encoding, XML_SAVE_NO_DECL); + heap_free(encoding); + if (!ctx) { CloseHandle(handle); @@ -2596,9 +2711,7 @@ static HRESULT WINAPI domdoc_save( return S_FALSE; } - xmldecl = xmldoc_unlink_xmldecl(get_doc(This)); if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE; - xmldoc_link_xmldecl(get_doc(This), xmldecl); /* will release resources through close callback */ xmlSaveClose(ctx); @@ -3460,7 +3573,7 @@ static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD co { ConnectionPoint *This = impl_from_IConnectionPoint(iface); - TRACE("(%p)->(%d)\n", This, cookie); + TRACE("%p, %ld.\n", iface, cookie); if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk) return CONNECT_E_NOCONNECTION; @@ -3551,6 +3664,12 @@ static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUn This->site = NULL; } + if(This->base_uri) + { + IUri_Release(This->base_uri); + This->base_uri = NULL; + } + return S_OK; } @@ -3611,13 +3730,14 @@ static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *ifa static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, DWORD mask, DWORD enabled) { - domdoc *This = impl_from_IObjectSafety(iface); - TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled); + domdoc *doc = impl_from_IObjectSafety(iface); + + TRACE("%p, %s, %lx, %lx.\n", iface, debugstr_guid(riid), mask, enabled); if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0) return E_FAIL; - This->safeopt = (This->safeopt & ~mask) | (mask & enabled); + doc->safeopt = (doc->safeopt & ~mask) | (mask & enabled); return S_OK; } @@ -3661,9 +3781,10 @@ HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document) doc->async = VARIANT_TRUE; doc->validating = 0; doc->resolving = 0; - doc->properties = properties_from_xmlDocPtr(xmldoc); + doc->properties = properties_add_ref(properties_from_xmlDocPtr(xmldoc)); doc->error = S_OK; doc->site = NULL; + doc->base_uri = NULL; doc->safeopt = 0; doc->cp_list = NULL; doc->namespaces = NULL; @@ -3699,7 +3820,7 @@ HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj) hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj); if(FAILED(hr)) { - free_properties(properties_from_xmlDocPtr(xmldoc)); + properties_release(properties_from_xmlDocPtr(xmldoc)); heap_free(xmldoc->_private); xmlFreeDoc(xmldoc); return hr;