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