msxml3: Implement a common way to store and get callback interface pointers.
[wine] / dlls / msxml3 / saxreader.c
1 /*
2  *    SAX Reader implementation
3  *
4  * Copyright 2008 Alistair Leslie-Hughes
5  * Copyright 2008 Piotr Caban
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 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 # include <libxml/SAX2.h>
30 # include <libxml/parserInternals.h>
31 #endif
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "winnls.h"
37 #include "ole2.h"
38 #include "msxml6.h"
39 #include "wininet.h"
40 #include "urlmon.h"
41 #include "winreg.h"
42 #include "shlwapi.h"
43
44 #include "wine/debug.h"
45 #include "wine/list.h"
46
47 #include "msxml_private.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
50
51 #ifdef HAVE_LIBXML2
52
53 typedef enum
54 {
55     FeatureUnknown               = 0,
56     ExhaustiveErrors             = 1 << 1,
57     ExternalGeneralEntities      = 1 << 2,
58     ExternalParameterEntities    = 1 << 3,
59     ForcedResync                 = 1 << 4,
60     NamespacePrefixes            = 1 << 5,
61     Namespaces                   = 1 << 6,
62     ParameterEntities            = 1 << 7,
63     PreserveSystemIndentifiers   = 1 << 8,
64     ProhibitDTD                  = 1 << 9,
65     SchemaValidation             = 1 << 10,
66     ServerHttpRequest            = 1 << 11,
67     SuppressValidationfatalError = 1 << 12,
68     UseInlineSchema              = 1 << 13,
69     UseSchemaLocation            = 1 << 14,
70     LexicalHandlerParEntities    = 1 << 15
71 } saxreader_feature;
72
73 /* feature names */
74 static const WCHAR FeatureExternalGeneralEntitiesW[] = {
75     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/',
76     'f','e','a','t','u','r','e','s','/','e','x','t','e','r','n','a','l','-','g','e','n','e','r','a','l',
77     '-','e','n','t','i','t','i','e','s',0
78 };
79
80 static const WCHAR FeatureExternalParameterEntitiesW[] = {
81     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
82     '/','e','x','t','e','r','n','a','l','-','p','a','r','a','m','e','t','e','r','-','e','n','t','i','t','i','e','s',0
83 };
84
85 static const WCHAR FeatureLexicalHandlerParEntitiesW[] = {
86     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
87     '/','l','e','x','i','c','a','l','-','h','a','n','d','l','e','r','/','p','a','r','a','m','e','t','e','r','-','e','n','t','i','t','i','e','s',0
88 };
89
90 static const WCHAR FeatureProhibitDTDW[] = {
91     'p','r','o','h','i','b','i','t','-','d','t','d',0
92 };
93
94 static const WCHAR FeatureNamespacesW[] = {
95     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
96     '/','n','a','m','e','s','p','a','c','e','s',0
97 };
98
99 static const WCHAR FeatureNamespacePrefixesW[] = {
100     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
101     '/','n','a','m','e','s','p','a','c','e','-','p','r','e','f','i','x','e','s',0
102 };
103
104 struct saxreader_feature_pair
105 {
106     saxreader_feature feature;
107     const WCHAR *name;
108 };
109
110 static const struct saxreader_feature_pair saxreader_feature_map[] = {
111     { ExternalGeneralEntities, FeatureExternalGeneralEntitiesW },
112     { ExternalParameterEntities, FeatureExternalParameterEntitiesW },
113     { LexicalHandlerParEntities, FeatureLexicalHandlerParEntitiesW },
114     { NamespacePrefixes, FeatureNamespacePrefixesW },
115     { Namespaces, FeatureNamespacesW },
116     { ProhibitDTD, FeatureProhibitDTDW }
117 };
118
119 static saxreader_feature get_saxreader_feature(const WCHAR *name)
120 {
121     int min, max, n, c;
122
123     min = 0;
124     max = sizeof(saxreader_feature_map)/sizeof(struct saxreader_feature_pair) - 1;
125
126     while (min <= max)
127     {
128         n = (min+max)/2;
129
130         c = strcmpW(saxreader_feature_map[n].name, name);
131         if (!c)
132             return saxreader_feature_map[n].feature;
133
134         if (c > 0)
135             max = n-1;
136         else
137             min = n+1;
138     }
139
140     return FeatureUnknown;
141 }
142
143 struct bstrpool
144 {
145     BSTR *pool;
146     unsigned int index;
147     unsigned int len;
148 };
149
150 typedef struct
151 {
152     BSTR prefix;
153     BSTR uri;
154 } ns;
155
156 typedef struct
157 {
158     struct list entry;
159     BSTR prefix;
160     BSTR local;
161     BSTR qname;
162     ns *ns; /* namespaces defined in this particular element */
163     int ns_count;
164 } element_entry;
165
166 enum saxhandler_type
167 {
168     SAXContentHandler = 0,
169     SAXDeclHandler,
170     SAXDTDHandler,
171     SAXErrorHandler,
172     SAXLexicalHandler,
173     SAXHandler_Last
174 };
175
176 struct saxhandler_iface
177 {
178     IUnknown *handler;
179     IUnknown *vbhandler;
180 };
181
182 struct saxcontenthandler_iface
183 {
184     ISAXContentHandler *handler;
185     IVBSAXContentHandler *vbhandler;
186 };
187
188 struct saxerrorhandler_iface
189 {
190     ISAXErrorHandler *handler;
191     IVBSAXErrorHandler *vbhandler;
192 };
193
194 struct saxlexicalhandler_iface
195 {
196     ISAXLexicalHandler *handler;
197     IVBSAXLexicalHandler *vbhandler;
198 };
199
200 typedef struct
201 {
202     DispatchEx dispex;
203     IVBSAXXMLReader IVBSAXXMLReader_iface;
204     ISAXXMLReader ISAXXMLReader_iface;
205     LONG ref;
206
207     struct saxhandler_iface saxhandlers[SAXHandler_Last];
208     xmlSAXHandler sax;
209     BOOL isParsing;
210     struct bstrpool pool;
211     saxreader_feature features;
212     MSXML_VERSION version;
213 } saxreader;
214
215 static HRESULT saxreader_put_handler(saxreader *reader, enum saxhandler_type type, void *ptr, BOOL vb)
216 {
217     struct saxhandler_iface *iface = &reader->saxhandlers[type];
218     IUnknown *unk = (IUnknown*)ptr;
219
220     if (unk)
221         IUnknown_AddRef(unk);
222
223     if ((vb && iface->vbhandler) || (!vb && iface->handler))
224         IUnknown_Release(vb ? iface->vbhandler : iface->handler);
225
226     if (vb)
227         iface->vbhandler = unk;
228     else
229         iface->handler = unk;
230
231     return S_OK;
232 }
233
234 static HRESULT saxreader_get_handler(const saxreader *reader, enum saxhandler_type type, BOOL vb, void **ret)
235 {
236     const struct saxhandler_iface *iface = &reader->saxhandlers[type];
237
238     if (!ret) return E_POINTER;
239
240     if ((vb && iface->vbhandler) || (!vb && iface->handler))
241     {
242         if (vb)
243             IUnknown_AddRef(iface->vbhandler);
244         else
245             IUnknown_AddRef(iface->handler);
246     }
247
248     *ret = vb ? iface->vbhandler : iface->handler;
249
250     return S_OK;
251 }
252
253 static struct saxcontenthandler_iface *saxreader_get_contenthandler(saxreader *reader)
254 {
255     return (struct saxcontenthandler_iface*)&reader->saxhandlers[SAXContentHandler];
256 }
257
258 static struct saxerrorhandler_iface *saxreader_get_errorhandler(saxreader *reader)
259 {
260     return (struct saxerrorhandler_iface*)&reader->saxhandlers[SAXErrorHandler];
261 }
262
263 static struct saxlexicalhandler_iface *saxreader_get_lexicalhandler(saxreader *reader)
264 {
265     return (struct saxlexicalhandler_iface*)&reader->saxhandlers[SAXLexicalHandler];
266 }
267
268 typedef struct
269 {
270     IVBSAXLocator IVBSAXLocator_iface;
271     ISAXLocator ISAXLocator_iface;
272     IVBSAXAttributes IVBSAXAttributes_iface;
273     ISAXAttributes ISAXAttributes_iface;
274     LONG ref;
275     saxreader *saxreader;
276     HRESULT ret;
277     xmlParserCtxtPtr pParserCtxt;
278     WCHAR *publicId;
279     WCHAR *systemId;
280     int line;
281     int column;
282     BOOL vbInterface;
283     struct list elements;
284
285     BSTR namespaceUri;
286     int attributesSize;
287     int nb_attributes;
288     struct _attributes
289     {
290         BSTR szLocalname;
291         BSTR szURI;
292         BSTR szValue;
293         BSTR szQName;
294     } *attributes;
295 } saxlocator;
296
297 static inline saxreader *impl_from_IVBSAXXMLReader( IVBSAXXMLReader *iface )
298 {
299     return CONTAINING_RECORD(iface, saxreader, IVBSAXXMLReader_iface);
300 }
301
302 static inline saxreader *impl_from_ISAXXMLReader( ISAXXMLReader *iface )
303 {
304     return CONTAINING_RECORD(iface, saxreader, ISAXXMLReader_iface);
305 }
306
307 static inline saxlocator *impl_from_IVBSAXLocator( IVBSAXLocator *iface )
308 {
309     return CONTAINING_RECORD(iface, saxlocator, IVBSAXLocator_iface);
310 }
311
312 static inline saxlocator *impl_from_ISAXLocator( ISAXLocator *iface )
313 {
314     return CONTAINING_RECORD(iface, saxlocator, ISAXLocator_iface);
315 }
316
317 static inline saxlocator *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface )
318 {
319     return CONTAINING_RECORD(iface, saxlocator, IVBSAXAttributes_iface);
320 }
321
322 static inline saxlocator *impl_from_ISAXAttributes( ISAXAttributes *iface )
323 {
324     return CONTAINING_RECORD(iface, saxlocator, ISAXAttributes_iface);
325 }
326
327 /* property names */
328 static const WCHAR PropertyCharsetW[] = {
329     'c','h','a','r','s','e','t',0
330 };
331 static const WCHAR PropertyDeclHandlerW[] = {
332     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
333     's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
334     'd','e','c','l','a','r','a','t','i','o','n',
335     '-','h','a','n','d','l','e','r',0
336 };
337 static const WCHAR PropertyDomNodeW[] = {
338     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
339     's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
340     'd','o','m','-','n','o','d','e',0
341 };
342 static const WCHAR PropertyInputSourceW[] = {
343     'i','n','p','u','t','-','s','o','u','r','c','e',0
344 };
345 static const WCHAR PropertyLexicalHandlerW[] = {
346     'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
347     's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
348     'l','e','x','i','c','a','l','-','h','a','n','d','l','e','r',0
349 };
350 static const WCHAR PropertyMaxElementDepthW[] = {
351     'm','a','x','-','e','l','e','m','e','n','t','-','d','e','p','t','h',0
352 };
353 static const WCHAR PropertyMaxXMLSizeW[] = {
354     'm','a','x','-','x','m','l','-','s','i','z','e',0
355 };
356 static const WCHAR PropertySchemaDeclHandlerW[] = {
357     's','c','h','e','m','a','-','d','e','c','l','a','r','a','t','i','o','n','-',
358     'h','a','n','d','l','e','r',0
359 };
360 static const WCHAR PropertyXMLDeclEncodingW[] = {
361     'x','m','l','d','e','c','l','-','e','n','c','o','d','i','n','g',0
362 };
363 static const WCHAR PropertyXMLDeclStandaloneW[] = {
364     'x','m','l','d','e','c','l','-','s','t','a','n','d','a','l','o','n','e',0
365 };
366 static const WCHAR PropertyXMLDeclVersionW[] = {
367     'x','m','l','d','e','c','l','-','v','e','r','s','i','o','n',0
368 };
369
370 static inline HRESULT set_feature_value(saxreader *reader, saxreader_feature feature, VARIANT_BOOL value)
371 {
372     /* handling of non-VARIANT_* values is version dependent */
373     if ((reader->version <  MSXML4) && (value != VARIANT_TRUE))
374         value = VARIANT_FALSE;
375     if ((reader->version >= MSXML4) && (value != VARIANT_FALSE))
376         value = VARIANT_TRUE;
377
378     if (value == VARIANT_TRUE)
379         reader->features |=  feature;
380     else
381         reader->features &= ~feature;
382
383     return S_OK;
384 }
385
386 static inline HRESULT get_feature_value(const saxreader *reader, saxreader_feature feature, VARIANT_BOOL *value)
387 {
388     *value = reader->features & feature ? VARIANT_TRUE : VARIANT_FALSE;
389     return S_OK;
390 }
391
392 static BOOL is_namespaces_enabled(const saxreader *reader)
393 {
394     return (reader->version < MSXML4) || (reader->features & Namespaces);
395 }
396
397 static inline int has_content_handler(const saxlocator *locator)
398 {
399     return  (locator->vbInterface && locator->saxreader->saxhandlers[SAXContentHandler].vbhandler) ||
400            (!locator->vbInterface && locator->saxreader->saxhandlers[SAXContentHandler].handler);
401 }
402
403 static inline int has_lexical_handler(const saxlocator *locator)
404 {
405     return  (locator->vbInterface && locator->saxreader->saxhandlers[SAXLexicalHandler].vbhandler) ||
406            (!locator->vbInterface && locator->saxreader->saxhandlers[SAXLexicalHandler].handler);
407 }
408
409 static inline int has_error_handler(const saxlocator *locator)
410 {
411     return  (locator->vbInterface && locator->saxreader->saxhandlers[SAXErrorHandler].vbhandler) ||
412            (!locator->vbInterface && locator->saxreader->saxhandlers[SAXErrorHandler].handler);
413 }
414
415 static BSTR build_qname(BSTR prefix, BSTR local)
416 {
417     if (prefix && *prefix)
418     {
419         BSTR qname = SysAllocStringLen(NULL, SysStringLen(prefix) + SysStringLen(local) + 1);
420         WCHAR *ptr;
421
422         ptr = qname;
423         strcpyW(ptr, prefix);
424         ptr += SysStringLen(prefix);
425         *ptr++ = ':';
426         strcpyW(ptr, local);
427         return qname;
428     }
429     else
430         return SysAllocString(local);
431 }
432
433 static element_entry* alloc_element_entry(const xmlChar *local, const xmlChar *prefix, int nb_ns,
434     const xmlChar **namespaces)
435 {
436     element_entry *ret;
437     int i;
438
439     ret = heap_alloc(sizeof(*ret));
440     if (!ret) return ret;
441
442     ret->local  = bstr_from_xmlChar(local);
443     ret->prefix = bstr_from_xmlChar(prefix);
444     ret->qname  = build_qname(ret->prefix, ret->local);
445     ret->ns = nb_ns ? heap_alloc(nb_ns*sizeof(ns)) : NULL;
446     ret->ns_count = nb_ns;
447
448     for (i=0; i < nb_ns; i++)
449     {
450         ret->ns[i].prefix = bstr_from_xmlChar(namespaces[2*i]);
451         ret->ns[i].uri = bstr_from_xmlChar(namespaces[2*i+1]);
452     }
453
454     return ret;
455 }
456
457 static void free_element_entry(element_entry *element)
458 {
459     int i;
460
461     for (i=0; i<element->ns_count;i++)
462     {
463         SysFreeString(element->ns[i].prefix);
464         SysFreeString(element->ns[i].uri);
465     }
466
467     SysFreeString(element->prefix);
468     SysFreeString(element->local);
469
470     heap_free(element->ns);
471     heap_free(element);
472 }
473
474 static void push_element_ns(saxlocator *locator, element_entry *element)
475 {
476     list_add_head(&locator->elements, &element->entry);
477 }
478
479 static element_entry * pop_element_ns(saxlocator *locator)
480 {
481     element_entry *element = LIST_ENTRY(list_head(&locator->elements), element_entry, entry);
482
483     if (element)
484         list_remove(&element->entry);
485
486     return element;
487 }
488
489 static BSTR find_element_uri(saxlocator *locator, const xmlChar *uri)
490 {
491     element_entry *element;
492     BSTR uriW;
493     int i;
494
495     if (!uri) return NULL;
496
497     uriW = bstr_from_xmlChar(uri);
498
499     LIST_FOR_EACH_ENTRY(element, &locator->elements, element_entry, entry)
500     {
501         for (i=0; i < element->ns_count; i++)
502             if (!strcmpW(uriW, element->ns[i].uri))
503             {
504                 SysFreeString(uriW);
505                 return element->ns[i].uri;
506             }
507     }
508
509     SysFreeString(uriW);
510     ERR("namespace uri not found, %s\n", debugstr_a((char*)uri));
511     return NULL;
512 }
513
514 /* used to localize version dependent error check behaviour */
515 static inline BOOL sax_callback_failed(saxlocator *This, HRESULT hr)
516 {
517     return This->saxreader->version >= MSXML4 ? FAILED(hr) : hr != S_OK;
518 }
519
520 /* index value -1 means it tries to loop for a first time */
521 static inline BOOL iterate_endprefix_index(saxlocator *This, const element_entry *element, int *i)
522 {
523     if (This->saxreader->version >= MSXML4)
524     {
525         if (*i == -1) *i = 0; else ++*i;
526         return *i < element->ns_count;
527     }
528     else
529     {
530         if (*i == -1) *i = element->ns_count-1; else --*i;
531         return *i >= 0;
532     }
533 }
534
535 static BOOL bstr_pool_insert(struct bstrpool *pool, BSTR pool_entry)
536 {
537     if (!pool->pool)
538     {
539         pool->pool = HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(*pool->pool));
540         if (!pool->pool)
541             return FALSE;
542
543         pool->index = 0;
544         pool->len = 16;
545     }
546     else if (pool->index == pool->len)
547     {
548         BSTR *realloc = HeapReAlloc(GetProcessHeap(), 0, pool->pool, pool->len * 2 * sizeof(*realloc));
549
550         if (!realloc)
551             return FALSE;
552
553         pool->pool = realloc;
554         pool->len *= 2;
555     }
556
557     pool->pool[pool->index++] = pool_entry;
558     return TRUE;
559 }
560
561 static void free_bstr_pool(struct bstrpool *pool)
562 {
563     unsigned int i;
564
565     for (i = 0; i < pool->index; i++)
566         SysFreeString(pool->pool[i]);
567
568     HeapFree(GetProcessHeap(), 0, pool->pool);
569
570     pool->pool = NULL;
571     pool->index = pool->len = 0;
572 }
573
574 static BSTR bstr_from_xmlCharN(const xmlChar *buf, int len)
575 {
576     DWORD dLen;
577     BSTR bstr;
578
579     if (!buf)
580         return NULL;
581
582     dLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0);
583     if(len != -1) dLen++;
584     bstr = SysAllocStringLen(NULL, dLen-1);
585     if (!bstr)
586         return NULL;
587     MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, bstr, dLen);
588     if(len != -1) bstr[dLen-1] = '\0';
589
590     return bstr;
591 }
592
593 static BSTR QName_from_xmlChar(const xmlChar *prefix, const xmlChar *name)
594 {
595     xmlChar *qname;
596     BSTR bstr;
597
598     if(!name) return NULL;
599
600     if(!prefix || !*prefix)
601         return bstr_from_xmlChar(name);
602
603     qname = xmlBuildQName(name, prefix, NULL, 0);
604     bstr = bstr_from_xmlChar(qname);
605     xmlFree(qname);
606
607     return bstr;
608 }
609
610 static BSTR pooled_bstr_from_xmlChar(struct bstrpool *pool, const xmlChar *buf)
611 {
612     BSTR pool_entry = bstr_from_xmlChar(buf);
613
614     if (pool_entry && !bstr_pool_insert(pool, pool_entry))
615     {
616         SysFreeString(pool_entry);
617         return NULL;
618     }
619
620     return pool_entry;
621 }
622
623 static BSTR pooled_bstr_from_xmlCharN(struct bstrpool *pool, const xmlChar *buf, int len)
624 {
625     BSTR pool_entry = bstr_from_xmlCharN(buf, len);
626
627     if (pool_entry && !bstr_pool_insert(pool, pool_entry))
628     {
629         SysFreeString(pool_entry);
630         return NULL;
631     }
632
633     return pool_entry;
634 }
635
636 static void format_error_message_from_id(saxlocator *This, HRESULT hr)
637 {
638     struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader);
639     xmlStopParser(This->pParserCtxt);
640     This->ret = hr;
641
642     if(has_error_handler(This))
643     {
644         WCHAR msg[1024];
645         if(!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
646                     NULL, hr, 0, msg, sizeof(msg), NULL))
647         {
648             FIXME("MSXML errors not yet supported.\n");
649             msg[0] = '\0';
650         }
651
652         if(This->vbInterface)
653         {
654             BSTR bstrMsg = SysAllocString(msg);
655             IVBSAXErrorHandler_fatalError(handler->vbhandler,
656                     &This->IVBSAXLocator_iface, &bstrMsg, hr);
657             SysFreeString(bstrMsg);
658         }
659         else
660             ISAXErrorHandler_fatalError(handler->handler,
661                     &This->ISAXLocator_iface, msg, hr);
662     }
663 }
664
665 static void update_position(saxlocator *This, BOOL fix_column)
666 {
667     const xmlChar *p = This->pParserCtxt->input->cur-1;
668
669     This->line = xmlSAX2GetLineNumber(This->pParserCtxt);
670     if(fix_column)
671     {
672         This->column = 1;
673         for(; *p!='\n' && *p!='\r' && p>=This->pParserCtxt->input->base; p--)
674             This->column++;
675     }
676     else
677     {
678         This->column = xmlSAX2GetColumnNumber(This->pParserCtxt);
679     }
680 }
681
682 /*** IVBSAXAttributes interface ***/
683 /*** IUnknown methods ***/
684 static HRESULT WINAPI ivbsaxattributes_QueryInterface(
685         IVBSAXAttributes* iface,
686         REFIID riid,
687         void **ppvObject)
688 {
689     saxlocator *This = impl_from_IVBSAXAttributes(iface);
690     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
691     return IVBSAXLocator_QueryInterface(&This->IVBSAXLocator_iface, riid, ppvObject);
692 }
693
694 static ULONG WINAPI ivbsaxattributes_AddRef(IVBSAXAttributes* iface)
695 {
696     saxlocator *This = impl_from_IVBSAXAttributes(iface);
697     return ISAXLocator_AddRef(&This->ISAXLocator_iface);
698 }
699
700 static ULONG WINAPI ivbsaxattributes_Release(IVBSAXAttributes* iface)
701 {
702     saxlocator *This = impl_from_IVBSAXAttributes(iface);
703     return ISAXLocator_Release(&This->ISAXLocator_iface);
704 }
705
706 /*** IDispatch methods ***/
707 static HRESULT WINAPI ivbsaxattributes_GetTypeInfoCount( IVBSAXAttributes *iface, UINT* pctinfo )
708 {
709     saxlocator *This = impl_from_IVBSAXAttributes( iface );
710
711     TRACE("(%p)->(%p)\n", This, pctinfo);
712
713     *pctinfo = 1;
714
715     return S_OK;
716 }
717
718 static HRESULT WINAPI ivbsaxattributes_GetTypeInfo(
719     IVBSAXAttributes *iface,
720     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
721 {
722     saxlocator *This = impl_from_IVBSAXAttributes( iface );
723     HRESULT hr;
724
725     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
726
727     hr = get_typeinfo(IVBSAXAttributes_tid, ppTInfo);
728
729     return hr;
730 }
731
732 static HRESULT WINAPI ivbsaxattributes_GetIDsOfNames(
733     IVBSAXAttributes *iface,
734     REFIID riid,
735     LPOLESTR* rgszNames,
736     UINT cNames,
737     LCID lcid,
738     DISPID* rgDispId)
739 {
740     saxlocator *This = impl_from_IVBSAXAttributes( iface );
741     ITypeInfo *typeinfo;
742     HRESULT hr;
743
744     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
745           lcid, rgDispId);
746
747     if(!rgszNames || cNames == 0 || !rgDispId)
748         return E_INVALIDARG;
749
750     hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
751     if(SUCCEEDED(hr))
752     {
753         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
754         ITypeInfo_Release(typeinfo);
755     }
756
757     return hr;
758 }
759
760 static HRESULT WINAPI ivbsaxattributes_Invoke(
761     IVBSAXAttributes *iface,
762     DISPID dispIdMember,
763     REFIID riid,
764     LCID lcid,
765     WORD wFlags,
766     DISPPARAMS* pDispParams,
767     VARIANT* pVarResult,
768     EXCEPINFO* pExcepInfo,
769     UINT* puArgErr)
770 {
771     saxlocator *This = impl_from_IVBSAXAttributes( iface );
772     ITypeInfo *typeinfo;
773     HRESULT hr;
774
775     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
776           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
777
778     hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
779     if(SUCCEEDED(hr))
780     {
781         hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXAttributes_iface, dispIdMember, wFlags,
782                 pDispParams, pVarResult, pExcepInfo, puArgErr);
783         ITypeInfo_Release(typeinfo);
784     }
785
786     return hr;
787 }
788
789 /*** IVBSAXAttributes methods ***/
790 static HRESULT WINAPI ivbsaxattributes_get_length(
791         IVBSAXAttributes* iface,
792         int *nLength)
793 {
794     saxlocator *This = impl_from_IVBSAXAttributes( iface );
795     return ISAXAttributes_getLength(&This->ISAXAttributes_iface, nLength);
796 }
797
798 static HRESULT WINAPI ivbsaxattributes_getURI(
799         IVBSAXAttributes* iface,
800         int nIndex,
801         BSTR *uri)
802 {
803     int len;
804     saxlocator *This = impl_from_IVBSAXAttributes( iface );
805     return ISAXAttributes_getURI(&This->ISAXAttributes_iface, nIndex, (const WCHAR**)uri, &len);
806 }
807
808 static HRESULT WINAPI ivbsaxattributes_getLocalName(
809         IVBSAXAttributes* iface,
810         int nIndex,
811         BSTR *localName)
812 {
813     int len;
814     saxlocator *This = impl_from_IVBSAXAttributes( iface );
815     return ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, nIndex,
816             (const WCHAR**)localName, &len);
817 }
818
819 static HRESULT WINAPI ivbsaxattributes_getQName(
820         IVBSAXAttributes* iface,
821         int nIndex,
822         BSTR *QName)
823 {
824     int len;
825     saxlocator *This = impl_from_IVBSAXAttributes( iface );
826     return ISAXAttributes_getQName(&This->ISAXAttributes_iface, nIndex, (const WCHAR**)QName, &len);
827 }
828
829 static HRESULT WINAPI ivbsaxattributes_getIndexFromName(
830         IVBSAXAttributes* iface,
831         BSTR uri,
832         BSTR localName,
833         int *index)
834 {
835     saxlocator *This = impl_from_IVBSAXAttributes( iface );
836     return ISAXAttributes_getIndexFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
837             localName, SysStringLen(localName), index);
838 }
839
840 static HRESULT WINAPI ivbsaxattributes_getIndexFromQName(
841         IVBSAXAttributes* iface,
842         BSTR QName,
843         int *index)
844 {
845     saxlocator *This = impl_from_IVBSAXAttributes( iface );
846     return ISAXAttributes_getIndexFromQName(&This->ISAXAttributes_iface, QName,
847             SysStringLen(QName), index);
848 }
849
850 static HRESULT WINAPI ivbsaxattributes_getType(
851         IVBSAXAttributes* iface,
852         int nIndex,
853         BSTR *type)
854 {
855     int len;
856     saxlocator *This = impl_from_IVBSAXAttributes( iface );
857     return ISAXAttributes_getType(&This->ISAXAttributes_iface, nIndex, (const WCHAR**)type, &len);
858 }
859
860 static HRESULT WINAPI ivbsaxattributes_getTypeFromName(
861         IVBSAXAttributes* iface,
862         BSTR uri,
863         BSTR localName,
864         BSTR *type)
865 {
866     int len;
867     saxlocator *This = impl_from_IVBSAXAttributes( iface );
868     return ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
869             localName, SysStringLen(localName), (const WCHAR**)type, &len);
870 }
871
872 static HRESULT WINAPI ivbsaxattributes_getTypeFromQName(
873         IVBSAXAttributes* iface,
874         BSTR QName,
875         BSTR *type)
876 {
877     int len;
878     saxlocator *This = impl_from_IVBSAXAttributes( iface );
879     return ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, QName, SysStringLen(QName),
880             (const WCHAR**)type, &len);
881 }
882
883 static HRESULT WINAPI ivbsaxattributes_getValue(
884         IVBSAXAttributes* iface,
885         int nIndex,
886         BSTR *value)
887 {
888     int len;
889     saxlocator *This = impl_from_IVBSAXAttributes( iface );
890     return ISAXAttributes_getValue(&This->ISAXAttributes_iface, nIndex, (const WCHAR**)value, &len);
891 }
892
893 static HRESULT WINAPI ivbsaxattributes_getValueFromName(
894         IVBSAXAttributes* iface,
895         BSTR uri,
896         BSTR localName,
897         BSTR *value)
898 {
899     int len;
900     saxlocator *This = impl_from_IVBSAXAttributes( iface );
901     return ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
902             localName, SysStringLen(localName), (const WCHAR**)value, &len);
903 }
904
905 static HRESULT WINAPI ivbsaxattributes_getValueFromQName(
906         IVBSAXAttributes* iface,
907         BSTR QName,
908         BSTR *value)
909 {
910     int len;
911     saxlocator *This = impl_from_IVBSAXAttributes( iface );
912     return ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, QName,
913             SysStringLen(QName), (const WCHAR**)value, &len);
914 }
915
916 static const struct IVBSAXAttributesVtbl ivbsaxattributes_vtbl =
917 {
918     ivbsaxattributes_QueryInterface,
919     ivbsaxattributes_AddRef,
920     ivbsaxattributes_Release,
921     ivbsaxattributes_GetTypeInfoCount,
922     ivbsaxattributes_GetTypeInfo,
923     ivbsaxattributes_GetIDsOfNames,
924     ivbsaxattributes_Invoke,
925     ivbsaxattributes_get_length,
926     ivbsaxattributes_getURI,
927     ivbsaxattributes_getLocalName,
928     ivbsaxattributes_getQName,
929     ivbsaxattributes_getIndexFromName,
930     ivbsaxattributes_getIndexFromQName,
931     ivbsaxattributes_getType,
932     ivbsaxattributes_getTypeFromName,
933     ivbsaxattributes_getTypeFromQName,
934     ivbsaxattributes_getValue,
935     ivbsaxattributes_getValueFromName,
936     ivbsaxattributes_getValueFromQName
937 };
938
939 /*** ISAXAttributes interface ***/
940 /*** IUnknown methods ***/
941 static HRESULT WINAPI isaxattributes_QueryInterface(
942         ISAXAttributes* iface,
943         REFIID riid,
944         void **ppvObject)
945 {
946     saxlocator *This = impl_from_ISAXAttributes(iface);
947     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
948     return ISAXLocator_QueryInterface(&This->ISAXLocator_iface, riid, ppvObject);
949 }
950
951 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
952 {
953     saxlocator *This = impl_from_ISAXAttributes(iface);
954     TRACE("%p\n", This);
955     return ISAXLocator_AddRef(&This->ISAXLocator_iface);
956 }
957
958 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
959 {
960     saxlocator *This = impl_from_ISAXAttributes(iface);
961
962     TRACE("%p\n", This);
963     return ISAXLocator_Release(&This->ISAXLocator_iface);
964 }
965
966 /*** ISAXAttributes methods ***/
967 static HRESULT WINAPI isaxattributes_getLength(
968         ISAXAttributes* iface,
969         int *length)
970 {
971     saxlocator *This = impl_from_ISAXAttributes( iface );
972
973     *length = This->nb_attributes;
974     TRACE("Length set to %d\n", *length);
975     return S_OK;
976 }
977
978 static HRESULT WINAPI isaxattributes_getURI(
979         ISAXAttributes* iface,
980         int index,
981         const WCHAR **url,
982         int *size)
983 {
984     saxlocator *This = impl_from_ISAXAttributes( iface );
985     TRACE("(%p)->(%d)\n", This, index);
986
987     if(index >= This->nb_attributes || index < 0) return E_INVALIDARG;
988     if(!url || !size) return E_POINTER;
989
990     *size = SysStringLen(This->attributes[index].szURI);
991     *url = This->attributes[index].szURI;
992
993     TRACE("(%s:%d)\n", debugstr_w(This->attributes[index].szURI), *size);
994
995     return S_OK;
996 }
997
998 static HRESULT WINAPI isaxattributes_getLocalName(
999         ISAXAttributes* iface,
1000         int nIndex,
1001         const WCHAR **pLocalName,
1002         int *pLocalNameLength)
1003 {
1004     saxlocator *This = impl_from_ISAXAttributes( iface );
1005     TRACE("(%p)->(%d)\n", This, nIndex);
1006
1007     if(nIndex>=This->nb_attributes || nIndex<0) return E_INVALIDARG;
1008     if(!pLocalName || !pLocalNameLength) return E_POINTER;
1009
1010     *pLocalNameLength = SysStringLen(This->attributes[nIndex].szLocalname);
1011     *pLocalName = This->attributes[nIndex].szLocalname;
1012
1013     return S_OK;
1014 }
1015
1016 static HRESULT WINAPI isaxattributes_getQName(
1017         ISAXAttributes* iface,
1018         int nIndex,
1019         const WCHAR **pQName,
1020         int *pQNameLength)
1021 {
1022     saxlocator *This = impl_from_ISAXAttributes( iface );
1023     TRACE("(%p)->(%d)\n", This, nIndex);
1024
1025     if(nIndex>=This->nb_attributes || nIndex<0) return E_INVALIDARG;
1026     if(!pQName || !pQNameLength) return E_POINTER;
1027
1028     *pQNameLength = SysStringLen(This->attributes[nIndex].szQName);
1029     *pQName = This->attributes[nIndex].szQName;
1030
1031     return S_OK;
1032 }
1033
1034 static HRESULT WINAPI isaxattributes_getName(
1035         ISAXAttributes* iface,
1036         int index,
1037         const WCHAR **uri,
1038         int *pUriLength,
1039         const WCHAR **localName,
1040         int *pLocalNameSize,
1041         const WCHAR **QName,
1042         int *pQNameLength)
1043 {
1044     saxlocator *This = impl_from_ISAXAttributes( iface );
1045     TRACE("(%p)->(%d)\n", This, index);
1046
1047     if(index>=This->nb_attributes || index<0) return E_INVALIDARG;
1048     if(!uri || !pUriLength || !localName || !pLocalNameSize
1049             || !QName || !pQNameLength) return E_POINTER;
1050
1051     *pUriLength = SysStringLen(This->attributes[index].szURI);
1052     *uri = This->attributes[index].szURI;
1053     *pLocalNameSize = SysStringLen(This->attributes[index].szLocalname);
1054     *localName = This->attributes[index].szLocalname;
1055     *pQNameLength = SysStringLen(This->attributes[index].szQName);
1056     *QName = This->attributes[index].szQName;
1057
1058     TRACE("(%s, %s, %s)\n", debugstr_w(*uri), debugstr_w(*localName), debugstr_w(*QName));
1059
1060     return S_OK;
1061 }
1062
1063 static HRESULT WINAPI isaxattributes_getIndexFromName(
1064         ISAXAttributes* iface,
1065         const WCHAR *pUri,
1066         int cUriLength,
1067         const WCHAR *pLocalName,
1068         int cocalNameLength,
1069         int *index)
1070 {
1071     saxlocator *This = impl_from_ISAXAttributes( iface );
1072     int i;
1073     TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), cUriLength,
1074             debugstr_w(pLocalName), cocalNameLength);
1075
1076     if(!pUri || !pLocalName || !index) return E_POINTER;
1077
1078     for(i=0; i<This->nb_attributes; i++)
1079     {
1080         if(cUriLength!=SysStringLen(This->attributes[i].szURI)
1081                 || cocalNameLength!=SysStringLen(This->attributes[i].szLocalname))
1082             continue;
1083         if(cUriLength && memcmp(pUri, This->attributes[i].szURI,
1084                     sizeof(WCHAR)*cUriLength))
1085             continue;
1086         if(cocalNameLength && memcmp(pLocalName, This->attributes[i].szLocalname,
1087                     sizeof(WCHAR)*cocalNameLength))
1088             continue;
1089
1090         *index = i;
1091         return S_OK;
1092     }
1093
1094     return E_INVALIDARG;
1095 }
1096
1097 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1098         ISAXAttributes* iface,
1099         const WCHAR *pQName,
1100         int nQNameLength,
1101         int *index)
1102 {
1103     saxlocator *This = impl_from_ISAXAttributes( iface );
1104     int i;
1105     TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQNameLength);
1106
1107     if(!pQName || !index) return E_POINTER;
1108     if(!nQNameLength) return E_INVALIDARG;
1109
1110     for(i=0; i<This->nb_attributes; i++)
1111     {
1112         if(nQNameLength!=SysStringLen(This->attributes[i].szQName)) continue;
1113         if(memcmp(pQName, This->attributes[i].szQName, sizeof(WCHAR)*nQNameLength)) continue;
1114
1115         *index = i;
1116         return S_OK;
1117     }
1118
1119     return E_INVALIDARG;
1120 }
1121
1122 static HRESULT WINAPI isaxattributes_getType(
1123         ISAXAttributes* iface,
1124         int nIndex,
1125         const WCHAR **pType,
1126         int *pTypeLength)
1127 {
1128     saxlocator *This = impl_from_ISAXAttributes( iface );
1129
1130     FIXME("(%p)->(%d) stub\n", This, nIndex);
1131     return E_NOTIMPL;
1132 }
1133
1134 static HRESULT WINAPI isaxattributes_getTypeFromName(
1135         ISAXAttributes* iface,
1136         const WCHAR *pUri,
1137         int nUri,
1138         const WCHAR *pLocalName,
1139         int nLocalName,
1140         const WCHAR **pType,
1141         int *nType)
1142 {
1143     saxlocator *This = impl_from_ISAXAttributes( iface );
1144
1145     FIXME("(%p)->(%s, %d, %s, %d) stub\n", This, debugstr_w(pUri), nUri,
1146             debugstr_w(pLocalName), nLocalName);
1147     return E_NOTIMPL;
1148 }
1149
1150 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1151         ISAXAttributes* iface,
1152         const WCHAR *pQName,
1153         int nQName,
1154         const WCHAR **pType,
1155         int *nType)
1156 {
1157     saxlocator *This = impl_from_ISAXAttributes( iface );
1158
1159     FIXME("(%p)->(%s, %d) stub\n", This, debugstr_w(pQName), nQName);
1160     return E_NOTIMPL;
1161 }
1162
1163 static HRESULT WINAPI isaxattributes_getValue(
1164         ISAXAttributes* iface,
1165         int index,
1166         const WCHAR **value,
1167         int *nValue)
1168 {
1169     saxlocator *This = impl_from_ISAXAttributes( iface );
1170     TRACE("(%p)->(%d)\n", This, index);
1171
1172     if(index>=This->nb_attributes || index<0) return E_INVALIDARG;
1173     if(!value || !nValue) return E_POINTER;
1174
1175     *nValue = SysStringLen(This->attributes[index].szValue);
1176     *value = This->attributes[index].szValue;
1177
1178     TRACE("(%s:%d)\n", debugstr_w(*value), *nValue);
1179
1180     return S_OK;
1181 }
1182
1183 static HRESULT WINAPI isaxattributes_getValueFromName(
1184         ISAXAttributes* iface,
1185         const WCHAR *pUri,
1186         int nUri,
1187         const WCHAR *pLocalName,
1188         int nLocalName,
1189         const WCHAR **pValue,
1190         int *nValue)
1191 {
1192     HRESULT hr;
1193     int index;
1194     saxlocator *This = impl_from_ISAXAttributes( iface );
1195     TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), nUri,
1196             debugstr_w(pLocalName), nLocalName);
1197
1198     hr = ISAXAttributes_getIndexFromName(iface,
1199             pUri, nUri, pLocalName, nLocalName, &index);
1200     if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue);
1201
1202     return hr;
1203 }
1204
1205 static HRESULT WINAPI isaxattributes_getValueFromQName(
1206         ISAXAttributes* iface,
1207         const WCHAR *pQName,
1208         int nQName,
1209         const WCHAR **pValue,
1210         int *nValue)
1211 {
1212     HRESULT hr;
1213     int index;
1214     saxlocator *This = impl_from_ISAXAttributes( iface );
1215     TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQName);
1216
1217     hr = ISAXAttributes_getIndexFromQName(iface, pQName, nQName, &index);
1218     if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue);
1219
1220     return hr;
1221 }
1222
1223 static const struct ISAXAttributesVtbl isaxattributes_vtbl =
1224 {
1225     isaxattributes_QueryInterface,
1226     isaxattributes_AddRef,
1227     isaxattributes_Release,
1228     isaxattributes_getLength,
1229     isaxattributes_getURI,
1230     isaxattributes_getLocalName,
1231     isaxattributes_getQName,
1232     isaxattributes_getName,
1233     isaxattributes_getIndexFromName,
1234     isaxattributes_getIndexFromQName,
1235     isaxattributes_getType,
1236     isaxattributes_getTypeFromName,
1237     isaxattributes_getTypeFromQName,
1238     isaxattributes_getValue,
1239     isaxattributes_getValueFromName,
1240     isaxattributes_getValueFromQName
1241 };
1242
1243 static HRESULT SAXAttributes_populate(saxlocator *locator,
1244         int nb_namespaces, const xmlChar **xmlNamespaces,
1245         int nb_attributes, const xmlChar **xmlAttributes)
1246 {
1247     static const xmlChar xmlns[] = "xmlns";
1248     static const WCHAR xmlnsW[] = { 'x','m','l','n','s',0 };
1249
1250     struct _attributes *attrs;
1251     int i;
1252
1253     /* skip namespace definitions */
1254     if ((locator->saxreader->features & NamespacePrefixes) == 0)
1255         nb_namespaces = 0;
1256
1257     locator->nb_attributes = nb_namespaces + nb_attributes;
1258     if(locator->nb_attributes > locator->attributesSize)
1259     {
1260         attrs = heap_realloc(locator->attributes, sizeof(struct _attributes)*locator->nb_attributes*2);
1261         if(!attrs)
1262         {
1263             locator->nb_attributes = 0;
1264             return E_OUTOFMEMORY;
1265         }
1266         locator->attributes = attrs;
1267     }
1268     else
1269     {
1270         attrs = locator->attributes;
1271     }
1272
1273     for (i = 0; i < nb_namespaces; i++)
1274     {
1275         attrs[nb_attributes+i].szLocalname = SysAllocStringLen(NULL, 0);
1276         attrs[nb_attributes+i].szURI = locator->namespaceUri;
1277         attrs[nb_attributes+i].szValue = bstr_from_xmlChar(xmlNamespaces[2*i+1]);
1278         if(!xmlNamespaces[2*i])
1279             attrs[nb_attributes+i].szQName = SysAllocString(xmlnsW);
1280         else
1281             attrs[nb_attributes+i].szQName = QName_from_xmlChar(xmlns, xmlNamespaces[2*i]);
1282     }
1283
1284     for (i = 0; i < nb_attributes; i++)
1285     {
1286         static const xmlChar xmlA[] = "xml";
1287
1288         if (xmlStrEqual(xmlAttributes[i*5+1], xmlA))
1289             attrs[i].szURI = bstr_from_xmlChar(xmlAttributes[i*5+2]);
1290         else
1291             /* that's an important feature to keep same uri pointer for every reported attribute */
1292             attrs[i].szURI = find_element_uri(locator, xmlAttributes[i*5+2]);
1293
1294         attrs[i].szLocalname = bstr_from_xmlChar(xmlAttributes[i*5]);
1295         attrs[i].szValue = bstr_from_xmlCharN(xmlAttributes[i*5+3],
1296                 xmlAttributes[i*5+4]-xmlAttributes[i*5+3]);
1297         attrs[i].szQName = QName_from_xmlChar(xmlAttributes[i*5+1],
1298                 xmlAttributes[i*5]);
1299     }
1300
1301     return S_OK;
1302 }
1303
1304 /*** LibXML callbacks ***/
1305 static void libxmlStartDocument(void *ctx)
1306 {
1307     saxlocator *This = ctx;
1308     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1309     HRESULT hr;
1310
1311     if (This->saxreader->version >= MSXML4)
1312     {
1313         const xmlChar *p = This->pParserCtxt->input->cur-1;
1314         update_position(This, FALSE);
1315         while(p>This->pParserCtxt->input->base && *p!='>')
1316         {
1317             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1318                 This->line--;
1319             p--;
1320         }
1321         This->column = 0;
1322         for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1323             This->column++;
1324     }
1325
1326     if(has_content_handler(This))
1327     {
1328         if(This->vbInterface)
1329             hr = IVBSAXContentHandler_startDocument(handler->vbhandler);
1330         else
1331             hr = ISAXContentHandler_startDocument(handler->handler);
1332
1333         if (sax_callback_failed(This, hr))
1334             format_error_message_from_id(This, hr);
1335     }
1336 }
1337
1338 static void libxmlEndDocument(void *ctx)
1339 {
1340     saxlocator *This = ctx;
1341     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1342     HRESULT hr;
1343
1344     if (This->saxreader->version >= MSXML4) {
1345         update_position(This, FALSE);
1346         if(This->column > 1)
1347             This->line++;
1348         This->column = 0;
1349     } else {
1350         This->column = 0;
1351         This->line = 0;
1352     }
1353
1354     if(This->ret != S_OK) return;
1355
1356     if(has_content_handler(This))
1357     {
1358         if(This->vbInterface)
1359             hr = IVBSAXContentHandler_endDocument(handler->vbhandler);
1360         else
1361             hr = ISAXContentHandler_endDocument(handler->handler);
1362
1363         if (sax_callback_failed(This, hr))
1364             format_error_message_from_id(This, hr);
1365     }
1366 }
1367
1368 static void libxmlStartElementNS(
1369         void *ctx,
1370         const xmlChar *localname,
1371         const xmlChar *prefix,
1372         const xmlChar *URI,
1373         int nb_namespaces,
1374         const xmlChar **namespaces,
1375         int nb_attributes,
1376         int nb_defaulted,
1377         const xmlChar **attributes)
1378 {
1379     saxlocator *This = ctx;
1380     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1381     element_entry *element;
1382     HRESULT hr = S_OK;
1383     BSTR uri;
1384
1385     update_position(This, TRUE);
1386     if(*(This->pParserCtxt->input->cur) == '/')
1387         This->column++;
1388     if(This->saxreader->version < MSXML4)
1389         This->column++;
1390
1391     element = alloc_element_entry(localname, prefix, nb_namespaces, namespaces);
1392     push_element_ns(This, element);
1393
1394     if (is_namespaces_enabled(This->saxreader))
1395     {
1396         int i;
1397
1398         for (i = 0; i < nb_namespaces && has_content_handler(This); i++)
1399         {
1400             if (This->vbInterface)
1401                 hr = IVBSAXContentHandler_startPrefixMapping(
1402                         handler->vbhandler,
1403                         &element->ns[i].prefix,
1404                         &element->ns[i].uri);
1405             else
1406                 hr = ISAXContentHandler_startPrefixMapping(
1407                         handler->handler,
1408                         element->ns[i].prefix,
1409                         SysStringLen(element->ns[i].prefix),
1410                         element->ns[i].uri,
1411                         SysStringLen(element->ns[i].uri));
1412
1413             if (sax_callback_failed(This, hr))
1414             {
1415                 format_error_message_from_id(This, hr);
1416                 return;
1417             }
1418         }
1419     }
1420
1421     uri = find_element_uri(This, URI);
1422     hr = SAXAttributes_populate(This, nb_namespaces, namespaces, nb_attributes, attributes);
1423     if (hr == S_OK && has_content_handler(This))
1424     {
1425         BSTR local;
1426
1427         if (is_namespaces_enabled(This->saxreader))
1428             local = element->local;
1429         else
1430             uri = local = NULL;
1431
1432         if (This->vbInterface)
1433             hr = IVBSAXContentHandler_startElement(handler->vbhandler,
1434                     &uri, &local, &element->qname, &This->IVBSAXAttributes_iface);
1435         else
1436             hr = ISAXContentHandler_startElement(handler->handler,
1437                     uri, SysStringLen(uri),
1438                     local, SysStringLen(local),
1439                     element->qname, SysStringLen(element->qname),
1440                     &This->ISAXAttributes_iface);
1441
1442        if (sax_callback_failed(This, hr))
1443            format_error_message_from_id(This, hr);
1444     }
1445 }
1446
1447 static void libxmlEndElementNS(
1448         void *ctx,
1449         const xmlChar *localname,
1450         const xmlChar *prefix,
1451         const xmlChar *URI)
1452 {
1453     saxlocator *This = ctx;
1454     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1455     element_entry *element;
1456     const xmlChar *p;
1457     BSTR uri, local;
1458     HRESULT hr;
1459
1460     update_position(This, FALSE);
1461     p = This->pParserCtxt->input->cur;
1462
1463     if (This->saxreader->version >= MSXML4)
1464     {
1465         p--;
1466         while(p>This->pParserCtxt->input->base && *p!='>')
1467         {
1468             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1469                 This->line--;
1470             p--;
1471         }
1472     }
1473     else if(*(p-1)!='>' || *(p-2)!='/')
1474     {
1475         p--;
1476         while(p-2>=This->pParserCtxt->input->base
1477                 && *(p-2)!='<' && *(p-1)!='/')
1478         {
1479             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1480                 This->line--;
1481             p--;
1482         }
1483     }
1484     This->column = 0;
1485     for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1486         This->column++;
1487
1488     uri = find_element_uri(This, URI);
1489     element = pop_element_ns(This);
1490
1491     if (!has_content_handler(This))
1492     {
1493         This->nb_attributes = 0;
1494         free_element_entry(element);
1495         return;
1496     }
1497
1498     if (is_namespaces_enabled(This->saxreader))
1499         local = element->local;
1500     else
1501         uri = local = NULL;
1502
1503     if (This->vbInterface)
1504         hr = IVBSAXContentHandler_endElement(
1505                 handler->vbhandler,
1506                 &uri, &local, &element->qname);
1507     else
1508         hr = ISAXContentHandler_endElement(
1509                 handler->handler,
1510                 uri, SysStringLen(uri),
1511                 local, SysStringLen(local),
1512                 element->qname, SysStringLen(element->qname));
1513
1514     This->nb_attributes = 0;
1515
1516     if (sax_callback_failed(This, hr))
1517     {
1518         format_error_message_from_id(This, hr);
1519         free_element_entry(element);
1520         return;
1521     }
1522
1523     if (is_namespaces_enabled(This->saxreader))
1524     {
1525         int i = -1;
1526         while (iterate_endprefix_index(This, element, &i) && has_content_handler(This))
1527         {
1528             if (This->vbInterface)
1529                 hr = IVBSAXContentHandler_endPrefixMapping(
1530                         handler->vbhandler, &element->ns[i].prefix);
1531             else
1532                 hr = ISAXContentHandler_endPrefixMapping(
1533                         handler->handler, element->ns[i].prefix, SysStringLen(element->ns[i].prefix));
1534
1535             if (sax_callback_failed(This, hr)) break;
1536        }
1537
1538        if (sax_callback_failed(This, hr))
1539            format_error_message_from_id(This, hr);
1540     }
1541
1542     free_element_entry(element);
1543 }
1544
1545 static void libxmlCharacters(
1546         void *ctx,
1547         const xmlChar *ch,
1548         int len)
1549 {
1550     saxlocator *This = ctx;
1551     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1552     BSTR Chars;
1553     HRESULT hr;
1554     xmlChar *cur, *end;
1555     BOOL lastEvent = FALSE;
1556
1557     if(!(has_content_handler(This))) return;
1558
1559     update_position(This, FALSE);
1560     cur = (xmlChar*)This->pParserCtxt->input->cur;
1561     while(cur>=This->pParserCtxt->input->base && *cur!='>')
1562     {
1563         if(*cur=='\n' || (*cur=='\r' && *(cur+1)!='\n'))
1564             This->line--;
1565         cur--;
1566     }
1567     This->column = 1;
1568     for(; cur>=This->pParserCtxt->input->base && *cur!='\n' && *cur!='\r'; cur--)
1569         This->column++;
1570
1571     cur = (xmlChar*)ch;
1572     if(*(ch-1)=='\r') cur--;
1573     end = cur;
1574
1575     while(1)
1576     {
1577         while(end-ch<len && *end!='\r') end++;
1578         if(end-ch==len)
1579         {
1580             lastEvent = TRUE;
1581         }
1582         else
1583         {
1584             *end = '\n';
1585             end++;
1586         }
1587
1588         if (This->saxreader->version >= MSXML4)
1589         {
1590             xmlChar *p;
1591
1592             for(p=cur; p!=end; p++)
1593             {
1594                 if(*p=='\n')
1595                 {
1596                     This->line++;
1597                     This->column = 1;
1598                 }
1599                 else
1600                 {
1601                     This->column++;
1602                 }
1603             }
1604
1605             if(!lastEvent)
1606                 This->column = 0;
1607         }
1608
1609         Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur);
1610         if(This->vbInterface)
1611             hr = IVBSAXContentHandler_characters(handler->vbhandler, &Chars);
1612         else
1613             hr = ISAXContentHandler_characters(handler->handler, Chars, SysStringLen(Chars));
1614
1615         if (sax_callback_failed(This, hr))
1616         {
1617             format_error_message_from_id(This, hr);
1618             return;
1619         }
1620
1621         if (This->saxreader->version < MSXML4)
1622             This->column += end-cur;
1623
1624         if(lastEvent)
1625             break;
1626
1627         *(end-1) = '\r';
1628         if(*end == '\n')
1629         {
1630             end++;
1631             This->column++;
1632         }
1633         cur = end;
1634
1635         if(end-ch == len) break;
1636     }
1637 }
1638
1639 static void libxmlSetDocumentLocator(
1640         void *ctx,
1641         xmlSAXLocatorPtr loc)
1642 {
1643     saxlocator *This = ctx;
1644     struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1645     HRESULT hr = S_OK;
1646
1647     if(has_content_handler(This))
1648     {
1649         if(This->vbInterface)
1650             hr = IVBSAXContentHandler_putref_documentLocator(handler->vbhandler,
1651                     &This->IVBSAXLocator_iface);
1652         else
1653             hr = ISAXContentHandler_putDocumentLocator(handler->handler, &This->ISAXLocator_iface);
1654     }
1655
1656     if(FAILED(hr))
1657         format_error_message_from_id(This, hr);
1658 }
1659
1660 static void libxmlComment(void *ctx, const xmlChar *value)
1661 {
1662     saxlocator *This = ctx;
1663     struct saxlexicalhandler_iface *handler = saxreader_get_lexicalhandler(This->saxreader);
1664     BSTR bValue;
1665     HRESULT hr;
1666     const xmlChar *p = This->pParserCtxt->input->cur;
1667
1668     update_position(This, FALSE);
1669     while(p-4>=This->pParserCtxt->input->base
1670             && memcmp(p-4, "<!--", sizeof(char[4])))
1671     {
1672         if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1673             This->line--;
1674         p--;
1675     }
1676
1677     This->column = 0;
1678     for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1679         This->column++;
1680
1681     if (!has_lexical_handler(This)) return;
1682
1683     bValue = pooled_bstr_from_xmlChar(&This->saxreader->pool, value);
1684
1685     if (This->vbInterface)
1686         hr = IVBSAXLexicalHandler_comment(handler->vbhandler, &bValue);
1687     else
1688         hr = ISAXLexicalHandler_comment(handler->handler, bValue, SysStringLen(bValue));
1689
1690     if(FAILED(hr))
1691         format_error_message_from_id(This, hr);
1692 }
1693
1694 static void libxmlFatalError(void *ctx, const char *msg, ...)
1695 {
1696     saxlocator *This = ctx;
1697     struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader);
1698     char message[1024];
1699     WCHAR *error;
1700     DWORD len;
1701     va_list args;
1702
1703     if(This->ret != S_OK) {
1704         xmlStopParser(This->pParserCtxt);
1705         return;
1706     }
1707
1708     va_start(args, msg);
1709     vsprintf(message, msg, args);
1710     va_end(args);
1711
1712     len = MultiByteToWideChar(CP_UNIXCP, 0, message, -1, NULL, 0);
1713     error = heap_alloc(sizeof(WCHAR)*len);
1714     if(error)
1715     {
1716         MultiByteToWideChar(CP_UNIXCP, 0, message, -1, error, len);
1717         TRACE("fatal error for %p: %s\n", This, debugstr_w(error));
1718     }
1719
1720     if(!has_error_handler(This))
1721     {
1722         xmlStopParser(This->pParserCtxt);
1723         This->ret = E_FAIL;
1724         heap_free(error);
1725         return;
1726     }
1727
1728     FIXME("Error handling is not compatible.\n");
1729
1730     if(This->vbInterface)
1731     {
1732         BSTR bstrError = SysAllocString(error);
1733         IVBSAXErrorHandler_fatalError(handler->vbhandler, &This->IVBSAXLocator_iface,
1734                 &bstrError, E_FAIL);
1735         SysFreeString(bstrError);
1736     }
1737     else
1738         ISAXErrorHandler_fatalError(handler->handler, &This->ISAXLocator_iface, error, E_FAIL);
1739
1740     heap_free(error);
1741
1742     xmlStopParser(This->pParserCtxt);
1743     This->ret = E_FAIL;
1744 }
1745
1746 static void libxmlCDataBlock(void *ctx, const xmlChar *value, int len)
1747 {
1748     saxlocator *This = ctx;
1749     struct saxcontenthandler_iface *content = saxreader_get_contenthandler(This->saxreader);
1750     struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(This->saxreader);
1751     HRESULT hr = S_OK;
1752     xmlChar *beg = (xmlChar*)This->pParserCtxt->input->cur-len;
1753     xmlChar *cur, *end;
1754     int realLen;
1755     BSTR Chars;
1756     BOOL lastEvent = FALSE, change;
1757
1758     update_position(This, FALSE);
1759     while(beg-9>=This->pParserCtxt->input->base
1760             && memcmp(beg-9, "<![CDATA[", sizeof(char[9])))
1761     {
1762         if(*beg=='\n' || (*beg=='\r' && *(beg+1)!='\n'))
1763             This->line--;
1764         beg--;
1765     }
1766     This->column = 0;
1767     for(; beg>=This->pParserCtxt->input->base && *beg!='\n' && *beg!='\r'; beg--)
1768         This->column++;
1769
1770     if (has_lexical_handler(This))
1771     {
1772        if (This->vbInterface)
1773            hr = IVBSAXLexicalHandler_startCDATA(lexical->vbhandler);
1774        else
1775            hr = ISAXLexicalHandler_startCDATA(lexical->handler);
1776     }
1777
1778     if(FAILED(hr))
1779     {
1780         format_error_message_from_id(This, hr);
1781         return;
1782     }
1783
1784     realLen = This->pParserCtxt->input->cur-beg-3;
1785     cur = beg;
1786     end = beg;
1787
1788     while(1)
1789     {
1790         while(end-beg<realLen && *end!='\r') end++;
1791         if(end-beg==realLen)
1792         {
1793             end--;
1794             lastEvent = TRUE;
1795         }
1796         else if(end-beg==realLen-1 && *end=='\r' && *(end+1)=='\n')
1797             lastEvent = TRUE;
1798
1799         if(*end == '\r') change = TRUE;
1800         else change = FALSE;
1801
1802         if(change) *end = '\n';
1803
1804         if (has_content_handler(This))
1805         {
1806             Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur+1);
1807             if (This->vbInterface)
1808                 hr = IVBSAXContentHandler_characters(content->vbhandler, &Chars);
1809             else
1810                 hr = ISAXContentHandler_characters(content->handler, Chars, SysStringLen(Chars));
1811         }
1812
1813         if(change) *end = '\r';
1814
1815         if(lastEvent)
1816             break;
1817
1818         This->column += end-cur+2;
1819         end += 2;
1820         cur = end;
1821     }
1822
1823     if (has_lexical_handler(This))
1824     {
1825         if (This->vbInterface)
1826             hr = IVBSAXLexicalHandler_endCDATA(lexical->vbhandler);
1827         else
1828             hr = ISAXLexicalHandler_endCDATA(lexical->handler);
1829     }
1830
1831     if(FAILED(hr))
1832         format_error_message_from_id(This, hr);
1833
1834     This->column += 4+end-cur;
1835 }
1836
1837 /*** IVBSAXLocator interface ***/
1838 /*** IUnknown methods ***/
1839 static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator* iface, REFIID riid, void **ppvObject)
1840 {
1841     saxlocator *This = impl_from_IVBSAXLocator( iface );
1842
1843     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject);
1844
1845     *ppvObject = NULL;
1846
1847     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
1848             IsEqualGUID( riid, &IID_IDispatch) ||
1849             IsEqualGUID( riid, &IID_IVBSAXLocator ))
1850     {
1851         *ppvObject = iface;
1852     }
1853     else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
1854     {
1855         *ppvObject = &This->IVBSAXAttributes_iface;
1856     }
1857     else
1858     {
1859         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1860         return E_NOINTERFACE;
1861     }
1862
1863     IVBSAXLocator_AddRef( iface );
1864
1865     return S_OK;
1866 }
1867
1868 static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator* iface)
1869 {
1870     saxlocator *This = impl_from_IVBSAXLocator( iface );
1871     TRACE("%p\n", This );
1872     return InterlockedIncrement( &This->ref );
1873 }
1874
1875 static ULONG WINAPI ivbsaxlocator_Release(
1876         IVBSAXLocator* iface)
1877 {
1878     saxlocator *This = impl_from_IVBSAXLocator( iface );
1879     return ISAXLocator_Release((ISAXLocator*)&This->IVBSAXLocator_iface);
1880 }
1881
1882 /*** IDispatch methods ***/
1883 static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount( IVBSAXLocator *iface, UINT* pctinfo )
1884 {
1885     saxlocator *This = impl_from_IVBSAXLocator( iface );
1886
1887     TRACE("(%p)->(%p)\n", This, pctinfo);
1888
1889     *pctinfo = 1;
1890
1891     return S_OK;
1892 }
1893
1894 static HRESULT WINAPI ivbsaxlocator_GetTypeInfo(
1895     IVBSAXLocator *iface,
1896     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1897 {
1898     saxlocator *This = impl_from_IVBSAXLocator( iface );
1899     HRESULT hr;
1900
1901     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1902
1903     hr = get_typeinfo(IVBSAXLocator_tid, ppTInfo);
1904
1905     return hr;
1906 }
1907
1908 static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames(
1909     IVBSAXLocator *iface,
1910     REFIID riid,
1911     LPOLESTR* rgszNames,
1912     UINT cNames,
1913     LCID lcid,
1914     DISPID* rgDispId)
1915 {
1916     saxlocator *This = impl_from_IVBSAXLocator( iface );
1917     ITypeInfo *typeinfo;
1918     HRESULT hr;
1919
1920     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1921           lcid, rgDispId);
1922
1923     if(!rgszNames || cNames == 0 || !rgDispId)
1924         return E_INVALIDARG;
1925
1926     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
1927     if(SUCCEEDED(hr))
1928     {
1929         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1930         ITypeInfo_Release(typeinfo);
1931     }
1932
1933     return hr;
1934 }
1935
1936 static HRESULT WINAPI ivbsaxlocator_Invoke(
1937     IVBSAXLocator *iface,
1938     DISPID dispIdMember,
1939     REFIID riid,
1940     LCID lcid,
1941     WORD wFlags,
1942     DISPPARAMS* pDispParams,
1943     VARIANT* pVarResult,
1944     EXCEPINFO* pExcepInfo,
1945     UINT* puArgErr)
1946 {
1947     saxlocator *This = impl_from_IVBSAXLocator( iface );
1948     ITypeInfo *typeinfo;
1949     HRESULT hr;
1950
1951     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1952           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1953
1954     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
1955     if(SUCCEEDED(hr))
1956     {
1957         hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXLocator_iface, dispIdMember, wFlags,
1958                 pDispParams, pVarResult, pExcepInfo, puArgErr);
1959         ITypeInfo_Release(typeinfo);
1960     }
1961
1962     return hr;
1963 }
1964
1965 /*** IVBSAXLocator methods ***/
1966 static HRESULT WINAPI ivbsaxlocator_get_columnNumber(
1967         IVBSAXLocator* iface,
1968         int *pnColumn)
1969 {
1970     saxlocator *This = impl_from_IVBSAXLocator( iface );
1971     return ISAXLocator_getColumnNumber((ISAXLocator*)&This->IVBSAXLocator_iface, pnColumn);
1972 }
1973
1974 static HRESULT WINAPI ivbsaxlocator_get_lineNumber(
1975         IVBSAXLocator* iface,
1976         int *pnLine)
1977 {
1978     saxlocator *This = impl_from_IVBSAXLocator( iface );
1979     return ISAXLocator_getLineNumber((ISAXLocator*)&This->IVBSAXLocator_iface, pnLine);
1980 }
1981
1982 static HRESULT WINAPI ivbsaxlocator_get_publicId(
1983         IVBSAXLocator* iface,
1984         BSTR* publicId)
1985 {
1986     saxlocator *This = impl_from_IVBSAXLocator( iface );
1987     return ISAXLocator_getPublicId((ISAXLocator*)&This->IVBSAXLocator_iface,
1988             (const WCHAR**)publicId);
1989 }
1990
1991 static HRESULT WINAPI ivbsaxlocator_get_systemId(
1992         IVBSAXLocator* iface,
1993         BSTR* systemId)
1994 {
1995     saxlocator *This = impl_from_IVBSAXLocator( iface );
1996     return ISAXLocator_getSystemId((ISAXLocator*)&This->IVBSAXLocator_iface,
1997             (const WCHAR**)systemId);
1998 }
1999
2000 static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl =
2001 {
2002     ivbsaxlocator_QueryInterface,
2003     ivbsaxlocator_AddRef,
2004     ivbsaxlocator_Release,
2005     ivbsaxlocator_GetTypeInfoCount,
2006     ivbsaxlocator_GetTypeInfo,
2007     ivbsaxlocator_GetIDsOfNames,
2008     ivbsaxlocator_Invoke,
2009     ivbsaxlocator_get_columnNumber,
2010     ivbsaxlocator_get_lineNumber,
2011     ivbsaxlocator_get_publicId,
2012     ivbsaxlocator_get_systemId
2013 };
2014
2015 /*** ISAXLocator interface ***/
2016 /*** IUnknown methods ***/
2017 static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid, void **ppvObject)
2018 {
2019     saxlocator *This = impl_from_ISAXLocator( iface );
2020
2021     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2022
2023     *ppvObject = NULL;
2024
2025     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2026             IsEqualGUID( riid, &IID_ISAXLocator ))
2027     {
2028         *ppvObject = iface;
2029     }
2030     else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
2031     {
2032         *ppvObject = &This->ISAXAttributes_iface;
2033     }
2034     else
2035     {
2036         WARN("interface %s not implemented\n", debugstr_guid(riid));
2037         return E_NOINTERFACE;
2038     }
2039
2040     ISAXLocator_AddRef( iface );
2041
2042     return S_OK;
2043 }
2044
2045 static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface)
2046 {
2047     saxlocator *This = impl_from_ISAXLocator( iface );
2048     ULONG ref = InterlockedIncrement( &This->ref );
2049     TRACE("(%p)->(%d)\n", This, ref);
2050     return ref;
2051 }
2052
2053 static ULONG WINAPI isaxlocator_Release(
2054         ISAXLocator* iface)
2055 {
2056     saxlocator *This = impl_from_ISAXLocator( iface );
2057     LONG ref = InterlockedDecrement( &This->ref );
2058
2059     TRACE("(%p)->(%d)\n", This, ref );
2060
2061     if (ref == 0)
2062     {
2063         element_entry *element, *element2;
2064         int index;
2065
2066         SysFreeString(This->publicId);
2067         SysFreeString(This->systemId);
2068         SysFreeString(This->namespaceUri);
2069
2070         for(index=0; index<This->nb_attributes; index++)
2071         {
2072             SysFreeString(This->attributes[index].szLocalname);
2073             SysFreeString(This->attributes[index].szValue);
2074             SysFreeString(This->attributes[index].szQName);
2075         }
2076         heap_free(This->attributes);
2077
2078         /* element stack */
2079         LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry)
2080         {
2081             list_remove(&element->entry);
2082             free_element_entry(element);
2083         }
2084
2085         ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface);
2086         heap_free( This );
2087     }
2088
2089     return ref;
2090 }
2091
2092 /*** ISAXLocator methods ***/
2093 static HRESULT WINAPI isaxlocator_getColumnNumber(
2094         ISAXLocator* iface,
2095         int *pnColumn)
2096 {
2097     saxlocator *This = impl_from_ISAXLocator( iface );
2098
2099     *pnColumn = This->column;
2100     return S_OK;
2101 }
2102
2103 static HRESULT WINAPI isaxlocator_getLineNumber(
2104         ISAXLocator* iface,
2105         int *pnLine)
2106 {
2107     saxlocator *This = impl_from_ISAXLocator( iface );
2108
2109     *pnLine = This->line;
2110     return S_OK;
2111 }
2112
2113 static HRESULT WINAPI isaxlocator_getPublicId(
2114         ISAXLocator* iface,
2115         const WCHAR ** ppwchPublicId)
2116 {
2117     BSTR publicId;
2118     saxlocator *This = impl_from_ISAXLocator( iface );
2119
2120     SysFreeString(This->publicId);
2121
2122     publicId = bstr_from_xmlChar(xmlSAX2GetPublicId(This->pParserCtxt));
2123     if(SysStringLen(publicId))
2124         This->publicId = (WCHAR*)&publicId;
2125     else
2126     {
2127         SysFreeString(publicId);
2128         This->publicId = NULL;
2129     }
2130
2131     *ppwchPublicId = This->publicId;
2132     return S_OK;
2133 }
2134
2135 static HRESULT WINAPI isaxlocator_getSystemId(
2136         ISAXLocator* iface,
2137         const WCHAR ** ppwchSystemId)
2138 {
2139     BSTR systemId;
2140     saxlocator *This = impl_from_ISAXLocator( iface );
2141
2142     SysFreeString(This->systemId);
2143
2144     systemId = bstr_from_xmlChar(xmlSAX2GetSystemId(This->pParserCtxt));
2145     if(SysStringLen(systemId))
2146         This->systemId = (WCHAR*)&systemId;
2147     else
2148     {
2149         SysFreeString(systemId);
2150         This->systemId = NULL;
2151     }
2152
2153     *ppwchSystemId = This->systemId;
2154     return S_OK;
2155 }
2156
2157 static const struct ISAXLocatorVtbl SAXLocatorVtbl =
2158 {
2159     isaxlocator_QueryInterface,
2160     isaxlocator_AddRef,
2161     isaxlocator_Release,
2162     isaxlocator_getColumnNumber,
2163     isaxlocator_getLineNumber,
2164     isaxlocator_getPublicId,
2165     isaxlocator_getSystemId
2166 };
2167
2168 static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, BOOL vbInterface)
2169 {
2170     static const WCHAR w3xmlns[] = { 'h','t','t','p',':','/','/', 'w','w','w','.','w','3','.',
2171         'o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0 };
2172
2173     saxlocator *locator;
2174
2175     locator = heap_alloc( sizeof (*locator) );
2176     if( !locator )
2177         return E_OUTOFMEMORY;
2178
2179     locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl;
2180     locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl;
2181     locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl;
2182     locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl;
2183     locator->ref = 1;
2184     locator->vbInterface = vbInterface;
2185
2186     locator->saxreader = reader;
2187     ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface);
2188
2189     locator->pParserCtxt = NULL;
2190     locator->publicId = NULL;
2191     locator->systemId = NULL;
2192     locator->line = reader->version < MSXML4 ? 0 : 1;
2193     locator->column = 0;
2194     locator->ret = S_OK;
2195     if (locator->saxreader->version >= MSXML6)
2196         locator->namespaceUri = SysAllocString(w3xmlns);
2197     else
2198         locator->namespaceUri = SysAllocStringLen(NULL, 0);
2199     if(!locator->namespaceUri)
2200     {
2201         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2202         heap_free(locator);
2203         return E_OUTOFMEMORY;
2204     }
2205
2206     locator->attributesSize = 8;
2207     locator->nb_attributes = 0;
2208     locator->attributes = heap_alloc(sizeof(struct _attributes)*locator->attributesSize);
2209     if(!locator->attributes)
2210     {
2211         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2212         SysFreeString(locator->namespaceUri);
2213         heap_free(locator);
2214         return E_OUTOFMEMORY;
2215     }
2216
2217     list_init(&locator->elements);
2218
2219     *ppsaxlocator = locator;
2220
2221     TRACE("returning %p\n", *ppsaxlocator);
2222
2223     return S_OK;
2224 }
2225
2226 /*** SAXXMLReader internal functions ***/
2227 static HRESULT internal_parseBuffer(saxreader *This, const char *buffer, int size, BOOL vbInterface)
2228 {
2229     xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
2230     xmlChar *enc_name = NULL;
2231     saxlocator *locator;
2232     HRESULT hr;
2233
2234     TRACE("(%p)->(%p %d)\n", This, buffer, size);
2235
2236     hr = SAXLocator_create(This, &locator, vbInterface);
2237     if (FAILED(hr))
2238         return hr;
2239
2240     if (size >= 4)
2241     {
2242         const unsigned char *buff = (unsigned char*)buffer;
2243
2244         encoding = xmlDetectCharEncoding((xmlChar*)buffer, 4);
2245         enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
2246         TRACE("detected encoding: %s\n", enc_name);
2247         /* skip BOM, parser won't switch encodings and so won't skip it on its own */
2248         if ((encoding == XML_CHAR_ENCODING_UTF8) &&
2249             buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF)
2250         {
2251             buffer += 3;
2252             size -= 3;
2253         }
2254     }
2255
2256     /* if libxml2 detection failed try to guess */
2257     if (encoding == XML_CHAR_ENCODING_NONE)
2258     {
2259         const WCHAR *ptr = (WCHAR*)buffer;
2260         /* xml declaration with possibly specfied encoding will be still handled by parser */
2261         if ((size >= 2) && *ptr == '<' && ptr[1] != '?')
2262         {
2263             enc_name = (xmlChar*)xmlGetCharEncodingName(XML_CHAR_ENCODING_UTF16LE);
2264             encoding = XML_CHAR_ENCODING_UTF16LE;
2265         }
2266     }
2267     else if (encoding == XML_CHAR_ENCODING_UTF8)
2268         enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
2269     else
2270         enc_name = NULL;
2271
2272     locator->pParserCtxt = xmlCreateMemoryParserCtxt(buffer, size);
2273     if (!locator->pParserCtxt)
2274     {
2275         ISAXLocator_Release(&locator->ISAXLocator_iface);
2276         return E_FAIL;
2277     }
2278
2279     if (enc_name)
2280     {
2281         locator->pParserCtxt->encoding = xmlStrdup(enc_name);
2282         if (encoding == XML_CHAR_ENCODING_UTF16LE) {
2283             TRACE("switching to %s\n", enc_name);
2284             xmlSwitchEncoding(locator->pParserCtxt, encoding);
2285         }
2286     }
2287
2288     xmlFree(locator->pParserCtxt->sax);
2289     locator->pParserCtxt->sax = &locator->saxreader->sax;
2290     locator->pParserCtxt->userData = locator;
2291
2292     This->isParsing = TRUE;
2293     if(xmlParseDocument(locator->pParserCtxt) == -1 && locator->ret == S_OK)
2294         hr = E_FAIL;
2295     else
2296         hr = locator->ret;
2297     This->isParsing = FALSE;
2298
2299     if(locator->pParserCtxt)
2300     {
2301         locator->pParserCtxt->sax = NULL;
2302         xmlFreeParserCtxt(locator->pParserCtxt);
2303         locator->pParserCtxt = NULL;
2304     }
2305
2306     ISAXLocator_Release(&locator->ISAXLocator_iface);
2307     return hr;
2308 }
2309
2310 static HRESULT internal_parseStream(saxreader *This, IStream *stream, BOOL vbInterface)
2311 {
2312     saxlocator *locator;
2313     HRESULT hr;
2314     ULONG dataRead;
2315     char data[1024];
2316     int ret;
2317
2318     dataRead = 0;
2319     hr = IStream_Read(stream, data, sizeof(data), &dataRead);
2320     if(FAILED(hr)) return hr;
2321
2322     hr = SAXLocator_create(This, &locator, vbInterface);
2323     if(FAILED(hr)) return hr;
2324
2325     locator->pParserCtxt = xmlCreatePushParserCtxt(
2326             &locator->saxreader->sax, locator,
2327             data, dataRead, NULL);
2328     if(!locator->pParserCtxt)
2329     {
2330         ISAXLocator_Release(&locator->ISAXLocator_iface);
2331         return E_FAIL;
2332     }
2333
2334     This->isParsing = TRUE;
2335
2336     if(dataRead != sizeof(data))
2337     {
2338         ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2339         hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2340     }
2341     else
2342     {
2343         while(1)
2344         {
2345             dataRead = 0;
2346             hr = IStream_Read(stream, data, sizeof(data), &dataRead);
2347             if (FAILED(hr)) break;
2348
2349             ret = xmlParseChunk(locator->pParserCtxt, data, dataRead, 0);
2350             hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2351
2352             if (hr != S_OK) break;
2353
2354             if (dataRead != sizeof(data))
2355             {
2356                 ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2357                 hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2358                 break;
2359             }
2360         }
2361     }
2362
2363     This->isParsing = FALSE;
2364
2365     xmlFreeParserCtxt(locator->pParserCtxt);
2366     locator->pParserCtxt = NULL;
2367     ISAXLocator_Release(&locator->ISAXLocator_iface);
2368     return hr;
2369 }
2370
2371 static HRESULT internal_getEntityResolver(
2372         saxreader *This,
2373         void *pEntityResolver,
2374         BOOL vbInterface)
2375 {
2376     FIXME("(%p)->(%p) stub\n", This, pEntityResolver);
2377     return E_NOTIMPL;
2378 }
2379
2380 static HRESULT internal_putEntityResolver(
2381         saxreader *This,
2382         void *pEntityResolver,
2383         BOOL vbInterface)
2384 {
2385     FIXME("(%p)->(%p) stub\n", This, pEntityResolver);
2386     return E_NOTIMPL;
2387 }
2388
2389 static HRESULT internal_parse(
2390         saxreader* This,
2391         VARIANT varInput,
2392         BOOL vbInterface)
2393 {
2394     HRESULT hr;
2395
2396     TRACE("(%p)->(%s)\n", This, debugstr_variant(&varInput));
2397
2398     /* Dispose of the BSTRs in the pool from a prior run, if any. */
2399     free_bstr_pool(&This->pool);
2400
2401     switch(V_VT(&varInput))
2402     {
2403         case VT_BSTR:
2404             hr = internal_parseBuffer(This, (const char*)V_BSTR(&varInput),
2405                     strlenW(V_BSTR(&varInput))*sizeof(WCHAR), vbInterface);
2406             break;
2407         case VT_ARRAY|VT_UI1: {
2408             void *pSAData;
2409             LONG lBound, uBound;
2410             ULONG dataRead;
2411
2412             hr = SafeArrayGetLBound(V_ARRAY(&varInput), 1, &lBound);
2413             if(hr != S_OK) break;
2414             hr = SafeArrayGetUBound(V_ARRAY(&varInput), 1, &uBound);
2415             if(hr != S_OK) break;
2416             dataRead = (uBound-lBound)*SafeArrayGetElemsize(V_ARRAY(&varInput));
2417             hr = SafeArrayAccessData(V_ARRAY(&varInput), &pSAData);
2418             if(hr != S_OK) break;
2419             hr = internal_parseBuffer(This, pSAData, dataRead, vbInterface);
2420             SafeArrayUnaccessData(V_ARRAY(&varInput));
2421             break;
2422         }
2423         case VT_UNKNOWN:
2424         case VT_DISPATCH: {
2425             IPersistStream *persistStream;
2426             IStream *stream = NULL;
2427             IXMLDOMDocument *xmlDoc;
2428
2429             if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2430                         &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK)
2431             {
2432                 BSTR bstrData;
2433
2434                 IXMLDOMDocument_get_xml(xmlDoc, &bstrData);
2435                 hr = internal_parseBuffer(This, (const char*)bstrData,
2436                         SysStringByteLen(bstrData), vbInterface);
2437                 IXMLDOMDocument_Release(xmlDoc);
2438                 SysFreeString(bstrData);
2439                 break;
2440             }
2441
2442             if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2443                         &IID_IPersistStream, (void**)&persistStream) == S_OK)
2444             {
2445                 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2446                 if(hr != S_OK)
2447                 {
2448                     IPersistStream_Release(persistStream);
2449                     return hr;
2450                 }
2451
2452                 hr = IPersistStream_Save(persistStream, stream, TRUE);
2453                 IPersistStream_Release(persistStream);
2454                 if(hr != S_OK)
2455                 {
2456                     IStream_Release(stream);
2457                     stream = NULL;
2458                 }
2459             }
2460
2461             if(stream || IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2462                         &IID_IStream, (void**)&stream) == S_OK)
2463             {
2464                 hr = internal_parseStream(This, stream, vbInterface);
2465                 IStream_Release(stream);
2466                 break;
2467             }
2468         }
2469         default:
2470             WARN("vt %d not implemented\n", V_VT(&varInput));
2471             hr = E_INVALIDARG;
2472     }
2473
2474     return hr;
2475 }
2476
2477 static HRESULT internal_vbonDataAvailable(void *obj, char *ptr, DWORD len)
2478 {
2479     saxreader *This = obj;
2480
2481     return internal_parseBuffer(This, ptr, len, TRUE);
2482 }
2483
2484 static HRESULT internal_onDataAvailable(void *obj, char *ptr, DWORD len)
2485 {
2486     saxreader *This = obj;
2487
2488     return internal_parseBuffer(This, ptr, len, FALSE);
2489 }
2490
2491 static HRESULT internal_parseURL(
2492         saxreader* This,
2493         const WCHAR *url,
2494         BOOL vbInterface)
2495 {
2496     IMoniker *mon;
2497     bsc_t *bsc;
2498     HRESULT hr;
2499
2500     TRACE("(%p)->(%s)\n", This, debugstr_w(url));
2501
2502     hr = create_moniker_from_url(url, &mon);
2503     if(FAILED(hr))
2504         return hr;
2505
2506     if(vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, This, &bsc);
2507     else hr = bind_url(mon, internal_onDataAvailable, This, &bsc);
2508     IMoniker_Release(mon);
2509
2510     if(FAILED(hr))
2511         return hr;
2512
2513     return detach_bsc(bsc);
2514 }
2515
2516 static HRESULT internal_putProperty(
2517     saxreader* This,
2518     const WCHAR *prop,
2519     VARIANT value,
2520     BOOL vbInterface)
2521 {
2522     TRACE("(%p)->(%s %s)\n", This, debugstr_w(prop), debugstr_variant(&value));
2523
2524     if(!memcmp(prop, PropertyDeclHandlerW, sizeof(PropertyDeclHandlerW)))
2525     {
2526         if(This->isParsing) return E_FAIL;
2527
2528         switch (V_VT(&value))
2529         {
2530         case VT_EMPTY:
2531             saxreader_put_handler(This, SAXDeclHandler, NULL, vbInterface);
2532             break;
2533         case VT_UNKNOWN:
2534         {
2535             IUnknown *handler = NULL;
2536
2537             if (V_UNKNOWN(&value))
2538             {
2539                 HRESULT hr;
2540
2541                 if (vbInterface)
2542                     hr = IUnknown_QueryInterface(V_UNKNOWN(&value), &IID_IVBSAXDeclHandler, (void**)&handler);
2543                 else
2544                     hr = IUnknown_QueryInterface(V_UNKNOWN(&value), &IID_ISAXDeclHandler, (void**)&handler);
2545                 if (FAILED(hr)) return hr;
2546             }
2547
2548             saxreader_put_handler(This, SAXDeclHandler, handler, vbInterface);
2549             if (handler) IUnknown_Release(handler);
2550             break;
2551         }
2552         default:
2553             return E_INVALIDARG;
2554         }
2555
2556         return S_OK;
2557     }
2558
2559     if(!memcmp(prop, PropertyLexicalHandlerW, sizeof(PropertyLexicalHandlerW)))
2560     {
2561         if(This->isParsing) return E_FAIL;
2562
2563         switch (V_VT(&value))
2564         {
2565         case VT_EMPTY:
2566             saxreader_put_handler(This, SAXLexicalHandler, NULL, vbInterface);
2567             break;
2568         case VT_UNKNOWN:
2569         {
2570             IUnknown *handler = NULL;
2571
2572             if (V_UNKNOWN(&value))
2573             {
2574                 HRESULT hr;
2575
2576                 if (vbInterface)
2577                     hr = IUnknown_QueryInterface(V_UNKNOWN(&value), &IID_IVBSAXLexicalHandler, (void**)&handler);
2578                 else
2579                     hr = IUnknown_QueryInterface(V_UNKNOWN(&value), &IID_ISAXLexicalHandler, (void**)&handler);
2580                 if (FAILED(hr)) return hr;
2581             }
2582
2583             saxreader_put_handler(This, SAXLexicalHandler, handler, vbInterface);
2584             if (handler) IUnknown_Release(handler);
2585             break;
2586         }
2587         default:
2588             return E_INVALIDARG;
2589         }
2590
2591         return S_OK;
2592     }
2593
2594     if(!memcmp(prop, PropertyMaxXMLSizeW, sizeof(PropertyMaxXMLSizeW)))
2595     {
2596         if (V_VT(&value) == VT_I4 && V_I4(&value) == 0) return S_OK;
2597         FIXME("(%p)->(%s): max-xml-size unsupported\n", This, debugstr_variant(&value));
2598         return E_NOTIMPL;
2599     }
2600
2601     if(!memcmp(prop, PropertyMaxElementDepthW, sizeof(PropertyMaxElementDepthW)))
2602     {
2603         if (V_VT(&value) == VT_I4 && V_I4(&value) == 0) return S_OK;
2604         FIXME("(%p)->(%s): max-element-depth unsupported\n", This, debugstr_variant(&value));
2605         return E_NOTIMPL;
2606     }
2607
2608     FIXME("(%p)->(%s:%s): unsupported property\n", This, debugstr_w(prop), debugstr_variant(&value));
2609
2610     if(!memcmp(prop, PropertyCharsetW, sizeof(PropertyCharsetW)))
2611         return E_NOTIMPL;
2612
2613     if(!memcmp(prop, PropertyDomNodeW, sizeof(PropertyDomNodeW)))
2614         return E_FAIL;
2615
2616     if(!memcmp(prop, PropertyInputSourceW, sizeof(PropertyInputSourceW)))
2617         return E_NOTIMPL;
2618
2619     if(!memcmp(prop, PropertySchemaDeclHandlerW, sizeof(PropertySchemaDeclHandlerW)))
2620         return E_NOTIMPL;
2621
2622     if(!memcmp(prop, PropertyXMLDeclEncodingW, sizeof(PropertyXMLDeclEncodingW)))
2623         return E_FAIL;
2624
2625     if(!memcmp(prop, PropertyXMLDeclStandaloneW, sizeof(PropertyXMLDeclStandaloneW)))
2626         return E_FAIL;
2627
2628     if(!memcmp(prop, PropertyXMLDeclVersionW, sizeof(PropertyXMLDeclVersionW)))
2629         return E_FAIL;
2630
2631     return E_INVALIDARG;
2632 }
2633
2634 static HRESULT internal_getProperty(const saxreader* This, const WCHAR *prop, VARIANT *value, BOOL vb)
2635 {
2636     TRACE("(%p)->(%s)\n", This, debugstr_w(prop));
2637
2638     if (!value) return E_POINTER;
2639
2640     if (!memcmp(PropertyLexicalHandlerW, prop, sizeof(PropertyLexicalHandlerW)))
2641     {
2642         V_VT(value) = VT_UNKNOWN;
2643         saxreader_get_handler(This, SAXLexicalHandler, vb, (void**)&V_UNKNOWN(value));
2644         return S_OK;
2645     }
2646
2647     if (!memcmp(PropertyDeclHandlerW, prop, sizeof(PropertyDeclHandlerW)))
2648     {
2649         V_VT(value) = VT_UNKNOWN;
2650         saxreader_get_handler(This, SAXDeclHandler, vb, (void**)&V_UNKNOWN(value));
2651         return S_OK;
2652     }
2653
2654     FIXME("(%p)->(%s) unsupported property\n", This, debugstr_w(prop));
2655
2656     return E_NOTIMPL;
2657 }
2658
2659 /*** IVBSAXXMLReader interface ***/
2660 /*** IUnknown methods ***/
2661 static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID riid, void **ppvObject)
2662 {
2663     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2664
2665     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2666
2667     *ppvObject = NULL;
2668
2669     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2670          IsEqualGUID( riid, &IID_IDispatch ) ||
2671          IsEqualGUID( riid, &IID_IVBSAXXMLReader ))
2672     {
2673         *ppvObject = iface;
2674     }
2675     else if( IsEqualGUID( riid, &IID_ISAXXMLReader ))
2676     {
2677         *ppvObject = &This->ISAXXMLReader_iface;
2678     }
2679     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
2680     {
2681         return *ppvObject ? S_OK : E_NOINTERFACE;
2682     }
2683     else
2684     {
2685         FIXME("interface %s not implemented\n", debugstr_guid(riid));
2686         return E_NOINTERFACE;
2687     }
2688
2689     IVBSAXXMLReader_AddRef( iface );
2690
2691     return S_OK;
2692 }
2693
2694 static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader* iface)
2695 {
2696     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2697     TRACE("%p\n", This );
2698     return InterlockedIncrement( &This->ref );
2699 }
2700
2701 static ULONG WINAPI saxxmlreader_Release(
2702     IVBSAXXMLReader* iface)
2703 {
2704     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2705     LONG ref;
2706
2707     TRACE("%p\n", This );
2708
2709     ref = InterlockedDecrement( &This->ref );
2710     if ( ref == 0 )
2711     {
2712         int i;
2713
2714         for (i = 0; i < SAXHandler_Last; i++)
2715         {
2716             struct saxhandler_iface *iface = &This->saxhandlers[i];
2717
2718             if (iface->handler)
2719                 IUnknown_Release(iface->handler);
2720
2721             if (iface->vbhandler)
2722                 IUnknown_Release(iface->vbhandler);
2723         }
2724
2725         free_bstr_pool(&This->pool);
2726
2727         release_dispex(&This->dispex);
2728         heap_free( This );
2729     }
2730
2731     return ref;
2732 }
2733 /*** IDispatch ***/
2734 static HRESULT WINAPI saxxmlreader_GetTypeInfoCount( IVBSAXXMLReader *iface, UINT* pctinfo )
2735 {
2736     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2737     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2738 }
2739
2740 static HRESULT WINAPI saxxmlreader_GetTypeInfo(
2741     IVBSAXXMLReader *iface,
2742     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2743 {
2744     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2745     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
2746         iTInfo, lcid, ppTInfo);
2747 }
2748
2749 static HRESULT WINAPI saxxmlreader_GetIDsOfNames(
2750     IVBSAXXMLReader *iface,
2751     REFIID riid,
2752     LPOLESTR* rgszNames,
2753     UINT cNames,
2754     LCID lcid,
2755     DISPID* rgDispId)
2756 {
2757     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2758     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
2759         riid, rgszNames, cNames, lcid, rgDispId);
2760 }
2761
2762 static HRESULT WINAPI saxxmlreader_Invoke(
2763     IVBSAXXMLReader *iface,
2764     DISPID dispIdMember,
2765     REFIID riid,
2766     LCID lcid,
2767     WORD wFlags,
2768     DISPPARAMS* pDispParams,
2769     VARIANT* pVarResult,
2770     EXCEPINFO* pExcepInfo,
2771     UINT* puArgErr)
2772 {
2773     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2774     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
2775         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2776 }
2777
2778 /*** IVBSAXXMLReader methods ***/
2779 static HRESULT WINAPI saxxmlreader_getFeature(
2780     IVBSAXXMLReader* iface,
2781     const WCHAR *feature_name,
2782     VARIANT_BOOL *value)
2783 {
2784     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2785     saxreader_feature feature;
2786
2787     TRACE("(%p)->(%s %p)\n", This, debugstr_w(feature_name), value);
2788
2789     feature = get_saxreader_feature(feature_name);
2790     if (feature == Namespaces || feature == NamespacePrefixes)
2791         return get_feature_value(This, feature, value);
2792
2793     FIXME("(%p)->(%s %p) stub\n", This, debugstr_w(feature_name), value);
2794     return E_NOTIMPL;
2795 }
2796
2797 static HRESULT WINAPI saxxmlreader_putFeature(
2798     IVBSAXXMLReader* iface,
2799     const WCHAR *feature_name,
2800     VARIANT_BOOL value)
2801 {
2802     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2803     saxreader_feature feature;
2804
2805     TRACE("(%p)->(%s %x)\n", This, debugstr_w(feature_name), value);
2806
2807     feature = get_saxreader_feature(feature_name);
2808
2809     /* accepted cases */
2810     if ((feature == ExternalGeneralEntities   && value == VARIANT_FALSE) ||
2811         (feature == ExternalParameterEntities && value == VARIANT_FALSE) ||
2812          feature == Namespaces ||
2813          feature == NamespacePrefixes)
2814     {
2815         return set_feature_value(This, feature, value);
2816     }
2817
2818     if (feature == LexicalHandlerParEntities || feature == ProhibitDTD)
2819     {
2820         FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
2821         return set_feature_value(This, feature, value);
2822     }
2823
2824     FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
2825     return E_NOTIMPL;
2826 }
2827
2828 static HRESULT WINAPI saxxmlreader_getProperty(
2829     IVBSAXXMLReader* iface,
2830     const WCHAR *prop,
2831     VARIANT *value)
2832 {
2833     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2834     return internal_getProperty(This, prop, value, TRUE);
2835 }
2836
2837 static HRESULT WINAPI saxxmlreader_putProperty(
2838     IVBSAXXMLReader* iface,
2839     const WCHAR *pProp,
2840     VARIANT value)
2841 {
2842     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2843     return internal_putProperty(This, pProp, value, TRUE);
2844 }
2845
2846 static HRESULT WINAPI saxxmlreader_get_entityResolver(
2847     IVBSAXXMLReader* iface,
2848     IVBSAXEntityResolver **pEntityResolver)
2849 {
2850     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2851     return internal_getEntityResolver(This, pEntityResolver, TRUE);
2852 }
2853
2854 static HRESULT WINAPI saxxmlreader_put_entityResolver(
2855     IVBSAXXMLReader* iface,
2856     IVBSAXEntityResolver *pEntityResolver)
2857 {
2858     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2859     return internal_putEntityResolver(This, pEntityResolver, TRUE);
2860 }
2861
2862 static HRESULT WINAPI saxxmlreader_get_contentHandler(
2863     IVBSAXXMLReader* iface,
2864     IVBSAXContentHandler **handler)
2865 {
2866     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2867     return saxreader_get_handler(This, SAXContentHandler, TRUE, (void**)handler);
2868 }
2869
2870 static HRESULT WINAPI saxxmlreader_put_contentHandler(
2871     IVBSAXXMLReader* iface,
2872     IVBSAXContentHandler *handler)
2873 {
2874     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2875     return saxreader_put_handler(This, SAXContentHandler, handler, TRUE);
2876 }
2877
2878 static HRESULT WINAPI saxxmlreader_get_dtdHandler(
2879     IVBSAXXMLReader* iface,
2880     IVBSAXDTDHandler **handler)
2881 {
2882     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2883     return saxreader_get_handler(This, SAXDTDHandler, TRUE, (void**)handler);
2884 }
2885
2886 static HRESULT WINAPI saxxmlreader_put_dtdHandler(
2887     IVBSAXXMLReader* iface,
2888     IVBSAXDTDHandler *handler)
2889 {
2890     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2891     return saxreader_put_handler(This, SAXDTDHandler, handler, TRUE);
2892 }
2893
2894 static HRESULT WINAPI saxxmlreader_get_errorHandler(
2895     IVBSAXXMLReader* iface,
2896     IVBSAXErrorHandler **handler)
2897 {
2898     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2899     return saxreader_get_handler(This, SAXErrorHandler, TRUE, (void**)handler);
2900 }
2901
2902 static HRESULT WINAPI saxxmlreader_put_errorHandler(
2903     IVBSAXXMLReader* iface,
2904     IVBSAXErrorHandler *handler)
2905 {
2906     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2907     return saxreader_put_handler(This, SAXErrorHandler, handler, TRUE);
2908 }
2909
2910 static HRESULT WINAPI saxxmlreader_get_baseURL(
2911     IVBSAXXMLReader* iface,
2912     const WCHAR **pBaseUrl)
2913 {
2914     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2915
2916     FIXME("(%p)->(%p) stub\n", This, pBaseUrl);
2917     return E_NOTIMPL;
2918 }
2919
2920 static HRESULT WINAPI saxxmlreader_put_baseURL(
2921     IVBSAXXMLReader* iface,
2922     const WCHAR *pBaseUrl)
2923 {
2924     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2925
2926     FIXME("(%p)->(%s) stub\n", This, debugstr_w(pBaseUrl));
2927     return E_NOTIMPL;
2928 }
2929
2930 static HRESULT WINAPI saxxmlreader_get_secureBaseURL(
2931     IVBSAXXMLReader* iface,
2932     const WCHAR **pSecureBaseUrl)
2933 {
2934     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2935
2936     FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
2937     return E_NOTIMPL;
2938 }
2939
2940
2941 static HRESULT WINAPI saxxmlreader_put_secureBaseURL(
2942     IVBSAXXMLReader* iface,
2943     const WCHAR *secureBaseUrl)
2944 {
2945     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2946
2947     FIXME("(%p)->(%s) stub\n", This, debugstr_w(secureBaseUrl));
2948     return E_NOTIMPL;
2949 }
2950
2951 static HRESULT WINAPI saxxmlreader_parse(
2952     IVBSAXXMLReader* iface,
2953     VARIANT varInput)
2954 {
2955     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2956     return internal_parse(This, varInput, TRUE);
2957 }
2958
2959 static HRESULT WINAPI saxxmlreader_parseURL(
2960     IVBSAXXMLReader* iface,
2961     const WCHAR *url)
2962 {
2963     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2964     return internal_parseURL(This, url, TRUE);
2965 }
2966
2967 static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl =
2968 {
2969     saxxmlreader_QueryInterface,
2970     saxxmlreader_AddRef,
2971     saxxmlreader_Release,
2972     saxxmlreader_GetTypeInfoCount,
2973     saxxmlreader_GetTypeInfo,
2974     saxxmlreader_GetIDsOfNames,
2975     saxxmlreader_Invoke,
2976     saxxmlreader_getFeature,
2977     saxxmlreader_putFeature,
2978     saxxmlreader_getProperty,
2979     saxxmlreader_putProperty,
2980     saxxmlreader_get_entityResolver,
2981     saxxmlreader_put_entityResolver,
2982     saxxmlreader_get_contentHandler,
2983     saxxmlreader_put_contentHandler,
2984     saxxmlreader_get_dtdHandler,
2985     saxxmlreader_put_dtdHandler,
2986     saxxmlreader_get_errorHandler,
2987     saxxmlreader_put_errorHandler,
2988     saxxmlreader_get_baseURL,
2989     saxxmlreader_put_baseURL,
2990     saxxmlreader_get_secureBaseURL,
2991     saxxmlreader_put_secureBaseURL,
2992     saxxmlreader_parse,
2993     saxxmlreader_parseURL
2994 };
2995
2996 /*** ISAXXMLReader interface ***/
2997 /*** IUnknown methods ***/
2998 static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader* iface, REFIID riid, void **ppvObject)
2999 {
3000     saxreader *This = impl_from_ISAXXMLReader( iface );
3001     return saxxmlreader_QueryInterface(&This->IVBSAXXMLReader_iface, riid, ppvObject);
3002 }
3003
3004 static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader* iface)
3005 {
3006     saxreader *This = impl_from_ISAXXMLReader( iface );
3007     return saxxmlreader_AddRef(&This->IVBSAXXMLReader_iface);
3008 }
3009
3010 static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader* iface)
3011 {
3012     saxreader *This = impl_from_ISAXXMLReader( iface );
3013     return saxxmlreader_Release(&This->IVBSAXXMLReader_iface);
3014 }
3015
3016 /*** ISAXXMLReader methods ***/
3017 static HRESULT WINAPI isaxxmlreader_getFeature(
3018         ISAXXMLReader* iface,
3019         const WCHAR *pFeature,
3020         VARIANT_BOOL *pValue)
3021 {
3022     saxreader *This = impl_from_ISAXXMLReader( iface );
3023     return IVBSAXXMLReader_getFeature(&This->IVBSAXXMLReader_iface, pFeature, pValue);
3024 }
3025
3026 static HRESULT WINAPI isaxxmlreader_putFeature(
3027         ISAXXMLReader* iface,
3028         const WCHAR *pFeature,
3029         VARIANT_BOOL vfValue)
3030 {
3031     saxreader *This = impl_from_ISAXXMLReader( iface );
3032     return IVBSAXXMLReader_putFeature(&This->IVBSAXXMLReader_iface, pFeature, vfValue);
3033 }
3034
3035 static HRESULT WINAPI isaxxmlreader_getProperty(
3036         ISAXXMLReader* iface,
3037         const WCHAR *prop,
3038         VARIANT *value)
3039 {
3040     saxreader *This = impl_from_ISAXXMLReader( iface );
3041     return internal_getProperty(This, prop, value, FALSE);
3042 }
3043
3044 static HRESULT WINAPI isaxxmlreader_putProperty(
3045         ISAXXMLReader* iface,
3046         const WCHAR *pProp,
3047         VARIANT value)
3048 {
3049     saxreader *This = impl_from_ISAXXMLReader( iface );
3050     return internal_putProperty(This, pProp, value, FALSE);
3051 }
3052
3053 static HRESULT WINAPI isaxxmlreader_getEntityResolver(
3054         ISAXXMLReader* iface,
3055         ISAXEntityResolver **ppEntityResolver)
3056 {
3057     saxreader *This = impl_from_ISAXXMLReader( iface );
3058     return internal_getEntityResolver(This, ppEntityResolver, FALSE);
3059 }
3060
3061 static HRESULT WINAPI isaxxmlreader_putEntityResolver(
3062         ISAXXMLReader* iface,
3063         ISAXEntityResolver *pEntityResolver)
3064 {
3065     saxreader *This = impl_from_ISAXXMLReader( iface );
3066     return internal_putEntityResolver(This, pEntityResolver, FALSE);
3067 }
3068
3069 static HRESULT WINAPI isaxxmlreader_getContentHandler(
3070         ISAXXMLReader* iface,
3071         ISAXContentHandler **handler)
3072 {
3073     saxreader *This = impl_from_ISAXXMLReader( iface );
3074     return saxreader_get_handler(This, SAXContentHandler, FALSE, (void**)handler);
3075 }
3076
3077 static HRESULT WINAPI isaxxmlreader_putContentHandler(
3078     ISAXXMLReader* iface,
3079     ISAXContentHandler *handler)
3080 {
3081     saxreader *This = impl_from_ISAXXMLReader( iface );
3082     return saxreader_put_handler(This, SAXContentHandler, handler, FALSE);
3083 }
3084
3085 static HRESULT WINAPI isaxxmlreader_getDTDHandler(
3086         ISAXXMLReader* iface,
3087         ISAXDTDHandler **handler)
3088 {
3089     saxreader *This = impl_from_ISAXXMLReader( iface );
3090     return saxreader_get_handler(This, SAXDTDHandler, FALSE, (void**)handler);
3091 }
3092
3093 static HRESULT WINAPI isaxxmlreader_putDTDHandler(
3094         ISAXXMLReader* iface,
3095         ISAXDTDHandler *handler)
3096 {
3097     saxreader *This = impl_from_ISAXXMLReader( iface );
3098     return saxreader_put_handler(This, SAXDTDHandler, handler, FALSE);
3099 }
3100
3101 static HRESULT WINAPI isaxxmlreader_getErrorHandler(
3102         ISAXXMLReader* iface,
3103         ISAXErrorHandler **handler)
3104 {
3105     saxreader *This = impl_from_ISAXXMLReader( iface );
3106     return saxreader_get_handler(This, SAXErrorHandler, FALSE, (void**)handler);
3107 }
3108
3109 static HRESULT WINAPI isaxxmlreader_putErrorHandler(ISAXXMLReader* iface, ISAXErrorHandler *handler)
3110 {
3111     saxreader *This = impl_from_ISAXXMLReader( iface );
3112     return saxreader_put_handler(This, SAXErrorHandler, handler, FALSE);
3113 }
3114
3115 static HRESULT WINAPI isaxxmlreader_getBaseURL(
3116         ISAXXMLReader* iface,
3117         const WCHAR **pBaseUrl)
3118 {
3119     saxreader *This = impl_from_ISAXXMLReader( iface );
3120     return IVBSAXXMLReader_get_baseURL(&This->IVBSAXXMLReader_iface, pBaseUrl);
3121 }
3122
3123 static HRESULT WINAPI isaxxmlreader_putBaseURL(
3124         ISAXXMLReader* iface,
3125         const WCHAR *pBaseUrl)
3126 {
3127     saxreader *This = impl_from_ISAXXMLReader( iface );
3128     return IVBSAXXMLReader_put_baseURL(&This->IVBSAXXMLReader_iface, pBaseUrl);
3129 }
3130
3131 static HRESULT WINAPI isaxxmlreader_getSecureBaseURL(
3132         ISAXXMLReader* iface,
3133         const WCHAR **pSecureBaseUrl)
3134 {
3135     saxreader *This = impl_from_ISAXXMLReader( iface );
3136     return IVBSAXXMLReader_get_secureBaseURL(&This->IVBSAXXMLReader_iface, pSecureBaseUrl);
3137 }
3138
3139 static HRESULT WINAPI isaxxmlreader_putSecureBaseURL(
3140         ISAXXMLReader* iface,
3141         const WCHAR *secureBaseUrl)
3142 {
3143     saxreader *This = impl_from_ISAXXMLReader( iface );
3144     return IVBSAXXMLReader_put_secureBaseURL(&This->IVBSAXXMLReader_iface, secureBaseUrl);
3145 }
3146
3147 static HRESULT WINAPI isaxxmlreader_parse(
3148         ISAXXMLReader* iface,
3149         VARIANT varInput)
3150 {
3151     saxreader *This = impl_from_ISAXXMLReader( iface );
3152     return internal_parse(This, varInput, FALSE);
3153 }
3154
3155 static HRESULT WINAPI isaxxmlreader_parseURL(
3156         ISAXXMLReader* iface,
3157         const WCHAR *url)
3158 {
3159     saxreader *This = impl_from_ISAXXMLReader( iface );
3160     return internal_parseURL(This, url, FALSE);
3161 }
3162
3163 static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl =
3164 {
3165     isaxxmlreader_QueryInterface,
3166     isaxxmlreader_AddRef,
3167     isaxxmlreader_Release,
3168     isaxxmlreader_getFeature,
3169     isaxxmlreader_putFeature,
3170     isaxxmlreader_getProperty,
3171     isaxxmlreader_putProperty,
3172     isaxxmlreader_getEntityResolver,
3173     isaxxmlreader_putEntityResolver,
3174     isaxxmlreader_getContentHandler,
3175     isaxxmlreader_putContentHandler,
3176     isaxxmlreader_getDTDHandler,
3177     isaxxmlreader_putDTDHandler,
3178     isaxxmlreader_getErrorHandler,
3179     isaxxmlreader_putErrorHandler,
3180     isaxxmlreader_getBaseURL,
3181     isaxxmlreader_putBaseURL,
3182     isaxxmlreader_getSecureBaseURL,
3183     isaxxmlreader_putSecureBaseURL,
3184     isaxxmlreader_parse,
3185     isaxxmlreader_parseURL
3186 };
3187
3188 static const tid_t saxreader_iface_tids[] = {
3189     IVBSAXXMLReader_tid,
3190     0
3191 };
3192 static dispex_static_data_t saxreader_dispex = {
3193     NULL,
3194     IVBSAXXMLReader_tid,
3195     NULL,
3196     saxreader_iface_tids
3197 };
3198
3199 HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *outer, LPVOID *ppObj)
3200 {
3201     saxreader *reader;
3202
3203     TRACE("(%p, %p)\n", outer, ppObj);
3204
3205     reader = heap_alloc( sizeof (*reader) );
3206     if( !reader )
3207         return E_OUTOFMEMORY;
3208
3209     reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl;
3210     reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl;
3211     reader->ref = 1;
3212     memset(reader->saxhandlers, 0, sizeof(reader->saxhandlers));
3213     reader->isParsing = FALSE;
3214     reader->pool.pool = NULL;
3215     reader->pool.index = 0;
3216     reader->pool.len = 0;
3217     reader->features = Namespaces | NamespacePrefixes;
3218     reader->version = version;
3219
3220     init_dispex(&reader->dispex, (IUnknown*)&reader->IVBSAXXMLReader_iface, &saxreader_dispex);
3221
3222     memset(&reader->sax, 0, sizeof(xmlSAXHandler));
3223     reader->sax.initialized = XML_SAX2_MAGIC;
3224     reader->sax.startDocument = libxmlStartDocument;
3225     reader->sax.endDocument = libxmlEndDocument;
3226     reader->sax.startElementNs = libxmlStartElementNS;
3227     reader->sax.endElementNs = libxmlEndElementNS;
3228     reader->sax.characters = libxmlCharacters;
3229     reader->sax.setDocumentLocator = libxmlSetDocumentLocator;
3230     reader->sax.comment = libxmlComment;
3231     reader->sax.error = libxmlFatalError;
3232     reader->sax.fatalError = libxmlFatalError;
3233     reader->sax.cdataBlock = libxmlCDataBlock;
3234
3235     *ppObj = &reader->IVBSAXXMLReader_iface;
3236
3237     TRACE("returning iface %p\n", *ppObj);
3238
3239     return S_OK;
3240 }
3241
3242 #else
3243
3244 HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *pUnkOuter, LPVOID *ppObj)
3245 {
3246     MESSAGE("This program tried to use a SAX XML Reader object, but\n"
3247             "libxml2 support was not present at compile time.\n");
3248     return E_NOTIMPL;
3249 }
3250
3251 #endif