mshtml: Added IHTMLElement::get_parentElement implementation.
[wine] / dlls / msxml3 / queryresult.c
1 /*
2  *    XPath query result node list implementation (TODO: XSLPattern support)
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2007 Mikolaj Zalewski
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "msxml2.h"
32
33 #include "msxml_private.h"
34
35 #include "wine/debug.h"
36
37 /* This file implements the object returned by a XPath query. Note that this is
38  * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
39  * They are different because the list returned by XPath queries:
40  *  - is static - gives the results for the XML tree as it existed during the
41  *    execution of the query
42  *  - supports IXMLDOMSelection (TODO)
43  *
44  * TODO: XSLPattern support
45  */
46
47 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
48
49 #ifdef HAVE_LIBXML2
50
51 #include <libxml/xpath.h>
52
53 typedef struct _queryresult
54 {
55     DispatchEx dispex;
56     const struct IXMLDOMNodeListVtbl *lpVtbl;
57     LONG ref;
58     xmlNodePtr node;
59     xmlXPathObjectPtr result;
60     int resultPos;
61 } queryresult;
62
63 static inline queryresult *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
64 {
65     return (queryresult *)((char*)iface - FIELD_OFFSET(queryresult, lpVtbl));
66 }
67
68 static HRESULT WINAPI queryresult_QueryInterface(
69     IXMLDOMNodeList *iface,
70     REFIID riid,
71     void** ppvObject )
72 {
73     queryresult *This = impl_from_IXMLDOMNodeList( iface );
74
75     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
76
77     if(!ppvObject)
78         return E_INVALIDARG;
79
80     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
81          IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
82     {
83         *ppvObject = iface;
84     }
85     else if(dispex_query_interface(&This->dispex, riid, ppvObject))
86     {
87         return *ppvObject ? S_OK : E_NOINTERFACE;
88     }
89     else
90     {
91         FIXME("interface %s not implemented\n", debugstr_guid(riid));
92         *ppvObject = NULL;
93         return E_NOINTERFACE;
94     }
95
96     IXMLDOMNodeList_AddRef( iface );
97
98     return S_OK;
99 }
100
101 static ULONG WINAPI queryresult_AddRef(
102     IXMLDOMNodeList *iface )
103 {
104     queryresult *This = impl_from_IXMLDOMNodeList( iface );
105     return InterlockedIncrement( &This->ref );
106 }
107
108 static ULONG WINAPI queryresult_Release(
109     IXMLDOMNodeList *iface )
110 {
111     queryresult *This = impl_from_IXMLDOMNodeList( iface );
112     ULONG ref;
113
114     ref = InterlockedDecrement(&This->ref);
115     if ( ref == 0 )
116     {
117         xmlXPathFreeObject(This->result);
118         xmldoc_release(This->node->doc);
119         heap_free(This);
120     }
121
122     return ref;
123 }
124
125 static HRESULT WINAPI queryresult_GetTypeInfoCount(
126     IXMLDOMNodeList *iface,
127     UINT* pctinfo )
128 {
129     queryresult *This = impl_from_IXMLDOMNodeList( iface );
130
131     TRACE("(%p)->(%p)\n", This, pctinfo);
132
133     *pctinfo = 1;
134
135     return S_OK;
136 }
137
138 static HRESULT WINAPI queryresult_GetTypeInfo(
139     IXMLDOMNodeList *iface,
140     UINT iTInfo,
141     LCID lcid,
142     ITypeInfo** ppTInfo )
143 {
144     queryresult *This = impl_from_IXMLDOMNodeList( iface );
145     HRESULT hr;
146
147     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
148
149     hr = get_typeinfo(IXMLDOMNodeList_tid, ppTInfo);
150
151     return hr;
152 }
153
154 static HRESULT WINAPI queryresult_GetIDsOfNames(
155     IXMLDOMNodeList *iface,
156     REFIID riid,
157     LPOLESTR* rgszNames,
158     UINT cNames,
159     LCID lcid,
160     DISPID* rgDispId )
161 {
162     queryresult *This = impl_from_IXMLDOMNodeList( iface );
163     ITypeInfo *typeinfo;
164     HRESULT hr;
165
166     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
167           lcid, rgDispId);
168
169     if(!rgszNames || cNames == 0 || !rgDispId)
170         return E_INVALIDARG;
171
172     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
173     if(SUCCEEDED(hr))
174     {
175         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
176         ITypeInfo_Release(typeinfo);
177     }
178
179     return hr;
180 }
181
182 static HRESULT WINAPI queryresult_Invoke(
183     IXMLDOMNodeList *iface,
184     DISPID dispIdMember,
185     REFIID riid,
186     LCID lcid,
187     WORD wFlags,
188     DISPPARAMS* pDispParams,
189     VARIANT* pVarResult,
190     EXCEPINFO* pExcepInfo,
191     UINT* puArgErr )
192 {
193     queryresult *This = impl_from_IXMLDOMNodeList( iface );
194     ITypeInfo *typeinfo;
195     HRESULT hr;
196
197     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
198           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
199
200     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
201     if(SUCCEEDED(hr))
202     {
203         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
204                 pVarResult, pExcepInfo, puArgErr);
205         ITypeInfo_Release(typeinfo);
206     }
207
208     return hr;
209 }
210
211 static HRESULT WINAPI queryresult_get_item(
212         IXMLDOMNodeList* iface,
213         long index,
214         IXMLDOMNode** listItem)
215 {
216     queryresult *This = impl_from_IXMLDOMNodeList( iface );
217
218     TRACE("%p %ld\n", This, index);
219
220     if(!listItem)
221         return E_INVALIDARG;
222
223     *listItem = NULL;
224
225     if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval))
226         return S_FALSE;
227
228     *listItem = create_node(This->result->nodesetval->nodeTab[index]);
229     This->resultPos = index + 1;
230
231     return S_OK;
232 }
233
234 static HRESULT WINAPI queryresult_get_length(
235         IXMLDOMNodeList* iface,
236         long* listLength)
237 {
238     queryresult *This = impl_from_IXMLDOMNodeList( iface );
239
240     TRACE("%p\n", This);
241
242     if(!listLength)
243         return E_INVALIDARG;
244
245     *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval);
246     return S_OK;
247 }
248
249 static HRESULT WINAPI queryresult_nextNode(
250         IXMLDOMNodeList* iface,
251         IXMLDOMNode** nextItem)
252 {
253     queryresult *This = impl_from_IXMLDOMNodeList( iface );
254
255     TRACE("%p %p\n", This, nextItem );
256
257     if(!nextItem)
258         return E_INVALIDARG;
259
260     *nextItem = NULL;
261
262     if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval))
263         return S_FALSE;
264
265     *nextItem = create_node(This->result->nodesetval->nodeTab[This->resultPos]);
266     This->resultPos++;
267     return S_OK;
268 }
269
270 static HRESULT WINAPI queryresult_reset(
271         IXMLDOMNodeList* iface)
272 {
273     queryresult *This = impl_from_IXMLDOMNodeList( iface );
274
275     TRACE("%p\n", This);
276     This->resultPos = 0;
277     return S_OK;
278 }
279
280 static HRESULT WINAPI queryresult__newEnum(
281         IXMLDOMNodeList* iface,
282         IUnknown** ppUnk)
283 {
284     FIXME("\n");
285     return E_NOTIMPL;
286 }
287
288
289 static const struct IXMLDOMNodeListVtbl queryresult_vtbl =
290 {
291     queryresult_QueryInterface,
292     queryresult_AddRef,
293     queryresult_Release,
294     queryresult_GetTypeInfoCount,
295     queryresult_GetTypeInfo,
296     queryresult_GetIDsOfNames,
297     queryresult_Invoke,
298     queryresult_get_item,
299     queryresult_get_length,
300     queryresult_nextNode,
301     queryresult_reset,
302     queryresult__newEnum,
303 };
304
305 static HRESULT queryresult_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
306 {
307     queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
308     WCHAR *ptr;
309     DWORD idx=0;
310
311     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
312         idx = idx*10 + (*ptr-'0');
313     if(*ptr)
314         return DISP_E_UNKNOWNNAME;
315
316     if(idx >= xmlXPathNodeSetGetLength(This->result->nodesetval))
317         return DISP_E_UNKNOWNNAME;
318
319     *dispid = MSXML_DISPID_CUSTOM_MIN + idx;
320     TRACE("ret %x\n", *dispid);
321     return S_OK;
322 }
323
324 static HRESULT queryresult_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
325         VARIANT *res, EXCEPINFO *ei)
326 {
327     queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
328
329     if(flags != DISPATCH_PROPERTYGET) {
330         FIXME("flags %x\n", flags);
331         return E_NOTIMPL;
332     }
333
334     V_VT(res) = VT_DISPATCH;
335     V_DISPATCH(res) = (IDispatch*)create_node(This->result->nodesetval->nodeTab[This->resultPos]);
336     return S_OK;
337 }
338
339 static const dispex_static_data_vtbl_t queryresult_dispex_vtbl = {
340     queryresult_get_dispid,
341     queryresult_invoke
342 };
343
344 static const tid_t queryresult_iface_tids[] = {
345     IXMLDOMNodeList_tid,
346     0
347 };
348 static dispex_static_data_t queryresult_dispex = {
349     &queryresult_dispex_vtbl,
350     IXMLDOMNodeList_tid,
351     NULL,
352     queryresult_iface_tids
353 };
354
355 HRESULT queryresult_create(xmlNodePtr node, LPWSTR szQuery, IXMLDOMNodeList **out)
356 {
357     queryresult *This = heap_alloc_zero(sizeof(queryresult));
358     xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
359     xmlChar *str = xmlChar_from_wchar(szQuery);
360     HRESULT hr;
361
362
363     TRACE("(%p, %s, %p)\n", node, wine_dbgstr_w(szQuery), out);
364
365     *out = NULL;
366     if (This == NULL || ctxt == NULL || str == NULL)
367     {
368         hr = E_OUTOFMEMORY;
369         goto cleanup;
370     }
371
372     This->lpVtbl = &queryresult_vtbl;
373     This->ref = 1;
374     This->resultPos = 0;
375     This->node = node;
376     xmldoc_add_ref(This->node->doc);
377
378     ctxt->node = node;
379     This->result = xmlXPathEval(str, ctxt);
380     if (!This->result || This->result->type != XPATH_NODESET)
381     {
382         hr = E_FAIL;
383         goto cleanup;
384     }
385
386     init_dispex(&This->dispex, (IUnknown*)&This->lpVtbl, &queryresult_dispex);
387
388     *out = (IXMLDOMNodeList *) &This->lpVtbl;
389     hr = S_OK;
390     TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
391
392 cleanup:
393     if (This != NULL && FAILED(hr))
394         IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
395     if (ctxt != NULL)
396         xmlXPathFreeContext(ctxt);
397     HeapFree(GetProcessHeap(), 0, str);
398     return hr;
399 }
400
401 #endif