wined3d: Get rid of wined3d_buffer_get_desc().
[wine] / dlls / msxml3 / queryresult.c
1 /*
2  *    XPath/XSLPattern query result node list implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2007 Mikolaj Zalewski
6  * Copyright 2010 Adam Martinson for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define COBJMACROS
24
25 #include "config.h"
26
27 #include <stdarg.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpath.h>
32 # include <libxml/xpathInternals.h>
33 #endif
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winuser.h"
38 #include "ole2.h"
39 #include "msxml6.h"
40
41 #include "msxml_private.h"
42
43 #include "wine/debug.h"
44
45 /* This file implements the object returned by a XPath query. Note that this is
46  * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
47  * They are different because the list returned by XPath queries:
48  *  - is static - gives the results for the XML tree as it existed during the
49  *    execution of the query
50  *  - supports IXMLDOMSelection (TODO)
51  *
52  */
53
54 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
55
56 #ifdef HAVE_LIBXML2
57
58 int registerNamespaces(xmlXPathContextPtr ctxt);
59 xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
60
61 typedef struct _queryresult
62 {
63     DispatchEx dispex;
64     const struct IXMLDOMNodeListVtbl *lpVtbl;
65     LONG ref;
66     xmlNodePtr node;
67     xmlXPathObjectPtr result;
68     int resultPos;
69 } queryresult;
70
71 static inline queryresult *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
72 {
73     return (queryresult *)((char*)iface - FIELD_OFFSET(queryresult, lpVtbl));
74 }
75
76 #define XMLQUERYRES(x)  ((IXMLDOMNodeList*)&(x)->lpVtbl)
77
78 static HRESULT WINAPI queryresult_QueryInterface(
79     IXMLDOMNodeList *iface,
80     REFIID riid,
81     void** ppvObject )
82 {
83     queryresult *This = impl_from_IXMLDOMNodeList( iface );
84
85     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
86
87     if(!ppvObject)
88         return E_INVALIDARG;
89
90     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
91          IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
92     {
93         *ppvObject = iface;
94     }
95     else if(dispex_query_interface(&This->dispex, riid, ppvObject))
96     {
97         return *ppvObject ? S_OK : E_NOINTERFACE;
98     }
99     else
100     {
101         FIXME("interface %s not implemented\n", debugstr_guid(riid));
102         *ppvObject = NULL;
103         return E_NOINTERFACE;
104     }
105
106     IXMLDOMNodeList_AddRef( iface );
107
108     return S_OK;
109 }
110
111 static ULONG WINAPI queryresult_AddRef(
112     IXMLDOMNodeList *iface )
113 {
114     queryresult *This = impl_from_IXMLDOMNodeList( iface );
115     return InterlockedIncrement( &This->ref );
116 }
117
118 static ULONG WINAPI queryresult_Release(
119     IXMLDOMNodeList *iface )
120 {
121     queryresult *This = impl_from_IXMLDOMNodeList( iface );
122     ULONG ref;
123
124     ref = InterlockedDecrement(&This->ref);
125     if ( ref == 0 )
126     {
127         xmlXPathFreeObject(This->result);
128         xmldoc_release(This->node->doc);
129         heap_free(This);
130     }
131
132     return ref;
133 }
134
135 static HRESULT WINAPI queryresult_GetTypeInfoCount(
136     IXMLDOMNodeList *iface,
137     UINT* pctinfo )
138 {
139     queryresult *This = impl_from_IXMLDOMNodeList( iface );
140
141     TRACE("(%p)->(%p)\n", This, pctinfo);
142
143     *pctinfo = 1;
144
145     return S_OK;
146 }
147
148 static HRESULT WINAPI queryresult_GetTypeInfo(
149     IXMLDOMNodeList *iface,
150     UINT iTInfo,
151     LCID lcid,
152     ITypeInfo** ppTInfo )
153 {
154     queryresult *This = impl_from_IXMLDOMNodeList( iface );
155     HRESULT hr;
156
157     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
158
159     hr = get_typeinfo(IXMLDOMNodeList_tid, ppTInfo);
160
161     return hr;
162 }
163
164 static HRESULT WINAPI queryresult_GetIDsOfNames(
165     IXMLDOMNodeList *iface,
166     REFIID riid,
167     LPOLESTR* rgszNames,
168     UINT cNames,
169     LCID lcid,
170     DISPID* rgDispId )
171 {
172     queryresult *This = impl_from_IXMLDOMNodeList( iface );
173     ITypeInfo *typeinfo;
174     HRESULT hr;
175
176     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
177           lcid, rgDispId);
178
179     if(!rgszNames || cNames == 0 || !rgDispId)
180         return E_INVALIDARG;
181
182     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
183     if(SUCCEEDED(hr))
184     {
185         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
186         ITypeInfo_Release(typeinfo);
187     }
188
189     return hr;
190 }
191
192 static HRESULT WINAPI queryresult_Invoke(
193     IXMLDOMNodeList *iface,
194     DISPID dispIdMember,
195     REFIID riid,
196     LCID lcid,
197     WORD wFlags,
198     DISPPARAMS* pDispParams,
199     VARIANT* pVarResult,
200     EXCEPINFO* pExcepInfo,
201     UINT* puArgErr )
202 {
203     queryresult *This = impl_from_IXMLDOMNodeList( iface );
204     ITypeInfo *typeinfo;
205     HRESULT hr;
206
207     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
208           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
209
210     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
211     if(SUCCEEDED(hr))
212     {
213         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
214                 pVarResult, pExcepInfo, puArgErr);
215         ITypeInfo_Release(typeinfo);
216     }
217
218     return hr;
219 }
220
221 static HRESULT WINAPI queryresult_get_item(
222         IXMLDOMNodeList* iface,
223         LONG index,
224         IXMLDOMNode** listItem)
225 {
226     queryresult *This = impl_from_IXMLDOMNodeList( iface );
227
228     TRACE("(%p)->(%d %p)\n", This, index, listItem);
229
230     if(!listItem)
231         return E_INVALIDARG;
232
233     *listItem = NULL;
234
235     if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval))
236         return S_FALSE;
237
238     *listItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, index));
239     This->resultPos = index + 1;
240
241     return S_OK;
242 }
243
244 static HRESULT WINAPI queryresult_get_length(
245         IXMLDOMNodeList* iface,
246         LONG* listLength)
247 {
248     queryresult *This = impl_from_IXMLDOMNodeList( iface );
249
250     TRACE("(%p)->(%p)\n", This, listLength);
251
252     if(!listLength)
253         return E_INVALIDARG;
254
255     *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval);
256     return S_OK;
257 }
258
259 static HRESULT WINAPI queryresult_nextNode(
260         IXMLDOMNodeList* iface,
261         IXMLDOMNode** nextItem)
262 {
263     queryresult *This = impl_from_IXMLDOMNodeList( iface );
264
265     TRACE("(%p)->(%p)\n", This, nextItem );
266
267     if(!nextItem)
268         return E_INVALIDARG;
269
270     *nextItem = NULL;
271
272     if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval))
273         return S_FALSE;
274
275     *nextItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, This->resultPos));
276     This->resultPos++;
277     return S_OK;
278 }
279
280 static HRESULT WINAPI queryresult_reset(
281         IXMLDOMNodeList* iface)
282 {
283     queryresult *This = impl_from_IXMLDOMNodeList( iface );
284
285     TRACE("%p\n", This);
286     This->resultPos = 0;
287     return S_OK;
288 }
289
290 static HRESULT WINAPI queryresult__newEnum(
291         IXMLDOMNodeList* iface,
292         IUnknown** ppUnk)
293 {
294     queryresult *This = impl_from_IXMLDOMNodeList( iface );
295     FIXME("(%p)->(%p)\n", This, ppUnk);
296     return E_NOTIMPL;
297 }
298
299
300 static const struct IXMLDOMNodeListVtbl queryresult_vtbl =
301 {
302     queryresult_QueryInterface,
303     queryresult_AddRef,
304     queryresult_Release,
305     queryresult_GetTypeInfoCount,
306     queryresult_GetTypeInfo,
307     queryresult_GetIDsOfNames,
308     queryresult_Invoke,
309     queryresult_get_item,
310     queryresult_get_length,
311     queryresult_nextNode,
312     queryresult_reset,
313     queryresult__newEnum,
314 };
315
316 static HRESULT queryresult_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
317 {
318     queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
319     WCHAR *ptr;
320     int idx = 0;
321
322     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
323         idx = idx*10 + (*ptr-'0');
324     if(*ptr)
325         return DISP_E_UNKNOWNNAME;
326
327     if(idx >= xmlXPathNodeSetGetLength(This->result->nodesetval))
328         return DISP_E_UNKNOWNNAME;
329
330     *dispid = MSXML_DISPID_CUSTOM_MIN + idx;
331     TRACE("ret %x\n", *dispid);
332     return S_OK;
333 }
334
335 static HRESULT queryresult_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
336         VARIANT *res, EXCEPINFO *ei)
337 {
338     queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
339
340     TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
341
342     V_VT(res) = VT_DISPATCH;
343     V_DISPATCH(res) = NULL;
344
345     switch(flags)
346     {
347         case INVOKE_PROPERTYGET:
348         {
349             IXMLDOMNode *disp = NULL;
350
351             queryresult_get_item(XMLQUERYRES(This), id - MSXML_DISPID_CUSTOM_MIN, &disp);
352             V_DISPATCH(res) = (IDispatch*)disp;
353             break;
354         }
355         default:
356         {
357             FIXME("unimplemented flags %x\n", flags);
358             break;
359         }
360     }
361
362     TRACE("ret %p\n", V_DISPATCH(res));
363
364     return S_OK;
365 }
366
367 static const dispex_static_data_vtbl_t queryresult_dispex_vtbl = {
368     queryresult_get_dispid,
369     queryresult_invoke
370 };
371
372 static const tid_t queryresult_iface_tids[] = {
373     IXMLDOMNodeList_tid,
374     0
375 };
376 static dispex_static_data_t queryresult_dispex = {
377     &queryresult_dispex_vtbl,
378     IXMLDOMSelection_tid,
379     NULL,
380     queryresult_iface_tids
381 };
382
383 #define XSLPATTERN_CHECK_ARGS(n) \
384     if (nargs != n) { \
385         FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
386         xmlXPathSetArityError(pctx); \
387         return; \
388     }
389
390
391 void XSLPattern_index(xmlXPathParserContextPtr pctx, int nargs)
392 {
393     XSLPATTERN_CHECK_ARGS(0);
394
395     xmlXPathPositionFunction(pctx, 0);
396     xmlXPathReturnNumber(pctx, xmlXPathPopNumber(pctx) - 1.0);
397 }
398
399 void XSLPattern_end(xmlXPathParserContextPtr pctx, int nargs)
400 {
401     double pos, last;
402     XSLPATTERN_CHECK_ARGS(0);
403
404     xmlXPathPositionFunction(pctx, 0);
405     pos = xmlXPathPopNumber(pctx);
406     xmlXPathLastFunction(pctx, 0);
407     last = xmlXPathPopNumber(pctx);
408     xmlXPathReturnBoolean(pctx, pos == last);
409 }
410
411 void XSLPattern_nodeType(xmlXPathParserContextPtr pctx, int nargs)
412 {
413     XSLPATTERN_CHECK_ARGS(0);
414     xmlXPathReturnNumber(pctx, pctx->context->node->type);
415 }
416
417 void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx, int nargs)
418 {
419     xmlChar *arg1, *arg2;
420     XSLPATTERN_CHECK_ARGS(2);
421
422     arg2 = xmlXPathPopString(pctx);
423     arg1 = xmlXPathPopString(pctx);
424     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) == 0);
425     xmlFree(arg1);
426     xmlFree(arg2);
427 }
428
429 void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx, int nargs)
430 {
431     xmlChar *arg1, *arg2;
432     XSLPATTERN_CHECK_ARGS(2);
433
434     arg2 = xmlXPathPopString(pctx);
435     arg1 = xmlXPathPopString(pctx);
436     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) != 0);
437     xmlFree(arg1);
438     xmlFree(arg2);
439 }
440
441 void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx, int nargs)
442 {
443     xmlChar *arg1, *arg2;
444     XSLPATTERN_CHECK_ARGS(2);
445
446     arg2 = xmlXPathPopString(pctx);
447     arg1 = xmlXPathPopString(pctx);
448     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) < 0);
449     xmlFree(arg1);
450     xmlFree(arg2);
451 }
452
453 void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx, int nargs)
454 {
455     xmlChar *arg1, *arg2;
456     XSLPATTERN_CHECK_ARGS(2);
457
458     arg2 = xmlXPathPopString(pctx);
459     arg1 = xmlXPathPopString(pctx);
460     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) <= 0);
461     xmlFree(arg1);
462     xmlFree(arg2);
463 }
464
465 void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx, int nargs)
466 {
467     xmlChar *arg1, *arg2;
468     XSLPATTERN_CHECK_ARGS(2);
469
470     arg2 = xmlXPathPopString(pctx);
471     arg1 = xmlXPathPopString(pctx);
472     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) > 0);
473     xmlFree(arg1);
474     xmlFree(arg2);
475 }
476
477 void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx, int nargs)
478 {
479     xmlChar *arg1, *arg2;
480     XSLPATTERN_CHECK_ARGS(2);
481
482     arg2 = xmlXPathPopString(pctx);
483     arg1 = xmlXPathPopString(pctx);
484     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) >= 0);
485     xmlFree(arg1);
486     xmlFree(arg2);
487 }
488
489 static void query_serror(void* ctx, xmlErrorPtr err)
490 {
491     LIBXML2_CALLBACK_SERROR(queryresult_create, err);
492 }
493
494 HRESULT queryresult_create(xmlNodePtr node, xmlChar* szQuery, IXMLDOMNodeList **out)
495 {
496     queryresult *This = heap_alloc_zero(sizeof(queryresult));
497     xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
498     HRESULT hr;
499
500     TRACE("(%p, %s, %p)\n", node, wine_dbgstr_a((char const*)szQuery), out);
501
502     *out = NULL;
503     if (This == NULL || ctxt == NULL || szQuery == NULL)
504     {
505         hr = E_OUTOFMEMORY;
506         goto cleanup;
507     }
508
509     This->lpVtbl = &queryresult_vtbl;
510     This->ref = 1;
511     This->resultPos = 0;
512     This->node = node;
513     xmldoc_add_ref(This->node->doc);
514
515     ctxt->error = query_serror;
516     ctxt->node = node;
517     registerNamespaces(ctxt);
518
519     if (is_xpathmode(This->node->doc))
520     {
521         xmlXPathRegisterAllFunctions(ctxt);
522         This->result = xmlXPathEvalExpression(szQuery, ctxt);
523     }
524     else
525     {
526         xmlChar* xslpQuery = XSLPattern_to_XPath(ctxt, szQuery);
527
528         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
529         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction);
530
531         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"index", XSLPattern_index);
532         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"end", XSLPattern_end);
533         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"nodeType", XSLPattern_nodeType);
534
535         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IEq", XSLPattern_OP_IEq);
536         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_INEq", XSLPattern_OP_INEq);
537         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILt", XSLPattern_OP_ILt);
538         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq);
539         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
540         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq);
541
542         This->result = xmlXPathEvalExpression(xslpQuery, ctxt);
543         xmlFree(xslpQuery);
544     }
545
546     if (!This->result || This->result->type != XPATH_NODESET)
547     {
548         hr = E_FAIL;
549         goto cleanup;
550     }
551
552     init_dispex(&This->dispex, (IUnknown*)&This->lpVtbl, &queryresult_dispex);
553
554     *out = (IXMLDOMNodeList *) &This->lpVtbl;
555     hr = S_OK;
556     TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
557
558 cleanup:
559     if (This != NULL && FAILED(hr))
560         IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
561     xmlXPathFreeContext(ctxt);
562     return hr;
563 }
564
565 #endif