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