msi: Don't set the shortcut's working directory if it's NULL.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <assert.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "ole2.h"
32 #include "msxml2.h"
33 #include "wininet.h"
34 #include "urlmon.h"
35 #include "winreg.h"
36 #include "shlwapi.h"
37
38 #include "wine/debug.h"
39
40 #include "msxml_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
43
44 #ifdef HAVE_LIBXML2
45
46 typedef struct {
47     const struct IBindStatusCallbackVtbl *lpVtbl;
48 } bsc;
49
50 static HRESULT WINAPI bsc_QueryInterface(
51     IBindStatusCallback *iface,
52     REFIID riid,
53     LPVOID *ppobj )
54 {
55     if (IsEqualGUID(riid, &IID_IUnknown) ||
56         IsEqualGUID(riid, &IID_IBindStatusCallback))
57     {
58         IBindStatusCallback_AddRef( iface );
59         *ppobj = iface;
60         return S_OK;
61     }
62
63     FIXME("interface %s not implemented\n", debugstr_guid(riid));
64     return E_NOINTERFACE;
65 }
66
67 static ULONG WINAPI bsc_AddRef(
68     IBindStatusCallback *iface )
69 {
70     return 2;
71 }
72
73 static ULONG WINAPI bsc_Release(
74     IBindStatusCallback *iface )
75 {
76     return 1;
77 }
78
79 static HRESULT WINAPI bsc_OnStartBinding(
80         IBindStatusCallback* iface,
81         DWORD dwReserved,
82         IBinding* pib)
83 {
84     return S_OK;
85 }
86
87 static HRESULT WINAPI bsc_GetPriority(
88         IBindStatusCallback* iface,
89         LONG* pnPriority)
90 {
91     return S_OK;
92 }
93
94 static HRESULT WINAPI bsc_OnLowResource(
95         IBindStatusCallback* iface,
96         DWORD reserved)
97 {
98     return S_OK;
99 }
100
101 static HRESULT WINAPI bsc_OnProgress(
102         IBindStatusCallback* iface,
103         ULONG ulProgress,
104         ULONG ulProgressMax,
105         ULONG ulStatusCode,
106         LPCWSTR szStatusText)
107 {
108     return S_OK;
109 }
110
111 static HRESULT WINAPI bsc_OnStopBinding(
112         IBindStatusCallback* iface,
113         HRESULT hresult,
114         LPCWSTR szError)
115 {
116     return S_OK;
117 }
118
119 static HRESULT WINAPI bsc_GetBindInfo(
120         IBindStatusCallback* iface,
121         DWORD* grfBINDF,
122         BINDINFO* pbindinfo)
123 {
124     *grfBINDF = BINDF_RESYNCHRONIZE;
125     
126     return S_OK;
127 }
128
129 static HRESULT WINAPI bsc_OnDataAvailable(
130         IBindStatusCallback* iface,
131         DWORD grfBSCF,
132         DWORD dwSize,
133         FORMATETC* pformatetc,
134         STGMEDIUM* pstgmed)
135 {
136     return S_OK;
137 }
138
139 static HRESULT WINAPI bsc_OnObjectAvailable(
140         IBindStatusCallback* iface,
141         REFIID riid,
142         IUnknown* punk)
143 {
144     return S_OK;
145 }
146
147 const struct IBindStatusCallbackVtbl bsc_vtbl =
148 {
149     bsc_QueryInterface,
150     bsc_AddRef,
151     bsc_Release,
152     bsc_OnStartBinding,
153     bsc_GetPriority,
154     bsc_OnLowResource,
155     bsc_OnProgress,
156     bsc_OnStopBinding,
157     bsc_GetBindInfo,
158     bsc_OnDataAvailable,
159     bsc_OnObjectAvailable
160 };
161
162 static bsc domdoc_bsc = { &bsc_vtbl };
163
164 typedef struct _domdoc
165 {
166     const struct IXMLDOMDocumentVtbl *lpVtbl;
167     LONG ref;
168     VARIANT_BOOL async;
169     IUnknown *node_unk;
170     IXMLDOMNode *node;
171     HRESULT error;
172 } domdoc;
173
174 LONG xmldoc_add_ref(xmlDocPtr doc)
175 {
176     LONG ref = InterlockedIncrement((LONG*)&doc->_private);
177     TRACE("%ld\n", ref);
178     return ref;
179 }
180
181 LONG xmldoc_release(xmlDocPtr doc)
182 {
183     LONG ref = InterlockedDecrement((LONG*)&doc->_private);
184     TRACE("%ld\n", ref);
185     if(ref == 0)
186     {
187         TRACE("freeing docptr %p\n", doc);
188         xmlFreeDoc(doc);
189     }
190
191     return ref;
192 }
193
194 static inline domdoc *impl_from_IXMLDOMDocument( IXMLDOMDocument *iface )
195 {
196     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
197 }
198
199 static inline xmlDocPtr get_doc( domdoc *This )
200 {
201     return (xmlDocPtr) xmlNodePtr_from_domnode( This->node, XML_DOCUMENT_NODE );
202 }
203
204 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument *iface, REFIID riid, void** ppvObject )
205 {
206     domdoc *This = impl_from_IXMLDOMDocument( iface );
207
208     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
209
210     if ( IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
211          IsEqualGUID( riid, &IID_IUnknown ) )
212     {
213         *ppvObject = iface;
214     }
215     else if ( IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
216               IsEqualGUID( riid, &IID_IDispatch ) )
217     {
218         return IUnknown_QueryInterface(This->node_unk, riid, ppvObject);
219     }
220     else
221     {
222         FIXME("interface %s not implemented\n", debugstr_guid(riid));
223         return E_NOINTERFACE;
224     }
225
226     IXMLDOMDocument_AddRef( iface );
227
228     return S_OK;
229 }
230
231
232 static ULONG WINAPI domdoc_AddRef(
233      IXMLDOMDocument *iface )
234 {
235     domdoc *This = impl_from_IXMLDOMDocument( iface );
236     TRACE("%p\n", This );
237     return InterlockedIncrement( &This->ref );
238 }
239
240
241 static ULONG WINAPI domdoc_Release(
242      IXMLDOMDocument *iface )
243 {
244     domdoc *This = impl_from_IXMLDOMDocument( iface );
245     LONG ref;
246
247     TRACE("%p\n", This );
248
249     ref = InterlockedDecrement( &This->ref );
250     if ( ref == 0 )
251     {
252         IUnknown_Release( This->node_unk );
253         HeapFree( GetProcessHeap(), 0, This );
254     }
255
256     return ref;
257 }
258
259 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument *iface, UINT* pctinfo )
260 {
261     FIXME("\n");
262     return E_NOTIMPL;
263 }
264
265 static HRESULT WINAPI domdoc_GetTypeInfo(
266     IXMLDOMDocument *iface,
267     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
268 {
269     FIXME("\n");
270     return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI domdoc_GetIDsOfNames(
274     IXMLDOMDocument *iface,
275     REFIID riid,
276     LPOLESTR* rgszNames,
277     UINT cNames,
278     LCID lcid,
279     DISPID* rgDispId)
280 {
281     FIXME("\n");
282     return E_NOTIMPL;
283 }
284
285
286 static HRESULT WINAPI domdoc_Invoke(
287     IXMLDOMDocument *iface,
288     DISPID dispIdMember,
289     REFIID riid,
290     LCID lcid,
291     WORD wFlags,
292     DISPPARAMS* pDispParams,
293     VARIANT* pVarResult,
294     EXCEPINFO* pExcepInfo,
295     UINT* puArgErr)
296 {
297     FIXME("\n");
298     return E_NOTIMPL;
299 }
300
301
302 static HRESULT WINAPI domdoc_get_nodeName(
303     IXMLDOMDocument *iface,
304     BSTR* name )
305 {
306     domdoc *This = impl_from_IXMLDOMDocument( iface );
307     return IXMLDOMNode_get_nodeName( This->node, name );
308 }
309
310
311 static HRESULT WINAPI domdoc_get_nodeValue(
312     IXMLDOMDocument *iface,
313     VARIANT* value )
314 {
315     domdoc *This = impl_from_IXMLDOMDocument( iface );
316     return IXMLDOMNode_get_nodeValue( This->node, value );
317 }
318
319
320 static HRESULT WINAPI domdoc_put_nodeValue(
321     IXMLDOMDocument *iface,
322     VARIANT value)
323 {
324     domdoc *This = impl_from_IXMLDOMDocument( iface );
325     return IXMLDOMNode_put_nodeValue( This->node, value );
326 }
327
328
329 static HRESULT WINAPI domdoc_get_nodeType(
330     IXMLDOMDocument *iface,
331     DOMNodeType* type )
332 {
333     domdoc *This = impl_from_IXMLDOMDocument( iface );
334     return IXMLDOMNode_get_nodeType( This->node, type );
335 }
336
337
338 static HRESULT WINAPI domdoc_get_parentNode(
339     IXMLDOMDocument *iface,
340     IXMLDOMNode** parent )
341 {
342     domdoc *This = impl_from_IXMLDOMDocument( iface );
343     return IXMLDOMNode_get_parentNode( This->node, parent );
344 }
345
346
347 static HRESULT WINAPI domdoc_get_childNodes(
348     IXMLDOMDocument *iface,
349     IXMLDOMNodeList** childList )
350 {
351     domdoc *This = impl_from_IXMLDOMDocument( iface );
352     return IXMLDOMNode_get_childNodes( This->node, childList );
353 }
354
355
356 static HRESULT WINAPI domdoc_get_firstChild(
357     IXMLDOMDocument *iface,
358     IXMLDOMNode** firstChild )
359 {
360     domdoc *This = impl_from_IXMLDOMDocument( iface );
361     return IXMLDOMNode_get_firstChild( This->node, firstChild );
362 }
363
364
365 static HRESULT WINAPI domdoc_get_lastChild(
366     IXMLDOMDocument *iface,
367     IXMLDOMNode** lastChild )
368 {
369     domdoc *This = impl_from_IXMLDOMDocument( iface );
370     return IXMLDOMNode_get_lastChild( This->node, lastChild );
371 }
372
373
374 static HRESULT WINAPI domdoc_get_previousSibling(
375     IXMLDOMDocument *iface,
376     IXMLDOMNode** previousSibling )
377 {
378     domdoc *This = impl_from_IXMLDOMDocument( iface );
379     return IXMLDOMNode_get_previousSibling( This->node, previousSibling );
380 }
381
382
383 static HRESULT WINAPI domdoc_get_nextSibling(
384     IXMLDOMDocument *iface,
385     IXMLDOMNode** nextSibling )
386 {
387     domdoc *This = impl_from_IXMLDOMDocument( iface );
388     return IXMLDOMNode_get_nextSibling( This->node, nextSibling );
389 }
390
391
392 static HRESULT WINAPI domdoc_get_attributes(
393     IXMLDOMDocument *iface,
394     IXMLDOMNamedNodeMap** attributeMap )
395 {
396     domdoc *This = impl_from_IXMLDOMDocument( iface );
397     return IXMLDOMNode_get_attributes( This->node, attributeMap );
398 }
399
400
401 static HRESULT WINAPI domdoc_insertBefore(
402     IXMLDOMDocument *iface,
403     IXMLDOMNode* newChild,
404     VARIANT refChild,
405     IXMLDOMNode** outNewChild )
406 {
407     domdoc *This = impl_from_IXMLDOMDocument( iface );
408     return IXMLDOMNode_insertBefore( This->node, newChild, refChild, outNewChild );
409 }
410
411
412 static HRESULT WINAPI domdoc_replaceChild(
413     IXMLDOMDocument *iface,
414     IXMLDOMNode* newChild,
415     IXMLDOMNode* oldChild,
416     IXMLDOMNode** outOldChild)
417 {
418     domdoc *This = impl_from_IXMLDOMDocument( iface );
419     return IXMLDOMNode_replaceChild( This->node, newChild, oldChild, outOldChild );
420 }
421
422
423 static HRESULT WINAPI domdoc_removeChild(
424     IXMLDOMDocument *iface,
425     IXMLDOMNode* childNode,
426     IXMLDOMNode** oldChild)
427 {
428     domdoc *This = impl_from_IXMLDOMDocument( iface );
429     return IXMLDOMNode_removeChild( This->node, childNode, oldChild );
430 }
431
432
433 static HRESULT WINAPI domdoc_appendChild(
434     IXMLDOMDocument *iface,
435     IXMLDOMNode* newChild,
436     IXMLDOMNode** outNewChild)
437 {
438     domdoc *This = impl_from_IXMLDOMDocument( iface );
439     return IXMLDOMNode_appendChild( This->node, newChild, outNewChild );
440 }
441
442
443 static HRESULT WINAPI domdoc_hasChildNodes(
444     IXMLDOMDocument *iface,
445     VARIANT_BOOL* hasChild)
446 {
447     domdoc *This = impl_from_IXMLDOMDocument( iface );
448     return IXMLDOMNode_hasChildNodes( This->node, hasChild );
449 }
450
451
452 static HRESULT WINAPI domdoc_get_ownerDocument(
453     IXMLDOMDocument *iface,
454     IXMLDOMDocument** DOMDocument)
455 {
456     domdoc *This = impl_from_IXMLDOMDocument( iface );
457     return IXMLDOMNode_get_ownerDocument( This->node, DOMDocument );
458 }
459
460
461 static HRESULT WINAPI domdoc_cloneNode(
462     IXMLDOMDocument *iface,
463     VARIANT_BOOL deep,
464     IXMLDOMNode** cloneRoot)
465 {
466     domdoc *This = impl_from_IXMLDOMDocument( iface );
467     return IXMLDOMNode_cloneNode( This->node, deep, cloneRoot );
468 }
469
470
471 static HRESULT WINAPI domdoc_get_nodeTypeString(
472     IXMLDOMDocument *iface,
473     BSTR* nodeType )
474 {
475     domdoc *This = impl_from_IXMLDOMDocument( iface );
476     return IXMLDOMNode_get_nodeTypeString( This->node, nodeType );
477 }
478
479
480 static HRESULT WINAPI domdoc_get_text(
481     IXMLDOMDocument *iface,
482     BSTR* text )
483 {
484     domdoc *This = impl_from_IXMLDOMDocument( iface );
485     return IXMLDOMNode_get_text( This->node, text );
486 }
487
488
489 static HRESULT WINAPI domdoc_put_text(
490     IXMLDOMDocument *iface,
491     BSTR text )
492 {
493     domdoc *This = impl_from_IXMLDOMDocument( iface );
494     return IXMLDOMNode_put_text( This->node, text );
495 }
496
497
498 static HRESULT WINAPI domdoc_get_specified(
499     IXMLDOMDocument *iface,
500     VARIANT_BOOL* isSpecified )
501 {
502     domdoc *This = impl_from_IXMLDOMDocument( iface );
503     return IXMLDOMNode_get_specified( This->node, isSpecified );
504 }
505
506
507 static HRESULT WINAPI domdoc_get_definition(
508     IXMLDOMDocument *iface,
509     IXMLDOMNode** definitionNode )
510 {
511     domdoc *This = impl_from_IXMLDOMDocument( iface );
512     return IXMLDOMNode_get_definition( This->node, definitionNode );
513 }
514
515
516 static HRESULT WINAPI domdoc_get_nodeTypedValue(
517     IXMLDOMDocument *iface,
518     VARIANT* typedValue )
519 {
520     domdoc *This = impl_from_IXMLDOMDocument( iface );
521     return IXMLDOMNode_get_nodeTypedValue( This->node, typedValue );
522 }
523
524 static HRESULT WINAPI domdoc_put_nodeTypedValue(
525     IXMLDOMDocument *iface,
526     VARIANT typedValue )
527 {
528     domdoc *This = impl_from_IXMLDOMDocument( iface );
529     return IXMLDOMNode_put_nodeTypedValue( This->node, typedValue );
530 }
531
532
533 static HRESULT WINAPI domdoc_get_dataType(
534     IXMLDOMDocument *iface,
535     VARIANT* dataTypeName )
536 {
537     domdoc *This = impl_from_IXMLDOMDocument( iface );
538     return IXMLDOMNode_get_dataType( This->node, dataTypeName );
539 }
540
541
542 static HRESULT WINAPI domdoc_put_dataType(
543     IXMLDOMDocument *iface,
544     BSTR dataTypeName )
545 {
546     domdoc *This = impl_from_IXMLDOMDocument( iface );
547     return IXMLDOMNode_put_dataType( This->node, dataTypeName );
548 }
549
550
551 static HRESULT WINAPI domdoc_get_xml(
552     IXMLDOMDocument *iface,
553     BSTR* xmlString )
554 {
555     domdoc *This = impl_from_IXMLDOMDocument( iface );
556     return IXMLDOMNode_get_xml( This->node, xmlString );
557 }
558
559
560 static HRESULT WINAPI domdoc_transformNode(
561     IXMLDOMDocument *iface,
562     IXMLDOMNode* styleSheet,
563     BSTR* xmlString )
564 {
565     domdoc *This = impl_from_IXMLDOMDocument( iface );
566     return IXMLDOMNode_transformNode( This->node, styleSheet, xmlString );
567 }
568
569
570 static HRESULT WINAPI domdoc_selectNodes(
571     IXMLDOMDocument *iface,
572     BSTR queryString,
573     IXMLDOMNodeList** resultList )
574 {
575     domdoc *This = impl_from_IXMLDOMDocument( iface );
576     return IXMLDOMNode_selectNodes( This->node, queryString, resultList );
577 }
578
579
580 static HRESULT WINAPI domdoc_selectSingleNode(
581     IXMLDOMDocument *iface,
582     BSTR queryString,
583     IXMLDOMNode** resultNode )
584 {
585     domdoc *This = impl_from_IXMLDOMDocument( iface );
586     return IXMLDOMNode_selectSingleNode( This->node, queryString, resultNode );
587 }
588
589
590 static HRESULT WINAPI domdoc_get_parsed(
591     IXMLDOMDocument *iface,
592     VARIANT_BOOL* isParsed )
593 {
594     domdoc *This = impl_from_IXMLDOMDocument( iface );
595     return IXMLDOMNode_get_parsed( This->node, isParsed );
596 }
597
598
599 static HRESULT WINAPI domdoc_get_namespaceURI(
600     IXMLDOMDocument *iface,
601     BSTR* namespaceURI )
602 {
603     domdoc *This = impl_from_IXMLDOMDocument( iface );
604     return IXMLDOMNode_get_namespaceURI( This->node, namespaceURI );
605 }
606
607
608 static HRESULT WINAPI domdoc_get_prefix(
609     IXMLDOMDocument *iface,
610     BSTR* prefixString )
611 {
612     domdoc *This = impl_from_IXMLDOMDocument( iface );
613     return IXMLDOMNode_get_prefix( This->node, prefixString );
614 }
615
616
617 static HRESULT WINAPI domdoc_get_baseName(
618     IXMLDOMDocument *iface,
619     BSTR* nameString )
620 {
621     domdoc *This = impl_from_IXMLDOMDocument( iface );
622     return IXMLDOMNode_get_baseName( This->node, nameString );
623 }
624
625
626 static HRESULT WINAPI domdoc_transformNodeToObject(
627     IXMLDOMDocument *iface,
628     IXMLDOMNode* stylesheet,
629     VARIANT outputObject)
630 {
631     domdoc *This = impl_from_IXMLDOMDocument( iface );
632     return IXMLDOMNode_transformNodeToObject( This->node, stylesheet, outputObject );
633 }
634
635
636 static HRESULT WINAPI domdoc_get_doctype(
637     IXMLDOMDocument *iface,
638     IXMLDOMDocumentType** documentType )
639 {
640     FIXME("\n");
641     return E_NOTIMPL;
642 }
643
644
645 static HRESULT WINAPI domdoc_get_implementation(
646     IXMLDOMDocument *iface,
647     IXMLDOMImplementation** impl )
648 {
649     FIXME("\n");
650     return E_NOTIMPL;
651 }
652
653 static HRESULT WINAPI domdoc_get_documentElement(
654     IXMLDOMDocument *iface,
655     IXMLDOMElement** DOMElement )
656 {
657     domdoc *This = impl_from_IXMLDOMDocument( iface );
658     xmlDocPtr xmldoc = NULL;
659     xmlNodePtr root = NULL;
660     IXMLDOMNode *element_node;
661     HRESULT hr;
662
663     TRACE("%p\n", This);
664
665     *DOMElement = NULL;
666
667     xmldoc = get_doc( This );
668
669     root = xmlDocGetRootElement( xmldoc );
670     if ( !root )
671         return S_FALSE;
672
673     element_node = create_node( root );
674     if(!element_node) return S_FALSE;
675
676     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (LPVOID*)DOMElement);
677     IXMLDOMNode_Release(element_node);
678
679     return hr;
680 }
681
682
683 static HRESULT WINAPI domdoc_documentElement(
684     IXMLDOMDocument *iface,
685     IXMLDOMElement* DOMElement )
686 {
687     FIXME("\n");
688     return E_NOTIMPL;
689 }
690
691
692 static HRESULT WINAPI domdoc_createElement(
693     IXMLDOMDocument *iface,
694     BSTR tagname,
695     IXMLDOMElement** element )
696 {
697     FIXME("\n");
698     return E_NOTIMPL;
699 }
700
701
702 static HRESULT WINAPI domdoc_createDocumentFragment(
703     IXMLDOMDocument *iface,
704     IXMLDOMDocumentFragment** docFrag )
705 {
706     FIXME("\n");
707     return E_NOTIMPL;
708 }
709
710
711 static HRESULT WINAPI domdoc_createTextNode(
712     IXMLDOMDocument *iface,
713     BSTR data,
714     IXMLDOMText** text )
715 {
716     FIXME("\n");
717     return E_NOTIMPL;
718 }
719
720
721 static HRESULT WINAPI domdoc_createComment(
722     IXMLDOMDocument *iface,
723     BSTR data,
724     IXMLDOMComment** comment )
725 {
726     FIXME("\n");
727     return E_NOTIMPL;
728 }
729
730
731 static HRESULT WINAPI domdoc_createCDATASection(
732     IXMLDOMDocument *iface,
733     BSTR data,
734     IXMLDOMCDATASection** cdata )
735 {
736     FIXME("\n");
737     return E_NOTIMPL;
738 }
739
740
741 static HRESULT WINAPI domdoc_createProcessingInstruction(
742     IXMLDOMDocument *iface,
743     BSTR target,
744     BSTR data,
745     IXMLDOMProcessingInstruction** pi )
746 {
747     FIXME("\n");
748     return E_NOTIMPL;
749 }
750
751
752 static HRESULT WINAPI domdoc_createAttribute(
753     IXMLDOMDocument *iface,
754     BSTR name,
755     IXMLDOMAttribute** attribute )
756 {
757     FIXME("\n");
758     return E_NOTIMPL;
759 }
760
761
762 static HRESULT WINAPI domdoc_createEntityReference(
763     IXMLDOMDocument *iface,
764     BSTR name,
765     IXMLDOMEntityReference** entityRef )
766 {
767     FIXME("\n");
768     return E_NOTIMPL;
769 }
770
771
772 static HRESULT WINAPI domdoc_getElementsByTagName(
773     IXMLDOMDocument *iface,
774     BSTR tagName,
775     IXMLDOMNodeList** resultList )
776 {
777     domdoc *This = impl_from_IXMLDOMDocument( iface );
778     xmlChar *name;
779     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
780
781     name = xmlChar_from_wchar((WCHAR*)tagName);
782     *resultList = create_filtered_nodelist((xmlNodePtr)get_doc(This), name, TRUE);
783     HeapFree(GetProcessHeap(), 0, name);
784
785     if(!*resultList) return S_FALSE;
786     return S_OK;
787 }
788
789 static DOMNodeType get_node_type(VARIANT Type)
790 {
791     if(V_VT(&Type) == VT_I4)
792         return V_I4(&Type);
793
794     FIXME("Unsupported variant type %x\n", V_VT(&Type));
795     return 0;
796 }
797
798 static HRESULT WINAPI domdoc_createNode(
799     IXMLDOMDocument *iface,
800     VARIANT Type,
801     BSTR name,
802     BSTR namespaceURI,
803     IXMLDOMNode** node )
804 {
805     domdoc *This = impl_from_IXMLDOMDocument( iface );
806     DOMNodeType node_type;
807     xmlNodePtr xmlnode = NULL;
808     xmlChar *xml_name;
809
810     TRACE("(%p)->(type,%s,%s,%p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
811
812     node_type = get_node_type(Type);
813     TRACE("node_type %d\n", node_type);
814
815     xml_name = xmlChar_from_wchar((WCHAR*)name);
816
817     switch(node_type)
818     {
819     case NODE_ELEMENT:
820         xmlnode = xmlNewDocNode(get_doc(This), NULL, xml_name, NULL);
821         *node = create_node(xmlnode);
822         TRACE("created %p\n", xmlnode);
823         break;
824
825     default:
826         FIXME("unhandled node type %d\n", node_type);
827         break;
828     }
829
830     HeapFree(GetProcessHeap(), 0, xml_name);
831
832     if(xmlnode && *node)
833         return S_OK;
834
835     return E_FAIL;
836 }
837
838 static HRESULT WINAPI domdoc_nodeFromID(
839     IXMLDOMDocument *iface,
840     BSTR idString,
841     IXMLDOMNode** node )
842 {
843     FIXME("\n");
844     return E_NOTIMPL;
845 }
846
847 static xmlDocPtr doparse( char *ptr, int len )
848 {
849 #ifdef HAVE_XMLREADMEMORY
850     /*
851      * use xmlReadMemory if possible so we can suppress
852      * writing errors to stderr
853      */
854     return xmlReadMemory( ptr, len, NULL, NULL,
855                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
856 #else
857     return xmlParseMemory( ptr, len );
858 #endif
859 }
860
861 static xmlDocPtr doread( LPWSTR filename )
862 {
863     xmlDocPtr xmldoc = NULL;
864     HRESULT hr;
865     IBindCtx *pbc;
866     IStream *stream, *memstream;
867     WCHAR url[INTERNET_MAX_URL_LENGTH];
868     BYTE buf[4096];
869     DWORD read, written;
870
871     TRACE("%s\n", debugstr_w( filename ));
872
873     if(!PathIsURLW(filename))
874     {
875         WCHAR fullpath[MAX_PATH];
876         DWORD needed = sizeof(url)/sizeof(WCHAR);
877
878         if(!PathSearchAndQualifyW(filename, fullpath, sizeof(fullpath)/sizeof(WCHAR)))
879         {
880             WARN("can't find path\n");
881             return NULL;
882         }
883
884         if(FAILED(UrlCreateFromPathW(fullpath, url, &needed, 0)))
885         {
886             ERR("can't create url from path\n");
887             return NULL;
888         }
889         filename = url;
890     }
891
892     hr = CreateBindCtx(0, &pbc);
893     if(SUCCEEDED(hr))
894     {
895         hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)&domdoc_bsc.lpVtbl, NULL, 0);
896         if(SUCCEEDED(hr))
897         {
898             IMoniker *moniker;
899             hr = CreateURLMoniker(NULL, filename, &moniker);
900             if(SUCCEEDED(hr))
901             {
902                 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
903                 IMoniker_Release(moniker);
904             }
905         }
906         IBindCtx_Release(pbc);
907     }
908     if(FAILED(hr))
909         return NULL;
910
911     hr = CreateStreamOnHGlobal(NULL, TRUE, &memstream);
912     if(FAILED(hr))
913     {
914         IStream_Release(stream);
915         return NULL;
916     }
917
918     do
919     {
920         IStream_Read(stream, buf, sizeof(buf), &read);
921         hr = IStream_Write(memstream, buf, read, &written);
922     } while(SUCCEEDED(hr) && written != 0 && read != 0);
923
924     if(SUCCEEDED(hr))
925     {
926         HGLOBAL hglobal;
927         hr = GetHGlobalFromStream(memstream, &hglobal);
928         if(SUCCEEDED(hr))
929         {
930             DWORD len = GlobalSize(hglobal);
931             char *ptr = GlobalLock(hglobal);
932             if(len != 0)
933                 xmldoc = doparse( ptr, len );
934             GlobalUnlock(hglobal);
935         }
936     }
937     IStream_Release(memstream);
938     IStream_Release(stream);
939     return xmldoc;
940 }
941
942 static HRESULT WINAPI domdoc_load(
943     IXMLDOMDocument *iface,
944     VARIANT xmlSource,
945     VARIANT_BOOL* isSuccessful )
946 {
947     domdoc *This = impl_from_IXMLDOMDocument( iface );
948     LPWSTR filename = NULL;
949     xmlDocPtr xmldoc = NULL;
950     HRESULT hr = S_FALSE;
951
952     TRACE("type %d\n", V_VT(&xmlSource) );
953
954     *isSuccessful = VARIANT_FALSE;
955
956     assert( This->node );
957
958     attach_xmlnode(This->node, NULL);
959
960     switch( V_VT(&xmlSource) )
961     {
962     case VT_BSTR:
963         filename = V_BSTR(&xmlSource);
964     }
965
966     if ( filename )
967     {
968         xmldoc = doread( filename );
969     
970         if ( !xmldoc )
971             This->error = E_FAIL;
972         else
973         {
974             hr = This->error = S_OK;
975             *isSuccessful = VARIANT_TRUE;
976         }
977     }
978
979     if(!xmldoc)
980         xmldoc = xmlNewDoc(NULL);
981
982     xmldoc->_private = 0;
983     attach_xmlnode(This->node, (xmlNodePtr) xmldoc);
984
985     return hr;
986 }
987
988
989 static HRESULT WINAPI domdoc_get_readyState(
990     IXMLDOMDocument *iface,
991     long* value )
992 {
993     FIXME("\n");
994     return E_NOTIMPL;
995 }
996
997
998 static HRESULT WINAPI domdoc_get_parseError(
999     IXMLDOMDocument *iface,
1000     IXMLDOMParseError** errorObj )
1001 {
1002     BSTR error_string = NULL;
1003     static const WCHAR err[] = {'e','r','r','o','r',0};
1004     domdoc *This = impl_from_IXMLDOMDocument( iface );
1005
1006     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
1007
1008     if(This->error)
1009         error_string = SysAllocString(err);
1010
1011     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
1012     if(!*errorObj) return E_OUTOFMEMORY;
1013     return S_OK;
1014 }
1015
1016
1017 static HRESULT WINAPI domdoc_get_url(
1018     IXMLDOMDocument *iface,
1019     BSTR* urlString )
1020 {
1021     FIXME("\n");
1022     return E_NOTIMPL;
1023 }
1024
1025
1026 static HRESULT WINAPI domdoc_get_async(
1027     IXMLDOMDocument *iface,
1028     VARIANT_BOOL* isAsync )
1029 {
1030     domdoc *This = impl_from_IXMLDOMDocument( iface );
1031
1032     TRACE("%p <- %d\n", isAsync, This->async);
1033     *isAsync = This->async;
1034     return S_OK;
1035 }
1036
1037
1038 static HRESULT WINAPI domdoc_put_async(
1039     IXMLDOMDocument *iface,
1040     VARIANT_BOOL isAsync )
1041 {
1042     domdoc *This = impl_from_IXMLDOMDocument( iface );
1043
1044     TRACE("%d\n", isAsync);
1045     This->async = isAsync;
1046     return S_OK;
1047 }
1048
1049
1050 static HRESULT WINAPI domdoc_abort(
1051     IXMLDOMDocument *iface )
1052 {
1053     FIXME("\n");
1054     return E_NOTIMPL;
1055 }
1056
1057
1058 BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
1059 {
1060     UINT len, blen = SysStringLen( bstr );
1061     LPSTR str;
1062
1063     len = WideCharToMultiByte( CP_UTF8, 0, bstr, blen, NULL, 0, NULL, NULL );
1064     str = HeapAlloc( GetProcessHeap(), 0, len );
1065     if ( !str )
1066         return FALSE;
1067     WideCharToMultiByte( CP_UTF8, 0, bstr, blen, str, len, NULL, NULL );
1068     *plen = len;
1069     *pstr = str;
1070     return TRUE;
1071 }
1072
1073 static HRESULT WINAPI domdoc_loadXML(
1074     IXMLDOMDocument *iface,
1075     BSTR bstrXML,
1076     VARIANT_BOOL* isSuccessful )
1077 {
1078     domdoc *This = impl_from_IXMLDOMDocument( iface );
1079     xmlDocPtr xmldoc = NULL;
1080     char *str;
1081     int len;
1082     HRESULT hr = S_FALSE;
1083
1084     TRACE("%p %s %p\n", This, debugstr_w( bstrXML ), isSuccessful );
1085
1086     assert ( This->node );
1087
1088     attach_xmlnode( This->node, NULL );
1089
1090     if ( isSuccessful )
1091     {
1092         *isSuccessful = VARIANT_FALSE;
1093
1094         if ( bstrXML  && bstr_to_utf8( bstrXML, &str, &len ) )
1095         {
1096             xmldoc = doparse( str, len );
1097             HeapFree( GetProcessHeap(), 0, str );
1098             if ( !xmldoc )
1099                 This->error = E_FAIL;
1100             else
1101             {
1102                 hr = This->error = S_OK;
1103                 *isSuccessful = VARIANT_TRUE;
1104             }
1105         }
1106     }
1107     if(!xmldoc)
1108         xmldoc = xmlNewDoc(NULL);
1109
1110     xmldoc->_private = 0;
1111     attach_xmlnode( This->node, (xmlNodePtr) xmldoc );
1112
1113     return hr;
1114 }
1115
1116
1117 static HRESULT WINAPI domdoc_save(
1118     IXMLDOMDocument *iface,
1119     VARIANT destination )
1120 {
1121     domdoc *This = impl_from_IXMLDOMDocument( iface );
1122     HANDLE handle;
1123     xmlChar *mem;
1124     int size;
1125     HRESULT ret = S_OK;
1126     DWORD written;
1127
1128     TRACE("(%p)->(var(vt %x, %s))\n", This, V_VT(&destination),
1129           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
1130
1131     if(V_VT(&destination) != VT_BSTR)
1132     {
1133         FIXME("Unhandled vt %x\n", V_VT(&destination));
1134         return S_FALSE;
1135     }
1136
1137     handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
1138                           NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1139     if( handle == INVALID_HANDLE_VALUE )
1140     {
1141         WARN("failed to create file\n");
1142         return S_FALSE;
1143     }
1144
1145     xmlDocDumpMemory(get_doc(This), &mem, &size);
1146     if(!WriteFile(handle, mem, (DWORD)size, &written, NULL) || written != (DWORD)size)
1147     {
1148         WARN("write error\n");
1149         ret = S_FALSE;
1150     }
1151
1152     xmlFree(mem);
1153     CloseHandle(handle);
1154     return ret;
1155 }
1156
1157 static HRESULT WINAPI domdoc_get_validateOnParse(
1158     IXMLDOMDocument *iface,
1159     VARIANT_BOOL* isValidating )
1160 {
1161     FIXME("\n");
1162     return E_NOTIMPL;
1163 }
1164
1165
1166 static HRESULT WINAPI domdoc_put_validateOnParse(
1167     IXMLDOMDocument *iface,
1168     VARIANT_BOOL isValidating )
1169 {
1170     FIXME("\n");
1171     return E_NOTIMPL;
1172 }
1173
1174
1175 static HRESULT WINAPI domdoc_get_resolveExternals(
1176     IXMLDOMDocument *iface,
1177     VARIANT_BOOL* isResolving )
1178 {
1179     FIXME("\n");
1180     return E_NOTIMPL;
1181 }
1182
1183
1184 static HRESULT WINAPI domdoc_put_resolveExternals(
1185     IXMLDOMDocument *iface,
1186     VARIANT_BOOL isValidating )
1187 {
1188     FIXME("\n");
1189     return E_NOTIMPL;
1190 }
1191
1192
1193 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
1194     IXMLDOMDocument *iface,
1195     VARIANT_BOOL* isPreserving )
1196 {
1197     FIXME("\n");
1198     return E_NOTIMPL;
1199 }
1200
1201
1202 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
1203     IXMLDOMDocument *iface,
1204     VARIANT_BOOL isPreserving )
1205 {
1206     FIXME("\n");
1207     return E_NOTIMPL;
1208 }
1209
1210
1211 static HRESULT WINAPI domdoc_put_onReadyStateChange(
1212     IXMLDOMDocument *iface,
1213     VARIANT readyStateChangeSink )
1214 {
1215     FIXME("\n");
1216     return E_NOTIMPL;
1217 }
1218
1219
1220 static HRESULT WINAPI domdoc_put_onDataAvailable(
1221     IXMLDOMDocument *iface,
1222     VARIANT onDataAvailableSink )
1223 {
1224     FIXME("\n");
1225     return E_NOTIMPL;
1226 }
1227
1228 static HRESULT WINAPI domdoc_put_onTransformNode(
1229     IXMLDOMDocument *iface,
1230     VARIANT onTransformNodeSink )
1231 {
1232     FIXME("\n");
1233     return E_NOTIMPL;
1234 }
1235
1236 const struct IXMLDOMDocumentVtbl domdoc_vtbl =
1237 {
1238     domdoc_QueryInterface,
1239     domdoc_AddRef,
1240     domdoc_Release,
1241     domdoc_GetTypeInfoCount,
1242     domdoc_GetTypeInfo,
1243     domdoc_GetIDsOfNames,
1244     domdoc_Invoke,
1245     domdoc_get_nodeName,
1246     domdoc_get_nodeValue,
1247     domdoc_put_nodeValue,
1248     domdoc_get_nodeType,
1249     domdoc_get_parentNode,
1250     domdoc_get_childNodes,
1251     domdoc_get_firstChild,
1252     domdoc_get_lastChild,
1253     domdoc_get_previousSibling,
1254     domdoc_get_nextSibling,
1255     domdoc_get_attributes,
1256     domdoc_insertBefore,
1257     domdoc_replaceChild,
1258     domdoc_removeChild,
1259     domdoc_appendChild,
1260     domdoc_hasChildNodes,
1261     domdoc_get_ownerDocument,
1262     domdoc_cloneNode,
1263     domdoc_get_nodeTypeString,
1264     domdoc_get_text,
1265     domdoc_put_text,
1266     domdoc_get_specified,
1267     domdoc_get_definition,
1268     domdoc_get_nodeTypedValue,
1269     domdoc_put_nodeTypedValue,
1270     domdoc_get_dataType,
1271     domdoc_put_dataType,
1272     domdoc_get_xml,
1273     domdoc_transformNode,
1274     domdoc_selectNodes,
1275     domdoc_selectSingleNode,
1276     domdoc_get_parsed,
1277     domdoc_get_namespaceURI,
1278     domdoc_get_prefix,
1279     domdoc_get_baseName,
1280     domdoc_transformNodeToObject,
1281     domdoc_get_doctype,
1282     domdoc_get_implementation,
1283     domdoc_get_documentElement,
1284     domdoc_documentElement,
1285     domdoc_createElement,
1286     domdoc_createDocumentFragment,
1287     domdoc_createTextNode,
1288     domdoc_createComment,
1289     domdoc_createCDATASection,
1290     domdoc_createProcessingInstruction,
1291     domdoc_createAttribute,
1292     domdoc_createEntityReference,
1293     domdoc_getElementsByTagName,
1294     domdoc_createNode,
1295     domdoc_nodeFromID,
1296     domdoc_load,
1297     domdoc_get_readyState,
1298     domdoc_get_parseError,
1299     domdoc_get_url,
1300     domdoc_get_async,
1301     domdoc_put_async,
1302     domdoc_abort,
1303     domdoc_loadXML,
1304     domdoc_save,
1305     domdoc_get_validateOnParse,
1306     domdoc_put_validateOnParse,
1307     domdoc_get_resolveExternals,
1308     domdoc_put_resolveExternals,
1309     domdoc_get_preserveWhiteSpace,
1310     domdoc_put_preserveWhiteSpace,
1311     domdoc_put_onReadyStateChange,
1312     domdoc_put_onDataAvailable,
1313     domdoc_put_onTransformNode,
1314 };
1315
1316 HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
1317 {
1318     domdoc *doc;
1319     HRESULT hr;
1320     xmlDocPtr xmldoc;
1321
1322     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1323
1324     doc = HeapAlloc( GetProcessHeap(), 0, sizeof (*doc) );
1325     if( !doc )
1326         return E_OUTOFMEMORY;
1327
1328     doc->lpVtbl = &domdoc_vtbl;
1329     doc->ref = 1;
1330     doc->async = 0;
1331     doc->error = S_OK;
1332
1333     xmldoc = xmlNewDoc(NULL);
1334     if(!xmldoc)
1335     {
1336         HeapFree(GetProcessHeap(), 0, doc);
1337         return E_OUTOFMEMORY;
1338     }
1339
1340     xmldoc->_private = 0;
1341
1342     doc->node_unk = create_basic_node( (xmlNodePtr)xmldoc, (IUnknown*)&doc->lpVtbl );
1343     if(!doc->node_unk)
1344     {
1345         xmlFreeDoc(xmldoc);
1346         HeapFree(GetProcessHeap(), 0, doc);
1347         return E_FAIL;
1348     }
1349
1350     hr = IUnknown_QueryInterface(doc->node_unk, &IID_IXMLDOMNode, (LPVOID*)&doc->node);
1351     if(FAILED(hr))
1352     {
1353         IUnknown_Release(doc->node_unk);
1354         HeapFree( GetProcessHeap(), 0, doc );
1355         return E_FAIL;
1356     }
1357     /* The ref on doc->node is actually looped back into this object, so release it */
1358     IXMLDOMNode_Release(doc->node);
1359
1360     *ppObj = &doc->lpVtbl;
1361
1362     TRACE("returning iface %p\n", *ppObj);
1363     return S_OK;
1364 }
1365
1366 #else
1367
1368 HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
1369 {
1370     MESSAGE("This program tried to use a DOMDocument object, but\n"
1371             "libxml2 support was not present at compile time.\n");
1372     return E_NOTIMPL;
1373 }
1374
1375 #endif