On 4/10/21 4:27 AM, Jefferson Carpenter wrote:
Moved some code from mxwriter ISAXContentHandler implementation into free functions that can be swapped out for DOMDocument functions.
For other mxwriter callback functions, immediately return E_NOTIMPL if the destination is a DOMDocument.
Added test_mxwriter_domdoc_start_end_document to help check the implementation of DOMDocument locking.
Added "BOOL locked" to XML documents and a private interface that allows this variable to be set and checked. (This variable is not used thread safely. `LONG refs` is thread safe, but `struct list orphans` is not.)
thanks, Jefferson @@ -125,6 +125,7 @@ struct domdoc IPersistStreamInit IPersistStreamInit_iface; IObjectWithSite IObjectWithSite_iface; IObjectSafety IObjectSafety_iface;
- IWineXMLDOMDocumentLock IWineXMLDOMDocumentLock_iface; IConnectionPointContainer IConnectionPointContainer_iface; LONG ref; VARIANT_BOOL async;
Maybe that could work, yes.
@@ -209,6 +210,7 @@ typedef struct _xmldoc_priv { LONG refs; struct list orphans; domdoc_properties* properties;
- BOOL locked;
} xmldoc_priv;
Why does it have to be in _priv?
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index 67f322eb0e5..9cbb2305830 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -457,6 +457,8 @@ HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT if(!new_child) return E_INVALIDARG;
- if (xmldoc_get_locked(This->node->doc)) return E_FAIL;
- node_obj = get_node_obj(new_child); if(!node_obj) return E_FAIL;
@@ -569,6 +571,8 @@ HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *ol if(!newChild || !oldChild) return E_INVALIDARG;
- if (xmldoc_get_locked(This->node->doc)) return E_FAIL;
- if(ret) *ret = NULL;
@@ -627,6 +631,8 @@ HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldCh
if(!child) return E_INVALIDARG;
- if (xmldoc_get_locked(This->node->doc)) return E_FAIL;
- if(oldChild) *oldChild = NULL;
Maybe, but there's many more methods that modify the tree.
+static HRESULT writer_end_tag_domdoc(mxwriter *writer, const WCHAR *qname, int len) {
- HRESULT hr;
- IXMLDOMNode *parent_node;
- IWineXMLDOMDocumentLock_put_locked(writer->doc_lock, 0);
- hr = domdoc_maybe_write_chars(writer);
- if (FAILED(hr)) return hr;
- IWineXMLDOMDocumentLock_put_locked(writer->doc_lock, 1);
- hr = IXMLDOMNode_get_parentNode(writer->current_node, &parent_node);
- if (FAILED(hr)) return hr;
- IXMLDOMNode_Release(writer->current_node);
- writer->current_node = parent_node;
- return hr;
+}
I don't understand this pattern. Idea I had was to lock when output is set to a document, and unlock when everything is written. Is that wrong?
+static HRESULT writer_start_tag_string_len_stream(mxwriter *writer, const WCHAR *qname, int len) +{
- static const WCHAR ltW[] = {'<'};
- close_element_starttag(writer);
- set_element_name(writer, qname ? qname : emptyW, qname ? len : 0);
- write_node_indent(writer);
- write_output_buffer(writer, ltW, 1);
- write_output_buffer(writer, qname ? qname : emptyW, qname ? len : 0);
- writer_inc_indent(writer);
- return S_OK;
+}
+static HRESULT writer_start_tag_bstr_stream(mxwriter *writer, BSTR name) +{
- return writer_start_tag_string_len_stream(writer, name, SysStringLen(name));
+}
Do you need both?