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