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