[MSXML3]
[reactos.git] / reactos / dll / win32 / msxml3 / xmldoc.c
1 /*
2 * XML Document implementation
3 *
4 * Copyright 2007 James Hawkins
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 #include "precomp.h"
22
23 #include <wininet.h>
24 #include <winreg.h>
25 #include <shlwapi.h>
26
27 #ifdef HAVE_LIBXML2
28
29 /* FIXME: IXMLDocument needs to implement
30 * - IXMLError
31 * - IPersistMoniker
32 */
33
34 typedef struct _xmldoc
35 {
36 IXMLDocument IXMLDocument_iface;
37 IPersistStreamInit IPersistStreamInit_iface;
38 LONG ref;
39 HRESULT error;
40
41 /* IXMLDocument */
42 xmlDocPtr xmldoc;
43
44 /* IPersistStream */
45 IStream *stream;
46 } xmldoc;
47
48 static inline xmldoc *impl_from_IXMLDocument(IXMLDocument *iface)
49 {
50 return CONTAINING_RECORD(iface, xmldoc, IXMLDocument_iface);
51 }
52
53 static inline xmldoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
54 {
55 return CONTAINING_RECORD(iface, xmldoc, IPersistStreamInit_iface);
56 }
57
58 static HRESULT WINAPI xmldoc_QueryInterface(IXMLDocument *iface, REFIID riid, void** ppvObject)
59 {
60 xmldoc *This = impl_from_IXMLDocument(iface);
61
62 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
63
64 if (IsEqualGUID(riid, &IID_IUnknown) ||
65 IsEqualGUID(riid, &IID_IDispatch) ||
66 IsEqualGUID(riid, &IID_IXMLDocument))
67 {
68 *ppvObject = iface;
69 }
70 else if (IsEqualGUID(&IID_IPersistStreamInit, riid) ||
71 IsEqualGUID(&IID_IPersistStream, riid))
72 {
73 *ppvObject = &This->IPersistStreamInit_iface;
74 }
75 else
76 {
77 FIXME("interface %s not implemented\n", debugstr_guid(riid));
78 *ppvObject = NULL;
79 return E_NOINTERFACE;
80 }
81
82 IXMLDocument_AddRef(iface);
83
84 return S_OK;
85 }
86
87 static ULONG WINAPI xmldoc_AddRef(IXMLDocument *iface)
88 {
89 xmldoc *This = impl_from_IXMLDocument(iface);
90 ULONG ref = InterlockedIncrement(&This->ref);
91 TRACE("(%p)->(%d)\n", This, ref);
92 return ref;
93 }
94
95 static ULONG WINAPI xmldoc_Release(IXMLDocument *iface)
96 {
97 xmldoc *This = impl_from_IXMLDocument(iface);
98 LONG ref = InterlockedDecrement(&This->ref);
99
100 TRACE("(%p)->(%d)\n", This, ref);
101
102 if (ref == 0)
103 {
104 xmlFreeDoc(This->xmldoc);
105 if (This->stream) IStream_Release(This->stream);
106 heap_free(This);
107 }
108
109 return ref;
110 }
111
112 static HRESULT WINAPI xmldoc_GetTypeInfoCount(IXMLDocument *iface, UINT* pctinfo)
113 {
114 xmldoc *This = impl_from_IXMLDocument(iface);
115
116 TRACE("(%p)->(%p)\n", This, pctinfo);
117
118 *pctinfo = 1;
119
120 return S_OK;
121 }
122
123 static HRESULT WINAPI xmldoc_GetTypeInfo(IXMLDocument *iface, UINT iTInfo,
124 LCID lcid, ITypeInfo** ppTInfo)
125 {
126 xmldoc *This = impl_from_IXMLDocument(iface);
127
128 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
129
130 return get_typeinfo(IXMLDocument_tid, ppTInfo);
131 }
132
133 static HRESULT WINAPI xmldoc_GetIDsOfNames(IXMLDocument *iface, REFIID riid,
134 LPOLESTR* rgszNames, UINT cNames,
135 LCID lcid, DISPID* rgDispId)
136 {
137 xmldoc *This = impl_from_IXMLDocument(iface);
138 ITypeInfo *typeinfo;
139 HRESULT hr;
140
141 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
142 lcid, rgDispId);
143
144 if(!rgszNames || cNames == 0 || !rgDispId)
145 return E_INVALIDARG;
146
147 hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
148 if(SUCCEEDED(hr))
149 {
150 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
151 ITypeInfo_Release(typeinfo);
152 }
153
154 return hr;
155 }
156
157 static HRESULT WINAPI xmldoc_Invoke(IXMLDocument *iface, DISPID dispIdMember,
158 REFIID riid, LCID lcid, WORD wFlags,
159 DISPPARAMS* pDispParams, VARIANT* pVarResult,
160 EXCEPINFO* pExcepInfo, UINT* puArgErr)
161 {
162 xmldoc *This = impl_from_IXMLDocument(iface);
163 ITypeInfo *typeinfo;
164 HRESULT hr;
165
166 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
167 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
168
169 hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
170 if(SUCCEEDED(hr))
171 {
172 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDocument_iface, dispIdMember, wFlags,
173 pDispParams, pVarResult, pExcepInfo, puArgErr);
174 ITypeInfo_Release(typeinfo);
175 }
176
177 return hr;
178 }
179
180 static HRESULT WINAPI xmldoc_get_root(IXMLDocument *iface, IXMLElement **p)
181 {
182 xmldoc *This = impl_from_IXMLDocument(iface);
183 xmlNodePtr root;
184
185 TRACE("(%p, %p)\n", iface, p);
186
187 if (!p)
188 return E_INVALIDARG;
189
190 *p = NULL;
191
192 if (!(root = xmlDocGetRootElement(This->xmldoc)))
193 return E_FAIL;
194
195 return XMLElement_create((IUnknown *)This, root, (LPVOID *)p, FALSE);
196 }
197
198 static HRESULT WINAPI xmldoc_get_fileSize(IXMLDocument *iface, BSTR *p)
199 {
200 FIXME("(%p, %p): stub\n", iface, p);
201 return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI xmldoc_put_fileModifiedDate(IXMLDocument *iface, BSTR *p)
205 {
206 FIXME("(%p, %p): stub\n", iface, p);
207 return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI xmldoc_get_fileUpdatedDate(IXMLDocument *iface, BSTR *p)
211 {
212 FIXME("(%p, %p): stub\n", iface, p);
213 return E_NOTIMPL;
214 }
215
216 static HRESULT WINAPI xmldoc_get_URL(IXMLDocument *iface, BSTR *p)
217 {
218 FIXME("(%p, %p): stub\n", iface, p);
219 return E_NOTIMPL;
220 }
221
222 typedef struct {
223 IBindStatusCallback IBindStatusCallback_iface;
224 } bsc;
225
226 static HRESULT WINAPI bsc_QueryInterface(
227 IBindStatusCallback *iface,
228 REFIID riid,
229 LPVOID *ppobj )
230 {
231 if (IsEqualGUID(riid, &IID_IUnknown) ||
232 IsEqualGUID(riid, &IID_IBindStatusCallback))
233 {
234 IBindStatusCallback_AddRef( iface );
235 *ppobj = iface;
236 return S_OK;
237 }
238
239 TRACE("interface %s not implemented\n", debugstr_guid(riid));
240 return E_NOINTERFACE;
241 }
242
243 static ULONG WINAPI bsc_AddRef(
244 IBindStatusCallback *iface )
245 {
246 return 2;
247 }
248
249 static ULONG WINAPI bsc_Release(
250 IBindStatusCallback *iface )
251 {
252 return 1;
253 }
254
255 static HRESULT WINAPI bsc_OnStartBinding(
256 IBindStatusCallback* iface,
257 DWORD dwReserved,
258 IBinding* pib)
259 {
260 return S_OK;
261 }
262
263 static HRESULT WINAPI bsc_GetPriority(
264 IBindStatusCallback* iface,
265 LONG* pnPriority)
266 {
267 return S_OK;
268 }
269
270 static HRESULT WINAPI bsc_OnLowResource(
271 IBindStatusCallback* iface,
272 DWORD reserved)
273 {
274 return S_OK;
275 }
276
277 static HRESULT WINAPI bsc_OnProgress(
278 IBindStatusCallback* iface,
279 ULONG ulProgress,
280 ULONG ulProgressMax,
281 ULONG ulStatusCode,
282 LPCWSTR szStatusText)
283 {
284 return S_OK;
285 }
286
287 static HRESULT WINAPI bsc_OnStopBinding(
288 IBindStatusCallback* iface,
289 HRESULT hresult,
290 LPCWSTR szError)
291 {
292 return S_OK;
293 }
294
295 static HRESULT WINAPI bsc_GetBindInfo(
296 IBindStatusCallback* iface,
297 DWORD* grfBINDF,
298 BINDINFO* pbindinfo)
299 {
300 *grfBINDF = BINDF_RESYNCHRONIZE;
301
302 return S_OK;
303 }
304
305 static HRESULT WINAPI bsc_OnDataAvailable(
306 IBindStatusCallback* iface,
307 DWORD grfBSCF,
308 DWORD dwSize,
309 FORMATETC* pformatetc,
310 STGMEDIUM* pstgmed)
311 {
312 return S_OK;
313 }
314
315 static HRESULT WINAPI bsc_OnObjectAvailable(
316 IBindStatusCallback* iface,
317 REFIID riid,
318 IUnknown* punk)
319 {
320 return S_OK;
321 }
322
323 static const struct IBindStatusCallbackVtbl bsc_vtbl =
324 {
325 bsc_QueryInterface,
326 bsc_AddRef,
327 bsc_Release,
328 bsc_OnStartBinding,
329 bsc_GetPriority,
330 bsc_OnLowResource,
331 bsc_OnProgress,
332 bsc_OnStopBinding,
333 bsc_GetBindInfo,
334 bsc_OnDataAvailable,
335 bsc_OnObjectAvailable
336 };
337
338 static bsc xmldoc_bsc = { { &bsc_vtbl } };
339
340 static HRESULT WINAPI xmldoc_put_URL(IXMLDocument *iface, BSTR p)
341 {
342 WCHAR url[INTERNET_MAX_URL_LENGTH];
343 IStream *stream;
344 IBindCtx *bctx;
345 IMoniker *moniker;
346 IPersistStreamInit *persist;
347 HRESULT hr;
348
349 TRACE("(%p, %s)\n", iface, debugstr_w(p));
350
351 if (!p)
352 return E_INVALIDARG;
353
354 if (!PathIsURLW(p))
355 {
356 WCHAR fullpath[MAX_PATH];
357 DWORD needed = sizeof(url) / sizeof(WCHAR);
358
359 if (!PathSearchAndQualifyW(p, fullpath, sizeof(fullpath) / sizeof(WCHAR)))
360 {
361 ERR("can't find path\n");
362 return E_FAIL;
363 }
364
365 if (FAILED(UrlCreateFromPathW(fullpath, url, &needed, 0)))
366 {
367 ERR("can't create url from path\n");
368 return E_FAIL;
369 }
370
371 p = url;
372 }
373
374 hr = CreateURLMoniker(NULL, p, &moniker);
375 if (FAILED(hr))
376 return hr;
377
378 CreateAsyncBindCtx(0, &xmldoc_bsc.IBindStatusCallback_iface, 0, &bctx);
379
380 hr = IMoniker_BindToStorage(moniker, bctx, NULL, &IID_IStream, (LPVOID *)&stream);
381 IBindCtx_Release(bctx);
382 IMoniker_Release(moniker);
383 if (FAILED(hr))
384 return hr;
385
386 hr = IXMLDocument_QueryInterface(iface, &IID_IPersistStreamInit, (LPVOID *)&persist);
387 if (FAILED(hr))
388 {
389 IStream_Release(stream);
390 return hr;
391 }
392
393 hr = IPersistStreamInit_Load(persist, stream);
394 IPersistStreamInit_Release(persist);
395 IStream_Release(stream);
396
397 return hr;
398 }
399
400 static HRESULT WINAPI xmldoc_get_mimeType(IXMLDocument *iface, BSTR *p)
401 {
402 FIXME("(%p, %p): stub\n", iface, p);
403 return E_NOTIMPL;
404 }
405
406 static HRESULT WINAPI xmldoc_get_readyState(IXMLDocument *iface, LONG *p)
407 {
408 FIXME("(%p, %p): stub\n", iface, p);
409 return E_NOTIMPL;
410 }
411
412 static HRESULT WINAPI xmldoc_get_charset(IXMLDocument *iface, BSTR *p)
413 {
414 FIXME("(%p, %p): stub\n", iface, p);
415 return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI xmldoc_put_charset(IXMLDocument *iface, BSTR p)
419 {
420 FIXME("(%p, %p): stub\n", iface, p);
421 return E_NOTIMPL;
422 }
423
424 static HRESULT WINAPI xmldoc_get_version(IXMLDocument *iface, BSTR *p)
425 {
426 xmldoc *This = impl_from_IXMLDocument(iface);
427
428 TRACE("(%p, %p)\n", This, p);
429
430 if (!p) return E_INVALIDARG;
431 *p = bstr_from_xmlChar(This->xmldoc->version);
432
433 return S_OK;
434 }
435
436 static HRESULT WINAPI xmldoc_get_doctype(IXMLDocument *iface, BSTR *p)
437 {
438 xmldoc *This = impl_from_IXMLDocument(iface);
439 xmlDtd *dtd;
440
441 TRACE("(%p, %p)\n", This, p);
442
443 if (!p) return E_INVALIDARG;
444
445 dtd = xmlGetIntSubset(This->xmldoc);
446 if (!dtd) return S_FALSE;
447
448 *p = bstr_from_xmlChar(dtd->name);
449 CharUpperBuffW(*p, SysStringLen(*p));
450
451 return S_OK;
452 }
453
454 static HRESULT WINAPI xmldoc_get_dtdURl(IXMLDocument *iface, BSTR *p)
455 {
456 FIXME("(%p, %p): stub\n", iface, p);
457 return E_NOTIMPL;
458 }
459
460 static xmlElementType type_msxml_to_libxml(LONG type)
461 {
462 switch (type)
463 {
464 case XMLELEMTYPE_ELEMENT:
465 return XML_ELEMENT_NODE;
466 case XMLELEMTYPE_TEXT:
467 return XML_TEXT_NODE;
468 case XMLELEMTYPE_COMMENT:
469 return XML_COMMENT_NODE;
470 case XMLELEMTYPE_DOCUMENT:
471 return XML_DOCUMENT_NODE;
472 case XMLELEMTYPE_DTD:
473 return XML_DTD_NODE;
474 case XMLELEMTYPE_PI:
475 return XML_PI_NODE;
476 default:
477 break;
478 }
479
480 return -1; /* FIXME: what is OTHER in msxml? */
481 }
482
483 static HRESULT WINAPI xmldoc_createElement(IXMLDocument *iface, VARIANT vType,
484 VARIANT var1, IXMLElement **ppElem)
485 {
486 xmlNodePtr node;
487 static const xmlChar empty[] = "\0";
488
489 TRACE("(%p)->(%s %s %p)\n", iface, debugstr_variant(&vType),
490 debugstr_variant(&var1), ppElem);
491
492 if (!ppElem)
493 return E_INVALIDARG;
494
495 *ppElem = NULL;
496
497 if (V_VT(&vType) != VT_I4)
498 return E_INVALIDARG;
499
500 if(type_msxml_to_libxml(V_I4(&vType)) == -1)
501 return E_NOTIMPL;
502
503 node = xmlNewNode(NULL, empty);
504 node->type = type_msxml_to_libxml(V_I4(&vType));
505
506 /* FIXME: create xmlNodePtr based on vType and var1 */
507 return XMLElement_create((IUnknown *)iface, node, (LPVOID *)ppElem, TRUE);
508 }
509
510 static const struct IXMLDocumentVtbl xmldoc_vtbl =
511 {
512 xmldoc_QueryInterface,
513 xmldoc_AddRef,
514 xmldoc_Release,
515 xmldoc_GetTypeInfoCount,
516 xmldoc_GetTypeInfo,
517 xmldoc_GetIDsOfNames,
518 xmldoc_Invoke,
519 xmldoc_get_root,
520 xmldoc_get_fileSize,
521 xmldoc_put_fileModifiedDate,
522 xmldoc_get_fileUpdatedDate,
523 xmldoc_get_URL,
524 xmldoc_put_URL,
525 xmldoc_get_mimeType,
526 xmldoc_get_readyState,
527 xmldoc_get_charset,
528 xmldoc_put_charset,
529 xmldoc_get_version,
530 xmldoc_get_doctype,
531 xmldoc_get_dtdURl,
532 xmldoc_createElement
533 };
534
535 /************************************************************************
536 * xmldoc implementation of IPersistStreamInit.
537 */
538 static HRESULT WINAPI xmldoc_IPersistStreamInit_QueryInterface(
539 IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj)
540 {
541 xmldoc *this = impl_from_IPersistStreamInit(iface);
542 return IXMLDocument_QueryInterface(&this->IXMLDocument_iface, riid, ppvObj);
543 }
544
545 static ULONG WINAPI xmldoc_IPersistStreamInit_AddRef(
546 IPersistStreamInit *iface)
547 {
548 xmldoc *this = impl_from_IPersistStreamInit(iface);
549 return IXMLDocument_AddRef(&this->IXMLDocument_iface);
550 }
551
552 static ULONG WINAPI xmldoc_IPersistStreamInit_Release(
553 IPersistStreamInit *iface)
554 {
555 xmldoc *this = impl_from_IPersistStreamInit(iface);
556 return IXMLDocument_Release(&this->IXMLDocument_iface);
557 }
558
559 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetClassID(
560 IPersistStreamInit *iface, CLSID *classid)
561 {
562 xmldoc *this = impl_from_IPersistStreamInit(iface);
563 TRACE("(%p,%p)\n", this, classid);
564
565 if (!classid) return E_POINTER;
566
567 *classid = CLSID_XMLDocument;
568 return S_OK;
569 }
570
571 static HRESULT WINAPI xmldoc_IPersistStreamInit_IsDirty(
572 IPersistStreamInit *iface)
573 {
574 FIXME("(%p): stub!\n", iface);
575 return E_NOTIMPL;
576 }
577
578 static xmlDocPtr parse_xml(char *ptr, int len)
579 {
580 #ifdef HAVE_XMLREADMEMORY
581 return xmlReadMemory(ptr, len, NULL, NULL,
582 XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS);
583 #else
584 return xmlParseMemory(ptr, len);
585 #endif
586 }
587
588 static HRESULT WINAPI xmldoc_IPersistStreamInit_Load(
589 IPersistStreamInit *iface, LPSTREAM pStm)
590 {
591 xmldoc *This = impl_from_IPersistStreamInit(iface);
592 HRESULT hr;
593 HGLOBAL hglobal;
594 DWORD read, written, len;
595 BYTE buf[4096];
596 char *ptr;
597
598 TRACE("(%p, %p)\n", iface, pStm);
599
600 if (!pStm)
601 return E_INVALIDARG;
602
603 /* release previously allocated stream */
604 if (This->stream) IStream_Release(This->stream);
605 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
606 if (FAILED(hr))
607 return hr;
608
609 do
610 {
611 IStream_Read(pStm, buf, sizeof(buf), &read);
612 hr = IStream_Write(This->stream, buf, read, &written);
613 } while(SUCCEEDED(hr) && written != 0 && read != 0);
614
615 if (FAILED(hr))
616 {
617 ERR("Failed to copy stream\n");
618 return hr;
619 }
620
621 hr = GetHGlobalFromStream(This->stream, &hglobal);
622 if (FAILED(hr))
623 return hr;
624
625 len = GlobalSize(hglobal);
626 ptr = GlobalLock(hglobal);
627 if (len != 0)
628 {
629 xmlFreeDoc(This->xmldoc);
630 This->xmldoc = parse_xml(ptr, len);
631 }
632 GlobalUnlock(hglobal);
633
634 if (!This->xmldoc)
635 {
636 ERR("Failed to parse xml\n");
637 return E_FAIL;
638 }
639
640 return S_OK;
641 }
642
643 static HRESULT WINAPI xmldoc_IPersistStreamInit_Save(
644 IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty)
645 {
646 FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty);
647 return E_NOTIMPL;
648 }
649
650 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetSizeMax(
651 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
652 {
653 xmldoc *This = impl_from_IPersistStreamInit(iface);
654 TRACE("(%p, %p)\n", This, pcbSize);
655 return E_NOTIMPL;
656 }
657
658 static HRESULT WINAPI xmldoc_IPersistStreamInit_InitNew(
659 IPersistStreamInit *iface)
660 {
661 xmldoc *This = impl_from_IPersistStreamInit(iface);
662 TRACE("(%p)\n", This);
663 return S_OK;
664 }
665
666 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
667 {
668 xmldoc_IPersistStreamInit_QueryInterface,
669 xmldoc_IPersistStreamInit_AddRef,
670 xmldoc_IPersistStreamInit_Release,
671 xmldoc_IPersistStreamInit_GetClassID,
672 xmldoc_IPersistStreamInit_IsDirty,
673 xmldoc_IPersistStreamInit_Load,
674 xmldoc_IPersistStreamInit_Save,
675 xmldoc_IPersistStreamInit_GetSizeMax,
676 xmldoc_IPersistStreamInit_InitNew
677 };
678
679 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
680 {
681 xmldoc *doc;
682
683 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
684
685 doc = heap_alloc(sizeof (*doc));
686 if(!doc)
687 return E_OUTOFMEMORY;
688
689 doc->IXMLDocument_iface.lpVtbl = &xmldoc_vtbl;
690 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
691 doc->ref = 1;
692 doc->error = S_OK;
693 doc->xmldoc = NULL;
694 doc->stream = NULL;
695
696 *ppObj = &doc->IXMLDocument_iface;
697
698 TRACE("returning iface %p\n", *ppObj);
699 return S_OK;
700 }
701
702 #else
703
704 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
705 {
706 MESSAGE("This program tried to use an XMLDocument object, but\n"
707 "libxml2 support was not present at compile time.\n");
708 return E_NOTIMPL;
709 }
710
711 #endif