menu: Take the MF_DEFAULT flag in to account in MENU_CalcItemSize.
[wine] / dlls / msxml3 / nodelist.c
1 /*
2  *    Node list 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
32 #include "msxml_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
37
38 #ifdef HAVE_LIBXML2
39
40 #ifdef HAVE_LIBXSLT
41
42 #ifdef HAVE_LIBXSLT_PATTERN_H
43 #include <libxslt/pattern.h>
44 #endif
45 #ifdef HAVE_LIBXSLT_TRANSFORM_H
46 #include <libxslt/transform.h>
47 #endif
48
49 struct xslt_info {
50     xsltTransformContextPtr ctxt;
51     xsltCompMatchPtr pattern;
52     xsltStylesheetPtr sheet;
53 };
54
55 static void xslt_info_init( struct xslt_info *info )
56 {
57     info->ctxt = NULL;
58     info->pattern = NULL;
59     info->sheet = NULL;
60 }
61
62 static int create_xslt_parser( struct xslt_info *info, xmlNodePtr node, const xmlChar *str )
63 {
64     info->sheet = xsltNewStylesheet();
65     if (!info->sheet)
66         return 0;
67
68     info->ctxt = xsltNewTransformContext( info->sheet, node->doc );
69     if (!info->ctxt)
70         return 0;
71
72     info->pattern = xsltCompilePattern( str, node->doc,
73                                         node, info->sheet, info->ctxt );
74     if (!info->pattern)
75         return 0;
76     return 1;
77 }
78  
79 void free_xslt_info( struct xslt_info *info )
80 {
81     if (info->pattern)
82         xsltFreeCompMatchList( info->pattern );
83     if (info->sheet)
84         xsltFreeStylesheet( info->sheet );
85     if (info->ctxt)
86         xsltFreeTransformContext( info->ctxt );
87 }
88
89
90 static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node );
91
92 static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node )
93 {
94     if (!info->ctxt)
95         return S_FALSE;
96  
97     /* make sure that the current element matches the pattern */
98     while ( *node )
99     {
100         int r;
101
102         r = xsltTestCompMatchList( info->ctxt, *node, info->pattern );
103         if ( 1 == r )
104         {
105             TRACE("Matched %p (%s)\n", *node, (*node)->name );
106             return S_OK;
107         }
108         if (r != 0)
109         {
110             ERR("Pattern match failed\n");
111             return E_FAIL;
112         }
113         *node = get_next_node(info, *node, top_level_node);
114     }
115     return S_OK;
116 }
117
118 #else
119
120 struct xslt_info {
121     /* empty */
122 };
123
124 static void xslt_info_init( struct xslt_info *info )
125 {
126 }
127
128 void free_xslt_info( struct xslt_info *info )
129 {
130 }
131
132 static int create_xslt_parser( struct xslt_info *info, xmlNodePtr node, const xmlChar *str )
133 {
134     MESSAGE("libxslt was missing at compile time\n");
135     return 0;
136 }
137
138 static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node )
139 {
140     return S_FALSE;
141 }
142
143 #endif
144
145 static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node )
146 {
147     if(!top_level_node) return node->next;
148
149     if(node->children) return node->children;
150     if(node->next)
151     {
152         if(node == *top_level_node)
153             *top_level_node = node->next;
154         return node->next;
155     }
156
157     if(node != *top_level_node && node->parent)
158     {
159         if(node->parent == *top_level_node)
160             *top_level_node = node->parent->next;
161         return node->parent->next;
162     }
163     return NULL;
164 }
165
166 typedef struct _xmlnodelist
167 {
168     const struct IXMLDOMNodeListVtbl *lpVtbl;
169     LONG ref;
170     xmlNodePtr node;
171     xmlNodePtr current;
172     xmlNodePtr top_level_node;
173     BOOL enum_children;
174     struct xslt_info xinfo;
175 } xmlnodelist;
176
177 static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
178 {
179     return (xmlnodelist *)((char*)iface - FIELD_OFFSET(xmlnodelist, lpVtbl));
180 }
181
182 static HRESULT WINAPI xmlnodelist_QueryInterface(
183     IXMLDOMNodeList *iface,
184     REFIID riid,
185     void** ppvObject )
186 {
187     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
188
189     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
190          IsEqualGUID( riid, &IID_IDispatch ) ||
191          IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
192     {
193         *ppvObject = iface;
194     }
195     else
196     {
197         FIXME("interface %s not implemented\n", debugstr_guid(riid));
198         return E_NOINTERFACE;
199     }
200
201     IXMLDOMNodeList_AddRef( iface );
202
203     return S_OK;
204 }
205
206 static ULONG WINAPI xmlnodelist_AddRef(
207     IXMLDOMNodeList *iface )
208 {
209     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
210     return InterlockedIncrement( &This->ref );
211 }
212
213 static ULONG WINAPI xmlnodelist_Release(
214     IXMLDOMNodeList *iface )
215 {
216     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
217     ULONG ref;
218
219     ref = InterlockedDecrement( &This->ref );
220     if ( ref == 0 )
221     {
222         free_xslt_info( &This->xinfo );
223         xmldoc_release( This->node->doc );
224         HeapFree( GetProcessHeap(), 0, This );
225     }
226
227     return ref;
228 }
229
230 static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
231     IXMLDOMNodeList *iface,
232     UINT* pctinfo )
233 {
234     FIXME("\n");
235     return E_NOTIMPL;
236 }
237
238 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
239     IXMLDOMNodeList *iface,
240     UINT iTInfo,
241     LCID lcid,
242     ITypeInfo** ppTInfo )
243 {
244     FIXME("\n");
245     return E_NOTIMPL;
246 }
247
248 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
249     IXMLDOMNodeList *iface,
250     REFIID riid,
251     LPOLESTR* rgszNames,
252     UINT cNames,
253     LCID lcid,
254     DISPID* rgDispId )
255 {
256     FIXME("\n");
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI xmlnodelist_Invoke(
261     IXMLDOMNodeList *iface,
262     DISPID dispIdMember,
263     REFIID riid,
264     LCID lcid,
265     WORD wFlags,
266     DISPPARAMS* pDispParams,
267     VARIANT* pVarResult,
268     EXCEPINFO* pExcepInfo,
269     UINT* puArgErr )
270 {
271     FIXME("\n");
272     return E_NOTIMPL;
273 }
274
275 static HRESULT WINAPI xmlnodelist_get_item(
276         IXMLDOMNodeList* iface,
277         long index,
278         IXMLDOMNode** listItem)
279 {
280     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
281     xmlNodePtr curr, tmp;
282     xmlNodePtr *top_level_node = NULL;
283     long nodeIndex = 0;
284     HRESULT r;
285
286     TRACE("%p %ld\n", This, index);
287  
288     *listItem = NULL;
289
290     if (index < 0)
291         return S_FALSE;
292
293     curr = This->node;
294
295     if(This->enum_children)
296     {
297         tmp = curr;
298         top_level_node = &tmp;
299     }
300
301     while(curr)
302     {
303         r = xslt_next_match( &This->xinfo, &curr, top_level_node);
304         if(FAILED(r) || !curr) return S_FALSE;
305         if(nodeIndex++ == index) break;
306         curr = get_next_node(&This->xinfo, curr, top_level_node);
307     }
308     if(!curr) return S_FALSE;
309
310     *listItem = create_node( curr );
311
312     return S_OK;
313 }
314
315 static HRESULT WINAPI xmlnodelist_get_length(
316         IXMLDOMNodeList* iface,
317         long* listLength)
318 {
319
320     xmlNodePtr curr, tmp;
321     xmlNodePtr *top_level_node = NULL;
322     long nodeCount = 0;
323     HRESULT r;
324
325     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
326
327     TRACE("%p\n", This);
328
329     if (This->node == NULL) {
330         *listLength = 0;
331         return S_OK;
332     }
333         
334     if(This->enum_children)
335     {
336         tmp = curr;
337         top_level_node = &tmp;
338     }
339
340     for(curr = This->node; curr; curr = get_next_node(&This->xinfo, curr, top_level_node))
341     {
342         r = xslt_next_match( &This->xinfo, &curr, top_level_node );
343         if(FAILED(r) || !curr) break;
344         nodeCount++;
345     }
346
347     *listLength = nodeCount;
348     return S_OK;
349 }
350
351 static HRESULT WINAPI xmlnodelist_nextNode(
352         IXMLDOMNodeList* iface,
353         IXMLDOMNode** nextItem)
354 {
355     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
356     HRESULT r;
357     xmlNodePtr *top_level_node = NULL;
358
359     TRACE("%p %p\n", This, nextItem );
360
361     if(This->enum_children)
362         top_level_node = &This->top_level_node;
363
364     r = xslt_next_match( &This->xinfo, &This->current, top_level_node );
365     if (FAILED(r) )
366         return r;
367
368     if (!This->current)
369         return S_FALSE;
370
371     *nextItem = create_node( This->current );
372     This->current = get_next_node(&This->xinfo, This->current, top_level_node);
373     return S_OK;
374 }
375
376 static HRESULT WINAPI xmlnodelist_reset(
377         IXMLDOMNodeList* iface)
378 {
379     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
380
381     TRACE("%p\n", This);
382     This->current = This->node;
383     return S_OK;
384 }
385
386 static HRESULT WINAPI xmlnodelist__newEnum(
387         IXMLDOMNodeList* iface,
388         IUnknown** ppUnk)
389 {
390     FIXME("\n");
391     return E_NOTIMPL;
392 }
393
394
395 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
396 {
397     xmlnodelist_QueryInterface,
398     xmlnodelist_AddRef,
399     xmlnodelist_Release,
400     xmlnodelist_GetTypeInfoCount,
401     xmlnodelist_GetTypeInfo,
402     xmlnodelist_GetIDsOfNames,
403     xmlnodelist_Invoke,
404     xmlnodelist_get_item,
405     xmlnodelist_get_length,
406     xmlnodelist_nextNode,
407     xmlnodelist_reset,
408     xmlnodelist__newEnum,
409 };
410
411 static xmlnodelist *new_nodelist( xmlNodePtr node )
412 {
413     xmlnodelist *nodelist;
414
415     nodelist = HeapAlloc( GetProcessHeap(), 0, sizeof *nodelist );
416     if ( !nodelist )
417         return NULL;
418
419     nodelist->lpVtbl = &xmlnodelist_vtbl;
420     nodelist->ref = 1;
421     nodelist->node = node;
422     nodelist->current = node; 
423     nodelist->top_level_node = node;
424     nodelist->enum_children = FALSE;
425     xslt_info_init( &nodelist->xinfo );
426
427     xmldoc_add_ref( node->doc );
428
429     return nodelist;
430 }
431
432 IXMLDOMNodeList* create_nodelist( xmlNodePtr node )
433 {
434     xmlnodelist *nodelist = new_nodelist( node );
435     if (!node)
436         return NULL;
437     return (IXMLDOMNodeList*) &nodelist->lpVtbl;
438 }
439
440 IXMLDOMNodeList* create_filtered_nodelist( xmlNodePtr node, const xmlChar *str, BOOL enum_children )
441 {
442     xmlnodelist *This = new_nodelist( node );
443
444     if (create_xslt_parser( &This->xinfo, node, str ))
445     {
446         This->enum_children = enum_children;
447         return (IXMLDOMNodeList*) &This->lpVtbl;
448     }
449
450     IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
451     return NULL;
452 }
453
454 #endif