xref: /reactos/dll/win32/msxml3/saxreader.c (revision 64daf542)
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     len = SysStringLen(bstr);
1954     ptr = bstr + len - 1;
1955     while ((*ptr == '\r' || *ptr == '\n') && ptr >= bstr)
1956         ptr--;
1957 
1958     while (*++ptr)
1959     {
1960         /* replace returns as:
1961 
1962            - "\r<char>" -> "\n<char>"
1963            - "\r\r" -> "\r"
1964            - "\r\n" -> "\n"
1965         */
1966         if (*ptr == '\r')
1967         {
1968             if (*(ptr+1) == '\r' || *(ptr+1) == '\n')
1969             {
1970                 /* shift tail */
1971                 memmove(ptr, ptr+1, len-- - (ptr-bstr));
1972             }
1973             else
1974                 *ptr = '\n';
1975         }
1976     }
1977 
1978     ret = SysAllocStringLen(bstr, len);
1979     SysFreeString(bstr);
1980     return ret;
1981 }
1982 
1983 static void libxml_cdatablock(void *ctx, const xmlChar *value, int len)
1984 {
1985     const xmlChar *start, *end;
1986     saxlocator *locator = ctx;
1987     struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader);
1988     HRESULT hr = S_OK;
1989     BSTR chars;
1990     int i;
1991 
1992     update_position(locator, FALSE);
1993     if (saxreader_has_handler(locator, SAXLexicalHandler))
1994     {
1995        if (locator->vbInterface)
1996            hr = IVBSAXLexicalHandler_startCDATA(lexical->vbhandler);
1997        else
1998            hr = ISAXLexicalHandler_startCDATA(lexical->handler);
1999     }
2000 
2001     if(FAILED(hr))
2002     {
2003         format_error_message_from_id(locator, hr);
2004         return;
2005     }
2006 
2007     start = value;
2008     end = NULL;
2009     i = 0;
2010 
2011     while (i < len)
2012     {
2013         /* scan for newlines */
2014         if (value[i] == '\r' || value[i] == '\n')
2015         {
2016             /* skip newlines/linefeeds */
2017             while (i < len)
2018             {
2019                 if (value[i] != '\r' && value[i] != '\n') break;
2020                 i++;
2021             }
2022             end = &value[i];
2023 
2024             /* report */
2025             chars = saxreader_get_cdata_chunk(start, end-start);
2026             TRACE("(chunk %s)\n", debugstr_w(chars));
2027             hr = saxreader_saxcharacters(locator, chars);
2028             SysFreeString(chars);
2029 
2030             start = &value[i];
2031             end = NULL;
2032         }
2033         i++;
2034         locator->column++;
2035     }
2036 
2037     /* no newline chars (or last chunk) report as a whole */
2038     if (!end && start == value)
2039     {
2040         /* report */
2041         chars = bstr_from_xmlCharN(start, len-(start-value));
2042         TRACE("(%s)\n", debugstr_w(chars));
2043         hr = saxreader_saxcharacters(locator, chars);
2044         SysFreeString(chars);
2045     }
2046 
2047     if (saxreader_has_handler(locator, SAXLexicalHandler))
2048     {
2049         if (locator->vbInterface)
2050             hr = IVBSAXLexicalHandler_endCDATA(lexical->vbhandler);
2051         else
2052             hr = ISAXLexicalHandler_endCDATA(lexical->handler);
2053     }
2054 
2055     if(FAILED(hr))
2056         format_error_message_from_id(locator, hr);
2057 }
2058 
2059 static xmlParserInputPtr libxmlresolveentity(void *ctx, const xmlChar *publicid, const xmlChar *systemid)
2060 {
2061     FIXME("entity resolving not implemented, %s, %s\n", publicid, systemid);
2062     return xmlSAX2ResolveEntity(ctx, publicid, systemid);
2063 }
2064 
2065 /*** IVBSAXLocator interface ***/
2066 /*** IUnknown methods ***/
2067 static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator* iface, REFIID riid, void **ppvObject)
2068 {
2069     saxlocator *This = impl_from_IVBSAXLocator( iface );
2070 
2071     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject);
2072 
2073     *ppvObject = NULL;
2074 
2075     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2076             IsEqualGUID( riid, &IID_IDispatch) ||
2077             IsEqualGUID( riid, &IID_IVBSAXLocator ))
2078     {
2079         *ppvObject = iface;
2080     }
2081     else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
2082     {
2083         *ppvObject = &This->IVBSAXAttributes_iface;
2084     }
2085     else
2086     {
2087         FIXME("interface %s not implemented\n", debugstr_guid(riid));
2088         return E_NOINTERFACE;
2089     }
2090 
2091     IVBSAXLocator_AddRef( iface );
2092 
2093     return S_OK;
2094 }
2095 
2096 static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator* iface)
2097 {
2098     saxlocator *This = impl_from_IVBSAXLocator( iface );
2099     TRACE("%p\n", This );
2100     return ISAXLocator_AddRef(&This->ISAXLocator_iface);
2101 }
2102 
2103 static ULONG WINAPI ivbsaxlocator_Release(IVBSAXLocator* iface)
2104 {
2105     saxlocator *This = impl_from_IVBSAXLocator( iface );
2106     return ISAXLocator_Release(&This->ISAXLocator_iface);
2107 }
2108 
2109 /*** IDispatch methods ***/
2110 static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount( IVBSAXLocator *iface, UINT* pctinfo )
2111 {
2112     saxlocator *This = impl_from_IVBSAXLocator( iface );
2113 
2114     TRACE("(%p)->(%p)\n", This, pctinfo);
2115 
2116     *pctinfo = 1;
2117 
2118     return S_OK;
2119 }
2120 
2121 static HRESULT WINAPI ivbsaxlocator_GetTypeInfo(
2122     IVBSAXLocator *iface,
2123     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2124 {
2125     saxlocator *This = impl_from_IVBSAXLocator( iface );
2126 
2127     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2128 
2129     return get_typeinfo(IVBSAXLocator_tid, ppTInfo);
2130 }
2131 
2132 static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames(
2133     IVBSAXLocator *iface,
2134     REFIID riid,
2135     LPOLESTR* rgszNames,
2136     UINT cNames,
2137     LCID lcid,
2138     DISPID* rgDispId)
2139 {
2140     saxlocator *This = impl_from_IVBSAXLocator( iface );
2141     ITypeInfo *typeinfo;
2142     HRESULT hr;
2143 
2144     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
2145           lcid, rgDispId);
2146 
2147     if(!rgszNames || cNames == 0 || !rgDispId)
2148         return E_INVALIDARG;
2149 
2150     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
2151     if(SUCCEEDED(hr))
2152     {
2153         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2154         ITypeInfo_Release(typeinfo);
2155     }
2156 
2157     return hr;
2158 }
2159 
2160 static HRESULT WINAPI ivbsaxlocator_Invoke(
2161     IVBSAXLocator *iface,
2162     DISPID dispIdMember,
2163     REFIID riid,
2164     LCID lcid,
2165     WORD wFlags,
2166     DISPPARAMS* pDispParams,
2167     VARIANT* pVarResult,
2168     EXCEPINFO* pExcepInfo,
2169     UINT* puArgErr)
2170 {
2171     saxlocator *This = impl_from_IVBSAXLocator( iface );
2172     ITypeInfo *typeinfo;
2173     HRESULT hr;
2174 
2175     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2176           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2177 
2178     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
2179     if(SUCCEEDED(hr))
2180     {
2181         hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXLocator_iface, dispIdMember, wFlags,
2182                 pDispParams, pVarResult, pExcepInfo, puArgErr);
2183         ITypeInfo_Release(typeinfo);
2184     }
2185 
2186     return hr;
2187 }
2188 
2189 /*** IVBSAXLocator methods ***/
2190 static HRESULT WINAPI ivbsaxlocator_get_columnNumber(
2191         IVBSAXLocator* iface,
2192         int *pnColumn)
2193 {
2194     saxlocator *This = impl_from_IVBSAXLocator( iface );
2195     return ISAXLocator_getColumnNumber(&This->ISAXLocator_iface, pnColumn);
2196 }
2197 
2198 static HRESULT WINAPI ivbsaxlocator_get_lineNumber(
2199         IVBSAXLocator* iface,
2200         int *pnLine)
2201 {
2202     saxlocator *This = impl_from_IVBSAXLocator( iface );
2203     return ISAXLocator_getLineNumber(&This->ISAXLocator_iface, pnLine);
2204 }
2205 
2206 static HRESULT WINAPI ivbsaxlocator_get_publicId(IVBSAXLocator* iface, BSTR *ret)
2207 {
2208     saxlocator *This = impl_from_IVBSAXLocator( iface );
2209     const WCHAR *publicidW;
2210     HRESULT hr;
2211 
2212     TRACE("(%p)->(%p)\n", This, ret);
2213 
2214     if (!ret)
2215         return E_POINTER;
2216 
2217     *ret = NULL;
2218     hr = ISAXLocator_getPublicId(&This->ISAXLocator_iface, &publicidW);
2219     if (FAILED(hr))
2220         return hr;
2221 
2222     return return_bstr(publicidW, ret);
2223 }
2224 
2225 static HRESULT WINAPI ivbsaxlocator_get_systemId(IVBSAXLocator* iface, BSTR *ret)
2226 {
2227     saxlocator *This = impl_from_IVBSAXLocator( iface );
2228     const WCHAR *systemidW;
2229     HRESULT hr;
2230 
2231     TRACE("(%p)->(%p)\n", This, ret);
2232 
2233     if (!ret)
2234         return E_POINTER;
2235 
2236     *ret = NULL;
2237     hr = ISAXLocator_getSystemId(&This->ISAXLocator_iface, &systemidW);
2238     if (FAILED(hr))
2239         return hr;
2240 
2241     return return_bstr(systemidW, ret);
2242 }
2243 
2244 static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl =
2245 {
2246     ivbsaxlocator_QueryInterface,
2247     ivbsaxlocator_AddRef,
2248     ivbsaxlocator_Release,
2249     ivbsaxlocator_GetTypeInfoCount,
2250     ivbsaxlocator_GetTypeInfo,
2251     ivbsaxlocator_GetIDsOfNames,
2252     ivbsaxlocator_Invoke,
2253     ivbsaxlocator_get_columnNumber,
2254     ivbsaxlocator_get_lineNumber,
2255     ivbsaxlocator_get_publicId,
2256     ivbsaxlocator_get_systemId
2257 };
2258 
2259 /*** ISAXLocator interface ***/
2260 /*** IUnknown methods ***/
2261 static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid, void **ppvObject)
2262 {
2263     saxlocator *This = impl_from_ISAXLocator( iface );
2264 
2265     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2266 
2267     *ppvObject = NULL;
2268 
2269     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2270             IsEqualGUID( riid, &IID_ISAXLocator ))
2271     {
2272         *ppvObject = iface;
2273     }
2274     else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
2275     {
2276         *ppvObject = &This->ISAXAttributes_iface;
2277     }
2278     else
2279     {
2280         WARN("interface %s not implemented\n", debugstr_guid(riid));
2281         return E_NOINTERFACE;
2282     }
2283 
2284     ISAXLocator_AddRef( iface );
2285 
2286     return S_OK;
2287 }
2288 
2289 static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface)
2290 {
2291     saxlocator *This = impl_from_ISAXLocator( iface );
2292     ULONG ref = InterlockedIncrement( &This->ref );
2293     TRACE("(%p)->(%d)\n", This, ref);
2294     return ref;
2295 }
2296 
2297 static ULONG WINAPI isaxlocator_Release(
2298         ISAXLocator* iface)
2299 {
2300     saxlocator *This = impl_from_ISAXLocator( iface );
2301     LONG ref = InterlockedDecrement( &This->ref );
2302 
2303     TRACE("(%p)->(%d)\n", This, ref );
2304 
2305     if (ref == 0)
2306     {
2307         element_entry *element, *element2;
2308         int index;
2309 
2310         SysFreeString(This->publicId);
2311         SysFreeString(This->systemId);
2312         SysFreeString(This->namespaceUri);
2313 
2314         for(index = 0; index < This->attr_alloc_count; index++)
2315         {
2316             SysFreeString(This->attributes[index].szLocalname);
2317             SysFreeString(This->attributes[index].szValue);
2318             SysFreeString(This->attributes[index].szQName);
2319         }
2320         heap_free(This->attributes);
2321 
2322         /* element stack */
2323         LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry)
2324         {
2325             list_remove(&element->entry);
2326             free_element_entry(element);
2327         }
2328 
2329         ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface);
2330         heap_free( This );
2331     }
2332 
2333     return ref;
2334 }
2335 
2336 /*** ISAXLocator methods ***/
2337 static HRESULT WINAPI isaxlocator_getColumnNumber(
2338         ISAXLocator* iface,
2339         int *pnColumn)
2340 {
2341     saxlocator *This = impl_from_ISAXLocator( iface );
2342 
2343     *pnColumn = This->column;
2344     return S_OK;
2345 }
2346 
2347 static HRESULT WINAPI isaxlocator_getLineNumber(
2348         ISAXLocator* iface,
2349         int *pnLine)
2350 {
2351     saxlocator *This = impl_from_ISAXLocator( iface );
2352 
2353     *pnLine = This->line;
2354     return S_OK;
2355 }
2356 
2357 static HRESULT WINAPI isaxlocator_getPublicId(
2358         ISAXLocator* iface,
2359         const WCHAR ** ppwchPublicId)
2360 {
2361     BSTR publicId;
2362     saxlocator *This = impl_from_ISAXLocator( iface );
2363 
2364     SysFreeString(This->publicId);
2365 
2366     publicId = bstr_from_xmlChar(xmlSAX2GetPublicId(This->pParserCtxt));
2367     if(SysStringLen(publicId))
2368         This->publicId = publicId;
2369     else
2370     {
2371         SysFreeString(publicId);
2372         This->publicId = NULL;
2373     }
2374 
2375     *ppwchPublicId = This->publicId;
2376     return S_OK;
2377 }
2378 
2379 static HRESULT WINAPI isaxlocator_getSystemId(
2380         ISAXLocator* iface,
2381         const WCHAR ** ppwchSystemId)
2382 {
2383     BSTR systemId;
2384     saxlocator *This = impl_from_ISAXLocator( iface );
2385 
2386     SysFreeString(This->systemId);
2387 
2388     systemId = bstr_from_xmlChar(xmlSAX2GetSystemId(This->pParserCtxt));
2389     if(SysStringLen(systemId))
2390         This->systemId = systemId;
2391     else
2392     {
2393         SysFreeString(systemId);
2394         This->systemId = NULL;
2395     }
2396 
2397     *ppwchSystemId = This->systemId;
2398     return S_OK;
2399 }
2400 
2401 static const struct ISAXLocatorVtbl SAXLocatorVtbl =
2402 {
2403     isaxlocator_QueryInterface,
2404     isaxlocator_AddRef,
2405     isaxlocator_Release,
2406     isaxlocator_getColumnNumber,
2407     isaxlocator_getLineNumber,
2408     isaxlocator_getPublicId,
2409     isaxlocator_getSystemId
2410 };
2411 
2412 static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, BOOL vbInterface)
2413 {
2414     static const WCHAR w3xmlns[] = { 'h','t','t','p',':','/','/', 'w','w','w','.','w','3','.',
2415         'o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0 };
2416 
2417     saxlocator *locator;
2418 
2419     locator = heap_alloc( sizeof (*locator) );
2420     if( !locator )
2421         return E_OUTOFMEMORY;
2422 
2423     locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl;
2424     locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl;
2425     locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl;
2426     locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl;
2427     locator->ref = 1;
2428     locator->vbInterface = vbInterface;
2429 
2430     locator->saxreader = reader;
2431     ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface);
2432 
2433     locator->pParserCtxt = NULL;
2434     locator->publicId = NULL;
2435     locator->systemId = NULL;
2436     locator->line = reader->version < MSXML4 ? 0 : 1;
2437     locator->column = 0;
2438     locator->ret = S_OK;
2439     if (locator->saxreader->version >= MSXML6)
2440         locator->namespaceUri = SysAllocString(w3xmlns);
2441     else
2442         locator->namespaceUri = SysAllocStringLen(NULL, 0);
2443     if(!locator->namespaceUri)
2444     {
2445         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2446         heap_free(locator);
2447         return E_OUTOFMEMORY;
2448     }
2449 
2450     locator->attr_alloc_count = 8;
2451     locator->attr_count = 0;
2452     locator->attributes = heap_alloc_zero(sizeof(struct _attributes)*locator->attr_alloc_count);
2453     if(!locator->attributes)
2454     {
2455         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2456         SysFreeString(locator->namespaceUri);
2457         heap_free(locator);
2458         return E_OUTOFMEMORY;
2459     }
2460 
2461     list_init(&locator->elements);
2462 
2463     *ppsaxlocator = locator;
2464 
2465     TRACE("returning %p\n", *ppsaxlocator);
2466 
2467     return S_OK;
2468 }
2469 
2470 /*** SAXXMLReader internal functions ***/
2471 static HRESULT internal_parseBuffer(saxreader *This, const char *buffer, int size, BOOL vbInterface)
2472 {
2473     xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
2474     xmlChar *enc_name = NULL;
2475     saxlocator *locator;
2476     HRESULT hr;
2477 
2478     TRACE("(%p)->(%p %d)\n", This, buffer, size);
2479 
2480     hr = SAXLocator_create(This, &locator, vbInterface);
2481     if (FAILED(hr))
2482         return hr;
2483 
2484     if (size >= 4)
2485     {
2486         const unsigned char *buff = (unsigned char*)buffer;
2487 
2488         encoding = xmlDetectCharEncoding((xmlChar*)buffer, 4);
2489         enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
2490         TRACE("detected encoding: %s\n", enc_name);
2491         /* skip BOM, parser won't switch encodings and so won't skip it on its own */
2492         if ((encoding == XML_CHAR_ENCODING_UTF8) &&
2493             buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF)
2494         {
2495             buffer += 3;
2496             size -= 3;
2497         }
2498     }
2499 
2500     /* if libxml2 detection failed try to guess */
2501     if (encoding == XML_CHAR_ENCODING_NONE)
2502     {
2503         const WCHAR *ptr = (WCHAR*)buffer;
2504         /* an xml declaration with optional encoding will still be handled by the parser */
2505         if ((size >= 2) && *ptr == '<' && ptr[1] != '?')
2506         {
2507             enc_name = (xmlChar*)xmlGetCharEncodingName(XML_CHAR_ENCODING_UTF16LE);
2508             encoding = XML_CHAR_ENCODING_UTF16LE;
2509         }
2510     }
2511     else if (encoding == XML_CHAR_ENCODING_UTF8)
2512         enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
2513     else
2514         enc_name = NULL;
2515 
2516     locator->pParserCtxt = xmlCreateMemoryParserCtxt(buffer, size);
2517     if (!locator->pParserCtxt)
2518     {
2519         ISAXLocator_Release(&locator->ISAXLocator_iface);
2520         return E_FAIL;
2521     }
2522 
2523     if (enc_name)
2524     {
2525         locator->pParserCtxt->encoding = xmlStrdup(enc_name);
2526         if (encoding == XML_CHAR_ENCODING_UTF16LE) {
2527             TRACE("switching to %s\n", enc_name);
2528             xmlSwitchEncoding(locator->pParserCtxt, encoding);
2529         }
2530     }
2531 
2532     xmlFree(locator->pParserCtxt->sax);
2533     locator->pParserCtxt->sax = &locator->saxreader->sax;
2534     locator->pParserCtxt->userData = locator;
2535 
2536     This->isParsing = TRUE;
2537     if(xmlParseDocument(locator->pParserCtxt) == -1 && locator->ret == S_OK)
2538         hr = E_FAIL;
2539     else
2540         hr = locator->ret;
2541     This->isParsing = FALSE;
2542 
2543     if(locator->pParserCtxt)
2544     {
2545         locator->pParserCtxt->sax = NULL;
2546         xmlFreeParserCtxt(locator->pParserCtxt);
2547         locator->pParserCtxt = NULL;
2548     }
2549 
2550     ISAXLocator_Release(&locator->ISAXLocator_iface);
2551     return hr;
2552 }
2553 
2554 static HRESULT internal_parseStream(saxreader *This, ISequentialStream *stream, BOOL vbInterface)
2555 {
2556     saxlocator *locator;
2557     HRESULT hr;
2558     ULONG dataRead;
2559     char data[2048];
2560     int ret;
2561 
2562     dataRead = 0;
2563     hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead);
2564     if(FAILED(hr)) return hr;
2565 
2566     hr = SAXLocator_create(This, &locator, vbInterface);
2567     if(FAILED(hr)) return hr;
2568 
2569     locator->pParserCtxt = xmlCreatePushParserCtxt(
2570             &locator->saxreader->sax, locator,
2571             data, dataRead, NULL);
2572     if(!locator->pParserCtxt)
2573     {
2574         ISAXLocator_Release(&locator->ISAXLocator_iface);
2575         return E_FAIL;
2576     }
2577 
2578     This->isParsing = TRUE;
2579 
2580     do {
2581         dataRead = 0;
2582         hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead);
2583         if (FAILED(hr) || !dataRead) break;
2584 
2585         ret = xmlParseChunk(locator->pParserCtxt, data, dataRead, 0);
2586         hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2587     }while(hr == S_OK);
2588 
2589     if(SUCCEEDED(hr))
2590     {
2591         ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2592         hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2593     }
2594 
2595 
2596     This->isParsing = FALSE;
2597 
2598     xmlFreeParserCtxt(locator->pParserCtxt);
2599     locator->pParserCtxt = NULL;
2600     ISAXLocator_Release(&locator->ISAXLocator_iface);
2601     return hr;
2602 }
2603 
2604 static HRESULT internal_parse(
2605         saxreader* This,
2606         VARIANT varInput,
2607         BOOL vbInterface)
2608 {
2609     HRESULT hr;
2610 
2611     TRACE("(%p)->(%s)\n", This, debugstr_variant(&varInput));
2612 
2613     /* Dispose of the BSTRs in the pool from a prior run, if any. */
2614     free_bstr_pool(&This->pool);
2615 
2616     switch(V_VT(&varInput))
2617     {
2618         case VT_BSTR:
2619         case VT_BSTR|VT_BYREF:
2620         {
2621             BSTR str = V_ISBYREF(&varInput) ? *V_BSTRREF(&varInput) : V_BSTR(&varInput);
2622             hr = internal_parseBuffer(This, (const char*)str, strlenW(str)*sizeof(WCHAR), vbInterface);
2623             break;
2624         }
2625         case VT_ARRAY|VT_UI1: {
2626             void *pSAData;
2627             LONG lBound, uBound;
2628             ULONG dataRead;
2629 
2630             hr = SafeArrayGetLBound(V_ARRAY(&varInput), 1, &lBound);
2631             if(hr != S_OK) break;
2632             hr = SafeArrayGetUBound(V_ARRAY(&varInput), 1, &uBound);
2633             if(hr != S_OK) break;
2634             dataRead = (uBound-lBound)*SafeArrayGetElemsize(V_ARRAY(&varInput));
2635             hr = SafeArrayAccessData(V_ARRAY(&varInput), &pSAData);
2636             if(hr != S_OK) break;
2637             hr = internal_parseBuffer(This, pSAData, dataRead, vbInterface);
2638             SafeArrayUnaccessData(V_ARRAY(&varInput));
2639             break;
2640         }
2641         case VT_UNKNOWN:
2642         case VT_DISPATCH: {
2643             ISequentialStream *stream = NULL;
2644             IXMLDOMDocument *xmlDoc;
2645 
2646             if (!V_UNKNOWN(&varInput))
2647                 return E_INVALIDARG;
2648 
2649             if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2650                         &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK)
2651             {
2652                 BSTR bstrData;
2653 
2654                 IXMLDOMDocument_get_xml(xmlDoc, &bstrData);
2655                 hr = internal_parseBuffer(This, (const char*)bstrData,
2656                         SysStringByteLen(bstrData), vbInterface);
2657                 IXMLDOMDocument_Release(xmlDoc);
2658                 SysFreeString(bstrData);
2659                 break;
2660             }
2661 
2662             /* try base interface first */
2663             IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_ISequentialStream, (void**)&stream);
2664             if (!stream)
2665                 /* this should never happen if IStream is implemented properly, but just in case */
2666                 IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_IStream, (void**)&stream);
2667 
2668             if(stream)
2669             {
2670                 hr = internal_parseStream(This, stream, vbInterface);
2671                 ISequentialStream_Release(stream);
2672             }
2673             else
2674             {
2675                 WARN("IUnknown* input doesn't support any of expected interfaces\n");
2676                 hr = E_INVALIDARG;
2677             }
2678 
2679             break;
2680         }
2681         default:
2682             WARN("vt %d not implemented\n", V_VT(&varInput));
2683             hr = E_INVALIDARG;
2684     }
2685 
2686     return hr;
2687 }
2688 
2689 static HRESULT internal_vbonDataAvailable(void *obj, char *ptr, DWORD len)
2690 {
2691     saxreader *This = obj;
2692 
2693     return internal_parseBuffer(This, ptr, len, TRUE);
2694 }
2695 
2696 static HRESULT internal_onDataAvailable(void *obj, char *ptr, DWORD len)
2697 {
2698     saxreader *This = obj;
2699 
2700     return internal_parseBuffer(This, ptr, len, FALSE);
2701 }
2702 
2703 static HRESULT internal_parseURL(
2704         saxreader* This,
2705         const WCHAR *url,
2706         BOOL vbInterface)
2707 {
2708     IMoniker *mon;
2709     bsc_t *bsc;
2710     HRESULT hr;
2711 
2712     TRACE("(%p)->(%s)\n", This, debugstr_w(url));
2713 
2714     hr = create_moniker_from_url(url, &mon);
2715     if(FAILED(hr))
2716         return hr;
2717 
2718     if(vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, This, &bsc);
2719     else hr = bind_url(mon, internal_onDataAvailable, This, &bsc);
2720     IMoniker_Release(mon);
2721 
2722     if(FAILED(hr))
2723         return hr;
2724 
2725     return detach_bsc(bsc);
2726 }
2727 
2728 static HRESULT saxreader_put_handler_from_variant(saxreader *This, enum saxhandler_type type, const VARIANT *v, BOOL vb)
2729 {
2730     const IID *riid;
2731 
2732     if (V_VT(v) == VT_EMPTY)
2733         return saxreader_put_handler(This, type, NULL, vb);
2734 
2735     switch (type)
2736     {
2737     case SAXDeclHandler:
2738         riid = vb ? &IID_IVBSAXDeclHandler : &IID_ISAXDeclHandler;
2739         break;
2740     case SAXLexicalHandler:
2741         riid = vb ? &IID_IVBSAXLexicalHandler : &IID_ISAXLexicalHandler;
2742         break;
2743     default:
2744         ERR("wrong handler type %d\n", type);
2745         return E_FAIL;
2746     }
2747 
2748     switch (V_VT(v))
2749     {
2750     case VT_DISPATCH:
2751     case VT_UNKNOWN:
2752     {
2753         IUnknown *handler = NULL;
2754 
2755         if (V_UNKNOWN(v))
2756         {
2757             HRESULT hr = IUnknown_QueryInterface(V_UNKNOWN(v), riid, (void**)&handler);
2758             if (FAILED(hr)) return hr;
2759         }
2760 
2761         saxreader_put_handler(This, type, handler, vb);
2762         if (handler) IUnknown_Release(handler);
2763         break;
2764     }
2765     default:
2766         ERR("value type %d not supported\n", V_VT(v));
2767         return E_INVALIDARG;
2768     }
2769 
2770     return S_OK;
2771 }
2772 
2773 static HRESULT internal_putProperty(
2774     saxreader* This,
2775     const WCHAR *prop,
2776     VARIANT value,
2777     BOOL vbInterface)
2778 {
2779     VARIANT *v;
2780 
2781     TRACE("(%p)->(%s %s)\n", This, debugstr_w(prop), debugstr_variant(&value));
2782 
2783     if (This->isParsing) return E_FAIL;
2784 
2785     v = V_VT(&value) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(&value) : &value;
2786     if(!memcmp(prop, PropertyDeclHandlerW, sizeof(PropertyDeclHandlerW)))
2787         return saxreader_put_handler_from_variant(This, SAXDeclHandler, v, vbInterface);
2788 
2789     if(!memcmp(prop, PropertyLexicalHandlerW, sizeof(PropertyLexicalHandlerW)))
2790         return saxreader_put_handler_from_variant(This, SAXLexicalHandler, v, vbInterface);
2791 
2792     if(!memcmp(prop, PropertyMaxXMLSizeW, sizeof(PropertyMaxXMLSizeW)))
2793     {
2794         if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK;
2795         FIXME("(%p)->(%s): max-xml-size unsupported\n", This, debugstr_variant(v));
2796         return E_NOTIMPL;
2797     }
2798 
2799     if(!memcmp(prop, PropertyMaxElementDepthW, sizeof(PropertyMaxElementDepthW)))
2800     {
2801         if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK;
2802         FIXME("(%p)->(%s): max-element-depth unsupported\n", This, debugstr_variant(v));
2803         return E_NOTIMPL;
2804     }
2805 
2806     FIXME("(%p)->(%s:%s): unsupported property\n", This, debugstr_w(prop), debugstr_variant(v));
2807 
2808     if(!memcmp(prop, PropertyCharsetW, sizeof(PropertyCharsetW)))
2809         return E_NOTIMPL;
2810 
2811     if(!memcmp(prop, PropertyDomNodeW, sizeof(PropertyDomNodeW)))
2812         return E_FAIL;
2813 
2814     if(!memcmp(prop, PropertyInputSourceW, sizeof(PropertyInputSourceW)))
2815         return E_NOTIMPL;
2816 
2817     if(!memcmp(prop, PropertySchemaDeclHandlerW, sizeof(PropertySchemaDeclHandlerW)))
2818         return E_NOTIMPL;
2819 
2820     if(!memcmp(prop, PropertyXMLDeclEncodingW, sizeof(PropertyXMLDeclEncodingW)))
2821         return E_FAIL;
2822 
2823     if(!memcmp(prop, PropertyXMLDeclStandaloneW, sizeof(PropertyXMLDeclStandaloneW)))
2824         return E_FAIL;
2825 
2826     if(!memcmp(prop, PropertyXMLDeclVersionW, sizeof(PropertyXMLDeclVersionW)))
2827         return E_FAIL;
2828 
2829     return E_INVALIDARG;
2830 }
2831 
2832 static HRESULT internal_getProperty(const saxreader* This, const WCHAR *prop, VARIANT *value, BOOL vb)
2833 {
2834     TRACE("(%p)->(%s)\n", This, debugstr_w(prop));
2835 
2836     if (!value) return E_POINTER;
2837 
2838     if (!memcmp(PropertyLexicalHandlerW, prop, sizeof(PropertyLexicalHandlerW)))
2839     {
2840         V_VT(value) = VT_UNKNOWN;
2841         saxreader_get_handler(This, SAXLexicalHandler, vb, (void**)&V_UNKNOWN(value));
2842         return S_OK;
2843     }
2844 
2845     if (!memcmp(PropertyDeclHandlerW, prop, sizeof(PropertyDeclHandlerW)))
2846     {
2847         V_VT(value) = VT_UNKNOWN;
2848         saxreader_get_handler(This, SAXDeclHandler, vb, (void**)&V_UNKNOWN(value));
2849         return S_OK;
2850     }
2851 
2852     if (!memcmp(PropertyXmlDeclVersionW, prop, sizeof(PropertyXmlDeclVersionW)))
2853     {
2854         V_VT(value) = VT_BSTR;
2855         V_BSTR(value) = SysAllocString(This->xmldecl_version);
2856         return S_OK;
2857     }
2858 
2859     FIXME("(%p)->(%s) unsupported property\n", This, debugstr_w(prop));
2860 
2861     return E_NOTIMPL;
2862 }
2863 
2864 /*** IVBSAXXMLReader interface ***/
2865 /*** IUnknown methods ***/
2866 static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID riid, void **ppvObject)
2867 {
2868     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2869 
2870     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2871 
2872     *ppvObject = NULL;
2873 
2874     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2875          IsEqualGUID( riid, &IID_IDispatch ) ||
2876          IsEqualGUID( riid, &IID_IVBSAXXMLReader ))
2877     {
2878         *ppvObject = iface;
2879     }
2880     else if( IsEqualGUID( riid, &IID_ISAXXMLReader ))
2881     {
2882         *ppvObject = &This->ISAXXMLReader_iface;
2883     }
2884     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
2885     {
2886         return *ppvObject ? S_OK : E_NOINTERFACE;
2887     }
2888     else
2889     {
2890         FIXME("interface %s not implemented\n", debugstr_guid(riid));
2891         return E_NOINTERFACE;
2892     }
2893 
2894     IVBSAXXMLReader_AddRef( iface );
2895 
2896     return S_OK;
2897 }
2898 
2899 static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader* iface)
2900 {
2901     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2902     TRACE("%p\n", This );
2903     return InterlockedIncrement( &This->ref );
2904 }
2905 
2906 static ULONG WINAPI saxxmlreader_Release(
2907     IVBSAXXMLReader* iface)
2908 {
2909     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2910     LONG ref;
2911 
2912     TRACE("%p\n", This );
2913 
2914     ref = InterlockedDecrement( &This->ref );
2915     if ( ref == 0 )
2916     {
2917         int i;
2918 
2919         for (i = 0; i < SAXHandler_Last; i++)
2920         {
2921             struct saxanyhandler_iface *saxiface = &This->saxhandlers[i].u.anyhandler;
2922 
2923             if (saxiface->handler)
2924                 IUnknown_Release(saxiface->handler);
2925 
2926             if (saxiface->vbhandler)
2927                 IUnknown_Release(saxiface->vbhandler);
2928         }
2929 
2930         SysFreeString(This->xmldecl_version);
2931         free_bstr_pool(&This->pool);
2932 
2933         heap_free( This );
2934     }
2935 
2936     return ref;
2937 }
2938 /*** IDispatch ***/
2939 static HRESULT WINAPI saxxmlreader_GetTypeInfoCount( IVBSAXXMLReader *iface, UINT* pctinfo )
2940 {
2941     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2942     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2943 }
2944 
2945 static HRESULT WINAPI saxxmlreader_GetTypeInfo(
2946     IVBSAXXMLReader *iface,
2947     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2948 {
2949     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2950     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
2951         iTInfo, lcid, ppTInfo);
2952 }
2953 
2954 static HRESULT WINAPI saxxmlreader_GetIDsOfNames(
2955     IVBSAXXMLReader *iface,
2956     REFIID riid,
2957     LPOLESTR* rgszNames,
2958     UINT cNames,
2959     LCID lcid,
2960     DISPID* rgDispId)
2961 {
2962     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2963     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
2964         riid, rgszNames, cNames, lcid, rgDispId);
2965 }
2966 
2967 static HRESULT WINAPI saxxmlreader_Invoke(
2968     IVBSAXXMLReader *iface,
2969     DISPID dispIdMember,
2970     REFIID riid,
2971     LCID lcid,
2972     WORD wFlags,
2973     DISPPARAMS* pDispParams,
2974     VARIANT* pVarResult,
2975     EXCEPINFO* pExcepInfo,
2976     UINT* puArgErr)
2977 {
2978     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2979     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
2980         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2981 }
2982 
2983 /*** IVBSAXXMLReader methods ***/
2984 static HRESULT WINAPI saxxmlreader_getFeature(
2985     IVBSAXXMLReader* iface,
2986     BSTR feature_name,
2987     VARIANT_BOOL *value)
2988 {
2989     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2990     return ISAXXMLReader_getFeature(&This->ISAXXMLReader_iface, feature_name, value);
2991 }
2992 
2993 static HRESULT WINAPI saxxmlreader_putFeature(
2994     IVBSAXXMLReader* iface,
2995     BSTR feature_name,
2996     VARIANT_BOOL value)
2997 {
2998     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2999     return ISAXXMLReader_putFeature(&This->ISAXXMLReader_iface, feature_name, value);
3000 }
3001 
3002 static HRESULT WINAPI saxxmlreader_getProperty(
3003     IVBSAXXMLReader* iface,
3004     BSTR prop,
3005     VARIANT *value)
3006 {
3007     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3008     return internal_getProperty(This, prop, value, TRUE);
3009 }
3010 
3011 static HRESULT WINAPI saxxmlreader_putProperty(
3012     IVBSAXXMLReader* iface,
3013     BSTR pProp,
3014     VARIANT value)
3015 {
3016     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3017     return internal_putProperty(This, pProp, value, TRUE);
3018 }
3019 
3020 static HRESULT WINAPI saxxmlreader_get_entityResolver(
3021     IVBSAXXMLReader* iface,
3022     IVBSAXEntityResolver **resolver)
3023 {
3024     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3025     return saxreader_get_handler(This, SAXEntityResolver, TRUE, (void**)resolver);
3026 }
3027 
3028 static HRESULT WINAPI saxxmlreader_put_entityResolver(
3029     IVBSAXXMLReader* iface,
3030     IVBSAXEntityResolver *resolver)
3031 {
3032     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3033     return saxreader_put_handler(This, SAXEntityResolver, resolver, TRUE);
3034 }
3035 
3036 static HRESULT WINAPI saxxmlreader_get_contentHandler(
3037     IVBSAXXMLReader* iface,
3038     IVBSAXContentHandler **handler)
3039 {
3040     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3041     return saxreader_get_handler(This, SAXContentHandler, TRUE, (void**)handler);
3042 }
3043 
3044 static HRESULT WINAPI saxxmlreader_put_contentHandler(
3045     IVBSAXXMLReader* iface,
3046     IVBSAXContentHandler *handler)
3047 {
3048     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3049     return saxreader_put_handler(This, SAXContentHandler, handler, TRUE);
3050 }
3051 
3052 static HRESULT WINAPI saxxmlreader_get_dtdHandler(
3053     IVBSAXXMLReader* iface,
3054     IVBSAXDTDHandler **handler)
3055 {
3056     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3057     return saxreader_get_handler(This, SAXDTDHandler, TRUE, (void**)handler);
3058 }
3059 
3060 static HRESULT WINAPI saxxmlreader_put_dtdHandler(
3061     IVBSAXXMLReader* iface,
3062     IVBSAXDTDHandler *handler)
3063 {
3064     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3065     return saxreader_put_handler(This, SAXDTDHandler, handler, TRUE);
3066 }
3067 
3068 static HRESULT WINAPI saxxmlreader_get_errorHandler(
3069     IVBSAXXMLReader* iface,
3070     IVBSAXErrorHandler **handler)
3071 {
3072     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3073     return saxreader_get_handler(This, SAXErrorHandler, TRUE, (void**)handler);
3074 }
3075 
3076 static HRESULT WINAPI saxxmlreader_put_errorHandler(
3077     IVBSAXXMLReader* iface,
3078     IVBSAXErrorHandler *handler)
3079 {
3080     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3081     return saxreader_put_handler(This, SAXErrorHandler, handler, TRUE);
3082 }
3083 
3084 static HRESULT WINAPI saxxmlreader_get_baseURL(
3085     IVBSAXXMLReader* iface,
3086     BSTR *pBaseUrl)
3087 {
3088     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3089 
3090     FIXME("(%p)->(%p) stub\n", This, pBaseUrl);
3091     return E_NOTIMPL;
3092 }
3093 
3094 static HRESULT WINAPI saxxmlreader_put_baseURL(
3095     IVBSAXXMLReader* iface,
3096     BSTR pBaseUrl)
3097 {
3098     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3099     return ISAXXMLReader_putBaseURL(&This->ISAXXMLReader_iface, pBaseUrl);
3100 }
3101 
3102 static HRESULT WINAPI saxxmlreader_get_secureBaseURL(
3103     IVBSAXXMLReader* iface,
3104     BSTR *pSecureBaseUrl)
3105 {
3106     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3107 
3108     FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
3109     return E_NOTIMPL;
3110 }
3111 
3112 static HRESULT WINAPI saxxmlreader_put_secureBaseURL(
3113     IVBSAXXMLReader* iface,
3114     BSTR secureBaseUrl)
3115 {
3116     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3117     return ISAXXMLReader_putSecureBaseURL(&This->ISAXXMLReader_iface, secureBaseUrl);
3118 }
3119 
3120 static HRESULT WINAPI saxxmlreader_parse(
3121     IVBSAXXMLReader* iface,
3122     VARIANT varInput)
3123 {
3124     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3125     return internal_parse(This, varInput, TRUE);
3126 }
3127 
3128 static HRESULT WINAPI saxxmlreader_parseURL(
3129     IVBSAXXMLReader* iface,
3130     BSTR url)
3131 {
3132     saxreader *This = impl_from_IVBSAXXMLReader( iface );
3133     return internal_parseURL(This, url, TRUE);
3134 }
3135 
3136 static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl =
3137 {
3138     saxxmlreader_QueryInterface,
3139     saxxmlreader_AddRef,
3140     saxxmlreader_Release,
3141     saxxmlreader_GetTypeInfoCount,
3142     saxxmlreader_GetTypeInfo,
3143     saxxmlreader_GetIDsOfNames,
3144     saxxmlreader_Invoke,
3145     saxxmlreader_getFeature,
3146     saxxmlreader_putFeature,
3147     saxxmlreader_getProperty,
3148     saxxmlreader_putProperty,
3149     saxxmlreader_get_entityResolver,
3150     saxxmlreader_put_entityResolver,
3151     saxxmlreader_get_contentHandler,
3152     saxxmlreader_put_contentHandler,
3153     saxxmlreader_get_dtdHandler,
3154     saxxmlreader_put_dtdHandler,
3155     saxxmlreader_get_errorHandler,
3156     saxxmlreader_put_errorHandler,
3157     saxxmlreader_get_baseURL,
3158     saxxmlreader_put_baseURL,
3159     saxxmlreader_get_secureBaseURL,
3160     saxxmlreader_put_secureBaseURL,
3161     saxxmlreader_parse,
3162     saxxmlreader_parseURL
3163 };
3164 
3165 /*** ISAXXMLReader interface ***/
3166 /*** IUnknown methods ***/
3167 static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader* iface, REFIID riid, void **ppvObject)
3168 {
3169     saxreader *This = impl_from_ISAXXMLReader( iface );
3170     return IVBSAXXMLReader_QueryInterface(&This->IVBSAXXMLReader_iface, riid, ppvObject);
3171 }
3172 
3173 static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader* iface)
3174 {
3175     saxreader *This = impl_from_ISAXXMLReader( iface );
3176     return IVBSAXXMLReader_AddRef(&This->IVBSAXXMLReader_iface);
3177 }
3178 
3179 static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader* iface)
3180 {
3181     saxreader *This = impl_from_ISAXXMLReader( iface );
3182     return IVBSAXXMLReader_Release(&This->IVBSAXXMLReader_iface);
3183 }
3184 
3185 /*** ISAXXMLReader methods ***/
3186 static HRESULT WINAPI isaxxmlreader_getFeature(
3187         ISAXXMLReader* iface,
3188         const WCHAR *feature_name,
3189         VARIANT_BOOL *value)
3190 {
3191     saxreader *This = impl_from_ISAXXMLReader( iface );
3192     saxreader_feature feature;
3193 
3194     TRACE("(%p)->(%s %p)\n", This, debugstr_w(feature_name), value);
3195 
3196     feature = get_saxreader_feature(feature_name);
3197     if (feature == Namespaces || feature == NamespacePrefixes)
3198         return get_feature_value(This, feature, value);
3199 
3200     FIXME("(%p)->(%s %p) stub\n", This, debugstr_w(feature_name), value);
3201     return E_NOTIMPL;
3202 }
3203 
3204 static HRESULT WINAPI isaxxmlreader_putFeature(
3205         ISAXXMLReader* iface,
3206         const WCHAR *feature_name,
3207         VARIANT_BOOL value)
3208 {
3209     saxreader *This = impl_from_ISAXXMLReader( iface );
3210     saxreader_feature feature;
3211 
3212     TRACE("(%p)->(%s %x)\n", This, debugstr_w(feature_name), value);
3213 
3214     feature = get_saxreader_feature(feature_name);
3215 
3216     /* accepted cases */
3217     if ((feature == ExternalGeneralEntities   && value == VARIANT_FALSE) ||
3218         (feature == ExternalParameterEntities && value == VARIANT_FALSE) ||
3219          feature == Namespaces ||
3220          feature == NamespacePrefixes)
3221     {
3222         return set_feature_value(This, feature, value);
3223     }
3224 
3225     if (feature == LexicalHandlerParEntities || feature == ProhibitDTD)
3226     {
3227         FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
3228         return set_feature_value(This, feature, value);
3229     }
3230 
3231     FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
3232     return E_NOTIMPL;
3233 }
3234 
3235 static HRESULT WINAPI isaxxmlreader_getProperty(
3236         ISAXXMLReader* iface,
3237         const WCHAR *prop,
3238         VARIANT *value)
3239 {
3240     saxreader *This = impl_from_ISAXXMLReader( iface );
3241     return internal_getProperty(This, prop, value, FALSE);
3242 }
3243 
3244 static HRESULT WINAPI isaxxmlreader_putProperty(
3245         ISAXXMLReader* iface,
3246         const WCHAR *pProp,
3247         VARIANT value)
3248 {
3249     saxreader *This = impl_from_ISAXXMLReader( iface );
3250     return internal_putProperty(This, pProp, value, FALSE);
3251 }
3252 
3253 static HRESULT WINAPI isaxxmlreader_getEntityResolver(
3254         ISAXXMLReader* iface,
3255         ISAXEntityResolver **resolver)
3256 {
3257     saxreader *This = impl_from_ISAXXMLReader( iface );
3258     return saxreader_get_handler(This, SAXEntityResolver, FALSE, (void**)resolver);
3259 }
3260 
3261 static HRESULT WINAPI isaxxmlreader_putEntityResolver(
3262         ISAXXMLReader* iface,
3263         ISAXEntityResolver *resolver)
3264 {
3265     saxreader *This = impl_from_ISAXXMLReader( iface );
3266     return saxreader_put_handler(This, SAXEntityResolver, resolver, FALSE);
3267 }
3268 
3269 static HRESULT WINAPI isaxxmlreader_getContentHandler(
3270         ISAXXMLReader* iface,
3271         ISAXContentHandler **handler)
3272 {
3273     saxreader *This = impl_from_ISAXXMLReader( iface );
3274     return saxreader_get_handler(This, SAXContentHandler, FALSE, (void**)handler);
3275 }
3276 
3277 static HRESULT WINAPI isaxxmlreader_putContentHandler(
3278     ISAXXMLReader* iface,
3279     ISAXContentHandler *handler)
3280 {
3281     saxreader *This = impl_from_ISAXXMLReader( iface );
3282     return saxreader_put_handler(This, SAXContentHandler, handler, FALSE);
3283 }
3284 
3285 static HRESULT WINAPI isaxxmlreader_getDTDHandler(
3286         ISAXXMLReader* iface,
3287         ISAXDTDHandler **handler)
3288 {
3289     saxreader *This = impl_from_ISAXXMLReader( iface );
3290     return saxreader_get_handler(This, SAXDTDHandler, FALSE, (void**)handler);
3291 }
3292 
3293 static HRESULT WINAPI isaxxmlreader_putDTDHandler(
3294         ISAXXMLReader* iface,
3295         ISAXDTDHandler *handler)
3296 {
3297     saxreader *This = impl_from_ISAXXMLReader( iface );
3298     return saxreader_put_handler(This, SAXDTDHandler, handler, FALSE);
3299 }
3300 
3301 static HRESULT WINAPI isaxxmlreader_getErrorHandler(
3302         ISAXXMLReader* iface,
3303         ISAXErrorHandler **handler)
3304 {
3305     saxreader *This = impl_from_ISAXXMLReader( iface );
3306     return saxreader_get_handler(This, SAXErrorHandler, FALSE, (void**)handler);
3307 }
3308 
3309 static HRESULT WINAPI isaxxmlreader_putErrorHandler(ISAXXMLReader* iface, ISAXErrorHandler *handler)
3310 {
3311     saxreader *This = impl_from_ISAXXMLReader( iface );
3312     return saxreader_put_handler(This, SAXErrorHandler, handler, FALSE);
3313 }
3314 
3315 static HRESULT WINAPI isaxxmlreader_getBaseURL(
3316         ISAXXMLReader* iface,
3317         const WCHAR **base_url)
3318 {
3319     saxreader *This = impl_from_ISAXXMLReader( iface );
3320 
3321     FIXME("(%p)->(%p) stub\n", This, base_url);
3322     return E_NOTIMPL;
3323 }
3324 
3325 static HRESULT WINAPI isaxxmlreader_putBaseURL(
3326         ISAXXMLReader* iface,
3327         const WCHAR *pBaseUrl)
3328 {
3329     saxreader *This = impl_from_ISAXXMLReader( iface );
3330 
3331     FIXME("(%p)->(%s) stub\n", This, debugstr_w(pBaseUrl));
3332     return E_NOTIMPL;
3333 }
3334 
3335 static HRESULT WINAPI isaxxmlreader_getSecureBaseURL(
3336         ISAXXMLReader* iface,
3337         const WCHAR **pSecureBaseUrl)
3338 {
3339     saxreader *This = impl_from_ISAXXMLReader( iface );
3340     FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
3341     return E_NOTIMPL;
3342 }
3343 
3344 static HRESULT WINAPI isaxxmlreader_putSecureBaseURL(
3345         ISAXXMLReader* iface,
3346         const WCHAR *secureBaseUrl)
3347 {
3348     saxreader *This = impl_from_ISAXXMLReader( iface );
3349 
3350     FIXME("(%p)->(%s) stub\n", This, debugstr_w(secureBaseUrl));
3351     return E_NOTIMPL;
3352 }
3353 
3354 static HRESULT WINAPI isaxxmlreader_parse(
3355         ISAXXMLReader* iface,
3356         VARIANT varInput)
3357 {
3358     saxreader *This = impl_from_ISAXXMLReader( iface );
3359     return internal_parse(This, varInput, FALSE);
3360 }
3361 
3362 static HRESULT WINAPI isaxxmlreader_parseURL(
3363         ISAXXMLReader* iface,
3364         const WCHAR *url)
3365 {
3366     saxreader *This = impl_from_ISAXXMLReader( iface );
3367     return internal_parseURL(This, url, FALSE);
3368 }
3369 
3370 static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl =
3371 {
3372     isaxxmlreader_QueryInterface,
3373     isaxxmlreader_AddRef,
3374     isaxxmlreader_Release,
3375     isaxxmlreader_getFeature,
3376     isaxxmlreader_putFeature,
3377     isaxxmlreader_getProperty,
3378     isaxxmlreader_putProperty,
3379     isaxxmlreader_getEntityResolver,
3380     isaxxmlreader_putEntityResolver,
3381     isaxxmlreader_getContentHandler,
3382     isaxxmlreader_putContentHandler,
3383     isaxxmlreader_getDTDHandler,
3384     isaxxmlreader_putDTDHandler,
3385     isaxxmlreader_getErrorHandler,
3386     isaxxmlreader_putErrorHandler,
3387     isaxxmlreader_getBaseURL,
3388     isaxxmlreader_putBaseURL,
3389     isaxxmlreader_getSecureBaseURL,
3390     isaxxmlreader_putSecureBaseURL,
3391     isaxxmlreader_parse,
3392     isaxxmlreader_parseURL
3393 };
3394 
3395 static const tid_t saxreader_iface_tids[] = {
3396     IVBSAXXMLReader_tid,
3397     0
3398 };
3399 static dispex_static_data_t saxreader_dispex = {
3400     NULL,
3401     IVBSAXXMLReader_tid,
3402     NULL,
3403     saxreader_iface_tids
3404 };
3405 
3406 HRESULT SAXXMLReader_create(MSXML_VERSION version, LPVOID *ppObj)
3407 {
3408     saxreader *reader;
3409 
3410     TRACE("(%p)\n", ppObj);
3411 
3412     reader = heap_alloc( sizeof (*reader) );
3413     if( !reader )
3414         return E_OUTOFMEMORY;
3415 
3416     reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl;
3417     reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl;
3418     reader->ref = 1;
3419     memset(reader->saxhandlers, 0, sizeof(reader->saxhandlers));
3420     reader->isParsing = FALSE;
3421     reader->xmldecl_version = NULL;
3422     reader->pool.pool = NULL;
3423     reader->pool.index = 0;
3424     reader->pool.len = 0;
3425     reader->features = Namespaces | NamespacePrefixes;
3426     reader->version = version;
3427 
3428     init_dispex(&reader->dispex, (IUnknown*)&reader->IVBSAXXMLReader_iface, &saxreader_dispex);
3429 
3430     memset(&reader->sax, 0, sizeof(xmlSAXHandler));
3431     reader->sax.initialized = XML_SAX2_MAGIC;
3432     reader->sax.startDocument = libxmlStartDocument;
3433     reader->sax.endDocument = libxmlEndDocument;
3434     reader->sax.startElementNs = libxmlStartElementNS;
3435     reader->sax.endElementNs = libxmlEndElementNS;
3436     reader->sax.characters = libxmlCharacters;
3437     reader->sax.setDocumentLocator = libxmlSetDocumentLocator;
3438     reader->sax.comment = libxmlComment;
3439     reader->sax.error = libxmlFatalError;
3440     reader->sax.fatalError = libxmlFatalError;
3441     reader->sax.cdataBlock = libxml_cdatablock;
3442     reader->sax.resolveEntity = libxmlresolveentity;
3443 
3444     *ppObj = &reader->IVBSAXXMLReader_iface;
3445 
3446     TRACE("returning iface %p\n", *ppObj);
3447 
3448     return S_OK;
3449 }
3450 
3451 #else
3452 
3453 HRESULT SAXXMLReader_create(MSXML_VERSION version, LPVOID *ppObj)
3454 {
3455     MESSAGE("This program tried to use a SAX XML Reader object, but\n"
3456             "libxml2 support was not present at compile time.\n");
3457     return E_NOTIMPL;
3458 }
3459 
3460 #endif
3461