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