msxml3: Use expected/actual sequence concept for reader tests including attributes...
[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 >= MSXML4 ? 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         static const xmlChar xmlA[] = "xml";
1139
1140         if (xmlStrEqual(xmlAttributes[index*5+1], xmlA))
1141             attrs[index].szURI = bstr_from_xmlChar(xmlAttributes[index*5+2]);
1142         else
1143             attrs[index].szURI = find_element_uri(locator, xmlAttributes[index*5+2]);
1144
1145         attrs[index].szLocalname = bstr_from_xmlChar(xmlAttributes[index*5]);
1146         attrs[index].szValue = bstr_from_xmlCharN(xmlAttributes[index*5+3],
1147                 xmlAttributes[index*5+4]-xmlAttributes[index*5+3]);
1148         attrs[index].szQName = QName_from_xmlChar(xmlAttributes[index*5+1],
1149                 xmlAttributes[index*5]);
1150     }
1151
1152     return S_OK;
1153 }
1154
1155 /*** LibXML callbacks ***/
1156 static void libxmlStartDocument(void *ctx)
1157 {
1158     saxlocator *This = ctx;
1159     HRESULT hr;
1160
1161     if (This->saxreader->version >= MSXML4)
1162     {
1163         const xmlChar *p = This->pParserCtxt->input->cur-1;
1164         update_position(This, FALSE);
1165         while(p>This->pParserCtxt->input->base && *p!='>')
1166         {
1167             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1168                 This->line--;
1169             p--;
1170         }
1171         This->column = 0;
1172         for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1173             This->column++;
1174     }
1175
1176     if(has_content_handler(This))
1177     {
1178         if(This->vbInterface)
1179             hr = IVBSAXContentHandler_startDocument(This->saxreader->vbcontentHandler);
1180         else
1181             hr = ISAXContentHandler_startDocument(This->saxreader->contentHandler);
1182
1183         if (sax_callback_failed(This, hr))
1184             format_error_message_from_id(This, hr);
1185     }
1186 }
1187
1188 static void libxmlEndDocument(void *ctx)
1189 {
1190     saxlocator *This = ctx;
1191     HRESULT hr;
1192
1193     if (This->saxreader->version >= MSXML4) {
1194         update_position(This, FALSE);
1195         if(This->column > 1)
1196             This->line++;
1197         This->column = 0;
1198     } else {
1199         This->column = 0;
1200         This->line = 0;
1201     }
1202
1203     if(This->ret != S_OK) return;
1204
1205     if(has_content_handler(This))
1206     {
1207         if(This->vbInterface)
1208             hr = IVBSAXContentHandler_endDocument(This->saxreader->vbcontentHandler);
1209         else
1210             hr = ISAXContentHandler_endDocument(This->saxreader->contentHandler);
1211
1212         if (sax_callback_failed(This, hr))
1213             format_error_message_from_id(This, hr);
1214     }
1215 }
1216
1217 static void libxmlStartElementNS(
1218         void *ctx,
1219         const xmlChar *localname,
1220         const xmlChar *prefix,
1221         const xmlChar *URI,
1222         int nb_namespaces,
1223         const xmlChar **namespaces,
1224         int nb_attributes,
1225         int nb_defaulted,
1226         const xmlChar **attributes)
1227 {
1228     saxlocator *This = ctx;
1229     element_entry *element;
1230     HRESULT hr = S_OK;
1231
1232     update_position(This, TRUE);
1233     if(*(This->pParserCtxt->input->cur) == '/')
1234         This->column++;
1235     if(This->saxreader->version < MSXML4)
1236         This->column++;
1237
1238     element = alloc_element_entry(localname, prefix, nb_namespaces, namespaces);
1239     push_element_ns(This, element);
1240
1241     if (has_content_handler(This))
1242     {
1243         BSTR uri;
1244         int i;
1245
1246         for (i = 0; i < nb_namespaces; i++)
1247         {
1248             if(This->vbInterface)
1249                 hr = IVBSAXContentHandler_startPrefixMapping(
1250                         This->saxreader->vbcontentHandler,
1251                         &element->ns[i].prefix,
1252                         &element->ns[i].uri);
1253             else
1254                 hr = ISAXContentHandler_startPrefixMapping(
1255                         This->saxreader->contentHandler,
1256                         element->ns[i].prefix,
1257                         SysStringLen(element->ns[i].prefix),
1258                         element->ns[i].uri,
1259                         SysStringLen(element->ns[i].uri));
1260
1261             if (sax_callback_failed(This, hr))
1262             {
1263                 format_error_message_from_id(This, hr);
1264                 return;
1265             }
1266         }
1267
1268         uri = find_element_uri(This, URI);
1269
1270         hr = SAXAttributes_populate(This, nb_namespaces, namespaces, nb_attributes, attributes);
1271         if(hr == S_OK)
1272         {
1273             if(This->vbInterface)
1274                 hr = IVBSAXContentHandler_startElement(This->saxreader->vbcontentHandler,
1275                         &uri, &element->local, &element->qname, &This->IVBSAXAttributes_iface);
1276             else
1277                 hr = ISAXContentHandler_startElement(This->saxreader->contentHandler,
1278                         uri, SysStringLen(uri),
1279                         element->local, SysStringLen(element->local),
1280                         element->qname, SysStringLen(element->qname),
1281                         &This->ISAXAttributes_iface);
1282         }
1283     }
1284
1285     if (sax_callback_failed(This, hr))
1286         format_error_message_from_id(This, hr);
1287 }
1288
1289 static void libxmlEndElementNS(
1290         void *ctx,
1291         const xmlChar *localname,
1292         const xmlChar *prefix,
1293         const xmlChar *URI)
1294 {
1295     saxlocator *This = ctx;
1296     element_entry *element;
1297     const xmlChar *p;
1298     HRESULT hr;
1299     BSTR uri;
1300     int i;
1301
1302     update_position(This, FALSE);
1303     p = This->pParserCtxt->input->cur;
1304
1305     if (This->saxreader->version >= MSXML4)
1306     {
1307         p--;
1308         while(p>This->pParserCtxt->input->base && *p!='>')
1309         {
1310             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1311                 This->line--;
1312             p--;
1313         }
1314     }
1315     else if(*(p-1)!='>' || *(p-2)!='/')
1316     {
1317         p--;
1318         while(p-2>=This->pParserCtxt->input->base
1319                 && *(p-2)!='<' && *(p-1)!='/')
1320         {
1321             if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1322                 This->line--;
1323             p--;
1324         }
1325     }
1326     This->column = 0;
1327     for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1328         This->column++;
1329
1330     uri = find_element_uri(This, URI);
1331     element = pop_element_ns(This);
1332
1333     if (!has_content_handler(This))
1334     {
1335         This->nb_attributes = 0;
1336         free_element_entry(element);
1337         return;
1338     }
1339
1340     if(This->vbInterface)
1341         hr = IVBSAXContentHandler_endElement(
1342                 This->saxreader->vbcontentHandler,
1343                 &uri, &element->local, &element->qname);
1344     else
1345         hr = ISAXContentHandler_endElement(
1346                 This->saxreader->contentHandler,
1347                 uri, SysStringLen(uri),
1348                 element->local, SysStringLen(element->local),
1349                 element->qname, SysStringLen(element->qname));
1350
1351     This->nb_attributes = 0;
1352
1353     if (sax_callback_failed(This, hr))
1354     {
1355         format_error_message_from_id(This, hr);
1356         free_element_entry(element);
1357         return;
1358     }
1359
1360     i = -1;
1361     while (iterate_endprefix_index(This, element, &i))
1362     {
1363         if(This->vbInterface)
1364             hr = IVBSAXContentHandler_endPrefixMapping(
1365                     This->saxreader->vbcontentHandler, &element->ns[i].prefix);
1366         else
1367             hr = ISAXContentHandler_endPrefixMapping(
1368                     This->saxreader->contentHandler,
1369                     element->ns[i].prefix, SysStringLen(element->ns[i].prefix));
1370
1371         if (sax_callback_failed(This, hr)) break;
1372     }
1373
1374     if (sax_callback_failed(This, hr))
1375         format_error_message_from_id(This, hr);
1376
1377     free_element_entry(element);
1378 }
1379
1380 static void libxmlCharacters(
1381         void *ctx,
1382         const xmlChar *ch,
1383         int len)
1384 {
1385     saxlocator *This = ctx;
1386     BSTR Chars;
1387     HRESULT hr;
1388     xmlChar *cur, *end;
1389     BOOL lastEvent = FALSE;
1390
1391     if(!(has_content_handler(This))) return;
1392
1393     update_position(This, FALSE);
1394     cur = (xmlChar*)This->pParserCtxt->input->cur;
1395     while(cur>=This->pParserCtxt->input->base && *cur!='>')
1396     {
1397         if(*cur=='\n' || (*cur=='\r' && *(cur+1)!='\n'))
1398             This->line--;
1399         cur--;
1400     }
1401     This->column = 1;
1402     for(; cur>=This->pParserCtxt->input->base && *cur!='\n' && *cur!='\r'; cur--)
1403         This->column++;
1404
1405     cur = (xmlChar*)ch;
1406     if(*(ch-1)=='\r') cur--;
1407     end = cur;
1408
1409     while(1)
1410     {
1411         while(end-ch<len && *end!='\r') end++;
1412         if(end-ch==len)
1413         {
1414             lastEvent = TRUE;
1415         }
1416         else
1417         {
1418             *end = '\n';
1419             end++;
1420         }
1421
1422         if (This->saxreader->version >= MSXML4)
1423         {
1424             xmlChar *p;
1425
1426             for(p=cur; p!=end; p++)
1427             {
1428                 if(*p=='\n')
1429                 {
1430                     This->line++;
1431                     This->column = 1;
1432                 }
1433                 else
1434                 {
1435                     This->column++;
1436                 }
1437             }
1438
1439             if(!lastEvent)
1440                 This->column = 0;
1441         }
1442
1443         Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur);
1444         if(This->vbInterface)
1445             hr = IVBSAXContentHandler_characters(
1446                     This->saxreader->vbcontentHandler, &Chars);
1447         else
1448             hr = ISAXContentHandler_characters(
1449                     This->saxreader->contentHandler,
1450                     Chars, SysStringLen(Chars));
1451
1452         if (sax_callback_failed(This, hr))
1453         {
1454             format_error_message_from_id(This, hr);
1455             return;
1456         }
1457
1458         if (This->saxreader->version < MSXML4)
1459             This->column += end-cur;
1460
1461         if(lastEvent)
1462             break;
1463
1464         *(end-1) = '\r';
1465         if(*end == '\n')
1466         {
1467             end++;
1468             This->column++;
1469         }
1470         cur = end;
1471
1472         if(end-ch == len) break;
1473     }
1474 }
1475
1476 static void libxmlSetDocumentLocator(
1477         void *ctx,
1478         xmlSAXLocatorPtr loc)
1479 {
1480     saxlocator *This = ctx;
1481     HRESULT hr = S_OK;
1482
1483     if(has_content_handler(This))
1484     {
1485         if(This->vbInterface)
1486             hr = IVBSAXContentHandler_putref_documentLocator(This->saxreader->vbcontentHandler,
1487                     &This->IVBSAXLocator_iface);
1488         else
1489             hr = ISAXContentHandler_putDocumentLocator(This->saxreader->contentHandler,
1490                     &This->ISAXLocator_iface);
1491     }
1492
1493     if(FAILED(hr))
1494         format_error_message_from_id(This, hr);
1495 }
1496
1497 static void libxmlComment(void *ctx, const xmlChar *value)
1498 {
1499     saxlocator *This = ctx;
1500     BSTR bValue;
1501     HRESULT hr;
1502     const xmlChar *p = This->pParserCtxt->input->cur;
1503
1504     update_position(This, FALSE);
1505     while(p-4>=This->pParserCtxt->input->base
1506             && memcmp(p-4, "<!--", sizeof(char[4])))
1507     {
1508         if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
1509             This->line--;
1510         p--;
1511     }
1512     This->column = 0;
1513     for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
1514         This->column++;
1515
1516     if(!This->vbInterface && !This->saxreader->lexicalHandler) return;
1517     if(This->vbInterface && !This->saxreader->vblexicalHandler) return;
1518
1519     bValue = pooled_bstr_from_xmlChar(&This->saxreader->pool, value);
1520
1521     if(This->vbInterface)
1522         hr = IVBSAXLexicalHandler_comment(
1523                 This->saxreader->vblexicalHandler, &bValue);
1524     else
1525         hr = ISAXLexicalHandler_comment(
1526                 This->saxreader->lexicalHandler,
1527                 bValue, SysStringLen(bValue));
1528
1529     if(FAILED(hr))
1530         format_error_message_from_id(This, hr);
1531 }
1532
1533 static void libxmlFatalError(void *ctx, const char *msg, ...)
1534 {
1535     saxlocator *This = ctx;
1536     char message[1024];
1537     WCHAR *error;
1538     DWORD len;
1539     va_list args;
1540
1541     if(This->ret != S_OK) {
1542         xmlStopParser(This->pParserCtxt);
1543         return;
1544     }
1545
1546     va_start(args, msg);
1547     vsprintf(message, msg, args);
1548     va_end(args);
1549
1550     len = MultiByteToWideChar(CP_UNIXCP, 0, message, -1, NULL, 0);
1551     error = heap_alloc(sizeof(WCHAR)*len);
1552     if(error)
1553     {
1554         MultiByteToWideChar(CP_UNIXCP, 0, message, -1, error, len);
1555         TRACE("fatal error for %p: %s\n", This, debugstr_w(error));
1556     }
1557
1558     if(!has_error_handler(This))
1559     {
1560         xmlStopParser(This->pParserCtxt);
1561         This->ret = E_FAIL;
1562         heap_free(error);
1563         return;
1564     }
1565
1566     FIXME("Error handling is not compatible.\n");
1567
1568     if(This->vbInterface)
1569     {
1570         BSTR bstrError = SysAllocString(error);
1571         IVBSAXErrorHandler_fatalError(This->saxreader->vberrorHandler, &This->IVBSAXLocator_iface,
1572                 &bstrError, E_FAIL);
1573         SysFreeString(bstrError);
1574     }
1575     else
1576         ISAXErrorHandler_fatalError(This->saxreader->errorHandler, &This->ISAXLocator_iface,
1577                 error, E_FAIL);
1578
1579     heap_free(error);
1580
1581     xmlStopParser(This->pParserCtxt);
1582     This->ret = E_FAIL;
1583 }
1584
1585 static void libxmlCDataBlock(void *ctx, const xmlChar *value, int len)
1586 {
1587     saxlocator *This = ctx;
1588     HRESULT hr = S_OK;
1589     xmlChar *beg = (xmlChar*)This->pParserCtxt->input->cur-len;
1590     xmlChar *cur, *end;
1591     int realLen;
1592     BSTR Chars;
1593     BOOL lastEvent = FALSE, change;
1594
1595     update_position(This, FALSE);
1596     while(beg-9>=This->pParserCtxt->input->base
1597             && memcmp(beg-9, "<![CDATA[", sizeof(char[9])))
1598     {
1599         if(*beg=='\n' || (*beg=='\r' && *(beg+1)!='\n'))
1600             This->line--;
1601         beg--;
1602     }
1603     This->column = 0;
1604     for(; beg>=This->pParserCtxt->input->base && *beg!='\n' && *beg!='\r'; beg--)
1605         This->column++;
1606
1607     if(This->vbInterface && This->saxreader->vblexicalHandler)
1608         hr = IVBSAXLexicalHandler_startCDATA(This->saxreader->vblexicalHandler);
1609     if(!This->vbInterface && This->saxreader->lexicalHandler)
1610         hr = ISAXLexicalHandler_startCDATA(This->saxreader->lexicalHandler);
1611
1612     if(FAILED(hr))
1613     {
1614         format_error_message_from_id(This, hr);
1615         return;
1616     }
1617
1618     realLen = This->pParserCtxt->input->cur-beg-3;
1619     cur = beg;
1620     end = beg;
1621
1622     while(1)
1623     {
1624         while(end-beg<realLen && *end!='\r') end++;
1625         if(end-beg==realLen)
1626         {
1627             end--;
1628             lastEvent = TRUE;
1629         }
1630         else if(end-beg==realLen-1 && *end=='\r' && *(end+1)=='\n')
1631             lastEvent = TRUE;
1632
1633         if(*end == '\r') change = TRUE;
1634         else change = FALSE;
1635
1636         if(change) *end = '\n';
1637
1638         if(has_content_handler(This))
1639         {
1640             Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur+1);
1641             if(This->vbInterface)
1642                 hr = IVBSAXContentHandler_characters(
1643                         This->saxreader->vbcontentHandler, &Chars);
1644             else
1645                 hr = ISAXContentHandler_characters(
1646                         This->saxreader->contentHandler,
1647                         Chars, SysStringLen(Chars));
1648         }
1649
1650         if(change) *end = '\r';
1651
1652         if(lastEvent)
1653             break;
1654
1655         This->column += end-cur+2;
1656         end += 2;
1657         cur = end;
1658     }
1659
1660     if(This->vbInterface && This->saxreader->vblexicalHandler)
1661         hr = IVBSAXLexicalHandler_endCDATA(This->saxreader->vblexicalHandler);
1662     if(!This->vbInterface && This->saxreader->lexicalHandler)
1663         hr = ISAXLexicalHandler_endCDATA(This->saxreader->lexicalHandler);
1664
1665     if(FAILED(hr))
1666         format_error_message_from_id(This, hr);
1667
1668     This->column += 4+end-cur;
1669 }
1670
1671 /*** IVBSAXLocator interface ***/
1672 /*** IUnknown methods ***/
1673 static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator* iface, REFIID riid, void **ppvObject)
1674 {
1675     saxlocator *This = impl_from_IVBSAXLocator( iface );
1676
1677     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject);
1678
1679     *ppvObject = NULL;
1680
1681     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
1682             IsEqualGUID( riid, &IID_IDispatch) ||
1683             IsEqualGUID( riid, &IID_IVBSAXLocator ))
1684     {
1685         *ppvObject = iface;
1686     }
1687     else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
1688     {
1689         *ppvObject = &This->IVBSAXAttributes_iface;
1690     }
1691     else
1692     {
1693         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1694         return E_NOINTERFACE;
1695     }
1696
1697     IVBSAXLocator_AddRef( iface );
1698
1699     return S_OK;
1700 }
1701
1702 static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator* iface)
1703 {
1704     saxlocator *This = impl_from_IVBSAXLocator( iface );
1705     TRACE("%p\n", This );
1706     return InterlockedIncrement( &This->ref );
1707 }
1708
1709 static ULONG WINAPI ivbsaxlocator_Release(
1710         IVBSAXLocator* iface)
1711 {
1712     saxlocator *This = impl_from_IVBSAXLocator( iface );
1713     return ISAXLocator_Release((ISAXLocator*)&This->IVBSAXLocator_iface);
1714 }
1715
1716 /*** IDispatch methods ***/
1717 static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount( IVBSAXLocator *iface, UINT* pctinfo )
1718 {
1719     saxlocator *This = impl_from_IVBSAXLocator( iface );
1720
1721     TRACE("(%p)->(%p)\n", This, pctinfo);
1722
1723     *pctinfo = 1;
1724
1725     return S_OK;
1726 }
1727
1728 static HRESULT WINAPI ivbsaxlocator_GetTypeInfo(
1729     IVBSAXLocator *iface,
1730     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1731 {
1732     saxlocator *This = impl_from_IVBSAXLocator( iface );
1733     HRESULT hr;
1734
1735     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1736
1737     hr = get_typeinfo(IVBSAXLocator_tid, ppTInfo);
1738
1739     return hr;
1740 }
1741
1742 static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames(
1743     IVBSAXLocator *iface,
1744     REFIID riid,
1745     LPOLESTR* rgszNames,
1746     UINT cNames,
1747     LCID lcid,
1748     DISPID* rgDispId)
1749 {
1750     saxlocator *This = impl_from_IVBSAXLocator( iface );
1751     ITypeInfo *typeinfo;
1752     HRESULT hr;
1753
1754     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1755           lcid, rgDispId);
1756
1757     if(!rgszNames || cNames == 0 || !rgDispId)
1758         return E_INVALIDARG;
1759
1760     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
1761     if(SUCCEEDED(hr))
1762     {
1763         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1764         ITypeInfo_Release(typeinfo);
1765     }
1766
1767     return hr;
1768 }
1769
1770 static HRESULT WINAPI ivbsaxlocator_Invoke(
1771     IVBSAXLocator *iface,
1772     DISPID dispIdMember,
1773     REFIID riid,
1774     LCID lcid,
1775     WORD wFlags,
1776     DISPPARAMS* pDispParams,
1777     VARIANT* pVarResult,
1778     EXCEPINFO* pExcepInfo,
1779     UINT* puArgErr)
1780 {
1781     saxlocator *This = impl_from_IVBSAXLocator( iface );
1782     ITypeInfo *typeinfo;
1783     HRESULT hr;
1784
1785     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1786           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1787
1788     hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
1789     if(SUCCEEDED(hr))
1790     {
1791         hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXLocator_iface, dispIdMember, wFlags,
1792                 pDispParams, pVarResult, pExcepInfo, puArgErr);
1793         ITypeInfo_Release(typeinfo);
1794     }
1795
1796     return hr;
1797 }
1798
1799 /*** IVBSAXLocator methods ***/
1800 static HRESULT WINAPI ivbsaxlocator_get_columnNumber(
1801         IVBSAXLocator* iface,
1802         int *pnColumn)
1803 {
1804     saxlocator *This = impl_from_IVBSAXLocator( iface );
1805     return ISAXLocator_getColumnNumber((ISAXLocator*)&This->IVBSAXLocator_iface, pnColumn);
1806 }
1807
1808 static HRESULT WINAPI ivbsaxlocator_get_lineNumber(
1809         IVBSAXLocator* iface,
1810         int *pnLine)
1811 {
1812     saxlocator *This = impl_from_IVBSAXLocator( iface );
1813     return ISAXLocator_getLineNumber((ISAXLocator*)&This->IVBSAXLocator_iface, pnLine);
1814 }
1815
1816 static HRESULT WINAPI ivbsaxlocator_get_publicId(
1817         IVBSAXLocator* iface,
1818         BSTR* publicId)
1819 {
1820     saxlocator *This = impl_from_IVBSAXLocator( iface );
1821     return ISAXLocator_getPublicId((ISAXLocator*)&This->IVBSAXLocator_iface,
1822             (const WCHAR**)publicId);
1823 }
1824
1825 static HRESULT WINAPI ivbsaxlocator_get_systemId(
1826         IVBSAXLocator* iface,
1827         BSTR* systemId)
1828 {
1829     saxlocator *This = impl_from_IVBSAXLocator( iface );
1830     return ISAXLocator_getSystemId((ISAXLocator*)&This->IVBSAXLocator_iface,
1831             (const WCHAR**)systemId);
1832 }
1833
1834 static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl =
1835 {
1836     ivbsaxlocator_QueryInterface,
1837     ivbsaxlocator_AddRef,
1838     ivbsaxlocator_Release,
1839     ivbsaxlocator_GetTypeInfoCount,
1840     ivbsaxlocator_GetTypeInfo,
1841     ivbsaxlocator_GetIDsOfNames,
1842     ivbsaxlocator_Invoke,
1843     ivbsaxlocator_get_columnNumber,
1844     ivbsaxlocator_get_lineNumber,
1845     ivbsaxlocator_get_publicId,
1846     ivbsaxlocator_get_systemId
1847 };
1848
1849 /*** ISAXLocator interface ***/
1850 /*** IUnknown methods ***/
1851 static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid, void **ppvObject)
1852 {
1853     saxlocator *This = impl_from_ISAXLocator( iface );
1854
1855     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
1856
1857     *ppvObject = NULL;
1858
1859     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
1860             IsEqualGUID( riid, &IID_ISAXLocator ))
1861     {
1862         *ppvObject = iface;
1863     }
1864     else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
1865     {
1866         *ppvObject = &This->ISAXAttributes_iface;
1867     }
1868     else
1869     {
1870         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1871         return E_NOINTERFACE;
1872     }
1873
1874     ISAXLocator_AddRef( iface );
1875
1876     return S_OK;
1877 }
1878
1879 static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface)
1880 {
1881     saxlocator *This = impl_from_ISAXLocator( iface );
1882     ULONG ref = InterlockedIncrement( &This->ref );
1883     TRACE("(%p)->(%d)\n", This, ref);
1884     return ref;
1885 }
1886
1887 static ULONG WINAPI isaxlocator_Release(
1888         ISAXLocator* iface)
1889 {
1890     saxlocator *This = impl_from_ISAXLocator( iface );
1891     LONG ref = InterlockedDecrement( &This->ref );
1892
1893     TRACE("(%p)->(%d)\n", This, ref );
1894
1895     if (ref == 0)
1896     {
1897         element_entry *element, *element2;
1898         int index;
1899
1900         SysFreeString(This->publicId);
1901         SysFreeString(This->systemId);
1902         SysFreeString(This->namespaceUri);
1903
1904         for(index=0; index<This->nb_attributes; index++)
1905         {
1906             SysFreeString(This->attributes[index].szLocalname);
1907             SysFreeString(This->attributes[index].szValue);
1908             SysFreeString(This->attributes[index].szQName);
1909         }
1910         heap_free(This->attributes);
1911
1912         /* element stack */
1913         LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry)
1914         {
1915             list_remove(&element->entry);
1916             free_element_entry(element);
1917         }
1918
1919         ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface);
1920         heap_free( This );
1921     }
1922
1923     return ref;
1924 }
1925
1926 /*** ISAXLocator methods ***/
1927 static HRESULT WINAPI isaxlocator_getColumnNumber(
1928         ISAXLocator* iface,
1929         int *pnColumn)
1930 {
1931     saxlocator *This = impl_from_ISAXLocator( iface );
1932
1933     *pnColumn = This->column;
1934     return S_OK;
1935 }
1936
1937 static HRESULT WINAPI isaxlocator_getLineNumber(
1938         ISAXLocator* iface,
1939         int *pnLine)
1940 {
1941     saxlocator *This = impl_from_ISAXLocator( iface );
1942
1943     *pnLine = This->line;
1944     return S_OK;
1945 }
1946
1947 static HRESULT WINAPI isaxlocator_getPublicId(
1948         ISAXLocator* iface,
1949         const WCHAR ** ppwchPublicId)
1950 {
1951     BSTR publicId;
1952     saxlocator *This = impl_from_ISAXLocator( iface );
1953
1954     SysFreeString(This->publicId);
1955
1956     publicId = bstr_from_xmlChar(xmlSAX2GetPublicId(This->pParserCtxt));
1957     if(SysStringLen(publicId))
1958         This->publicId = (WCHAR*)&publicId;
1959     else
1960     {
1961         SysFreeString(publicId);
1962         This->publicId = NULL;
1963     }
1964
1965     *ppwchPublicId = This->publicId;
1966     return S_OK;
1967 }
1968
1969 static HRESULT WINAPI isaxlocator_getSystemId(
1970         ISAXLocator* iface,
1971         const WCHAR ** ppwchSystemId)
1972 {
1973     BSTR systemId;
1974     saxlocator *This = impl_from_ISAXLocator( iface );
1975
1976     SysFreeString(This->systemId);
1977
1978     systemId = bstr_from_xmlChar(xmlSAX2GetSystemId(This->pParserCtxt));
1979     if(SysStringLen(systemId))
1980         This->systemId = (WCHAR*)&systemId;
1981     else
1982     {
1983         SysFreeString(systemId);
1984         This->systemId = NULL;
1985     }
1986
1987     *ppwchSystemId = This->systemId;
1988     return S_OK;
1989 }
1990
1991 static const struct ISAXLocatorVtbl SAXLocatorVtbl =
1992 {
1993     isaxlocator_QueryInterface,
1994     isaxlocator_AddRef,
1995     isaxlocator_Release,
1996     isaxlocator_getColumnNumber,
1997     isaxlocator_getLineNumber,
1998     isaxlocator_getPublicId,
1999     isaxlocator_getSystemId
2000 };
2001
2002 static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, BOOL vbInterface)
2003 {
2004     static const WCHAR w3xmlns[] = { 'h','t','t','p',':','/','/', 'w','w','w','.','w','3','.',
2005         'o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0 };
2006
2007     saxlocator *locator;
2008
2009     locator = heap_alloc( sizeof (*locator) );
2010     if( !locator )
2011         return E_OUTOFMEMORY;
2012
2013     locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl;
2014     locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl;
2015     locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl;
2016     locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl;
2017     locator->ref = 1;
2018     locator->vbInterface = vbInterface;
2019
2020     locator->saxreader = reader;
2021     ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface);
2022
2023     locator->pParserCtxt = NULL;
2024     locator->publicId = NULL;
2025     locator->systemId = NULL;
2026     locator->line = reader->version < MSXML4 ? 0 : 1;
2027     locator->column = 0;
2028     locator->ret = S_OK;
2029     if (locator->saxreader->version >= MSXML6)
2030         locator->namespaceUri = SysAllocString(w3xmlns);
2031     else
2032         locator->namespaceUri = SysAllocStringLen(NULL, 0);
2033     if(!locator->namespaceUri)
2034     {
2035         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2036         heap_free(locator);
2037         return E_OUTOFMEMORY;
2038     }
2039
2040     locator->attributesSize = 8;
2041     locator->nb_attributes = 0;
2042     locator->attributes = heap_alloc(sizeof(struct _attributes)*locator->attributesSize);
2043     if(!locator->attributes)
2044     {
2045         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2046         SysFreeString(locator->namespaceUri);
2047         heap_free(locator);
2048         return E_OUTOFMEMORY;
2049     }
2050
2051     list_init(&locator->elements);
2052
2053     *ppsaxlocator = locator;
2054
2055     TRACE("returning %p\n", *ppsaxlocator);
2056
2057     return S_OK;
2058 }
2059
2060 /*** SAXXMLReader internal functions ***/
2061 static HRESULT internal_parseBuffer(saxreader *This, const char *buffer, int size, BOOL vbInterface)
2062 {
2063     xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
2064     xmlChar *enc_name = NULL;
2065     saxlocator *locator;
2066     HRESULT hr;
2067
2068     hr = SAXLocator_create(This, &locator, vbInterface);
2069     if(FAILED(hr))
2070         return hr;
2071
2072     if (size >= 4)
2073     {
2074         const unsigned char *buff = (unsigned char*)buffer;
2075
2076         encoding = xmlDetectCharEncoding((xmlChar*)buffer, 4);
2077         enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
2078         TRACE("detected encoding: %s\n", enc_name);
2079         /* skip BOM, parser won't switch encodings and so won't skip it on its own */
2080         if ((encoding == XML_CHAR_ENCODING_UTF8) &&
2081             buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF)
2082         {
2083             buffer += 3;
2084             size -= 3;
2085         }
2086     }
2087
2088     locator->pParserCtxt = xmlCreateMemoryParserCtxt(buffer, size);
2089     if(!locator->pParserCtxt)
2090     {
2091         ISAXLocator_Release(&locator->ISAXLocator_iface);
2092         return E_FAIL;
2093     }
2094
2095     if (encoding == XML_CHAR_ENCODING_UTF8)
2096         locator->pParserCtxt->encoding = xmlStrdup(enc_name);
2097
2098     xmlFree(locator->pParserCtxt->sax);
2099     locator->pParserCtxt->sax = &locator->saxreader->sax;
2100     locator->pParserCtxt->userData = locator;
2101
2102     This->isParsing = TRUE;
2103     if(xmlParseDocument(locator->pParserCtxt)==-1 && locator->ret==S_OK)
2104         hr = E_FAIL;
2105     else
2106         hr = locator->ret;
2107     This->isParsing = FALSE;
2108
2109     if(locator->pParserCtxt)
2110     {
2111         locator->pParserCtxt->sax = NULL;
2112         xmlFreeParserCtxt(locator->pParserCtxt);
2113         locator->pParserCtxt = NULL;
2114     }
2115
2116     ISAXLocator_Release(&locator->ISAXLocator_iface);
2117     return hr;
2118 }
2119
2120 static HRESULT internal_parseStream(saxreader *This, IStream *stream, BOOL vbInterface)
2121 {
2122     saxlocator *locator;
2123     HRESULT hr;
2124     ULONG dataRead;
2125     char data[1024];
2126     int ret;
2127
2128     dataRead = 0;
2129     hr = IStream_Read(stream, data, sizeof(data), &dataRead);
2130     if(FAILED(hr)) return hr;
2131
2132     hr = SAXLocator_create(This, &locator, vbInterface);
2133     if(FAILED(hr)) return hr;
2134
2135     locator->pParserCtxt = xmlCreatePushParserCtxt(
2136             &locator->saxreader->sax, locator,
2137             data, dataRead, NULL);
2138     if(!locator->pParserCtxt)
2139     {
2140         ISAXLocator_Release(&locator->ISAXLocator_iface);
2141         return E_FAIL;
2142     }
2143
2144     This->isParsing = TRUE;
2145
2146     if(dataRead != sizeof(data))
2147     {
2148         ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2149         hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2150     }
2151     else
2152     {
2153         while(1)
2154         {
2155             dataRead = 0;
2156             hr = IStream_Read(stream, data, sizeof(data), &dataRead);
2157             if (FAILED(hr)) break;
2158
2159             ret = xmlParseChunk(locator->pParserCtxt, data, dataRead, 0);
2160             hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2161
2162             if (hr != S_OK) break;
2163
2164             if (dataRead != sizeof(data))
2165             {
2166                 ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2167                 hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2168                 break;
2169             }
2170         }
2171     }
2172
2173     This->isParsing = FALSE;
2174
2175     xmlFreeParserCtxt(locator->pParserCtxt);
2176     locator->pParserCtxt = NULL;
2177     ISAXLocator_Release(&locator->ISAXLocator_iface);
2178     return hr;
2179 }
2180
2181 static HRESULT internal_getEntityResolver(
2182         saxreader *This,
2183         void *pEntityResolver,
2184         BOOL vbInterface)
2185 {
2186     FIXME("(%p)->(%p) stub\n", This, pEntityResolver);
2187     return E_NOTIMPL;
2188 }
2189
2190 static HRESULT internal_putEntityResolver(
2191         saxreader *This,
2192         void *pEntityResolver,
2193         BOOL vbInterface)
2194 {
2195     FIXME("(%p)->(%p) stub\n", This, pEntityResolver);
2196     return E_NOTIMPL;
2197 }
2198
2199 static HRESULT internal_getContentHandler(
2200         saxreader* This,
2201         void *pContentHandler,
2202         BOOL vbInterface)
2203 {
2204     TRACE("(%p)->(%p)\n", This, pContentHandler);
2205     if(pContentHandler == NULL)
2206         return E_POINTER;
2207     if((vbInterface && This->vbcontentHandler)
2208             || (!vbInterface && This->contentHandler))
2209     {
2210         if(vbInterface)
2211             IVBSAXContentHandler_AddRef(This->vbcontentHandler);
2212         else
2213             ISAXContentHandler_AddRef(This->contentHandler);
2214     }
2215     if(vbInterface) *(IVBSAXContentHandler**)pContentHandler =
2216         This->vbcontentHandler;
2217     else *(ISAXContentHandler**)pContentHandler = This->contentHandler;
2218
2219     return S_OK;
2220 }
2221
2222 static HRESULT internal_putContentHandler(
2223         saxreader* This,
2224         void *contentHandler,
2225         BOOL vbInterface)
2226 {
2227     TRACE("(%p)->(%p)\n", This, contentHandler);
2228     if(contentHandler)
2229     {
2230         if(vbInterface)
2231             IVBSAXContentHandler_AddRef((IVBSAXContentHandler*)contentHandler);
2232         else
2233             ISAXContentHandler_AddRef((ISAXContentHandler*)contentHandler);
2234     }
2235     if((vbInterface && This->vbcontentHandler)
2236             || (!vbInterface && This->contentHandler))
2237     {
2238         if(vbInterface)
2239             IVBSAXContentHandler_Release(This->vbcontentHandler);
2240         else
2241             ISAXContentHandler_Release(This->contentHandler);
2242     }
2243     if(vbInterface)
2244         This->vbcontentHandler = contentHandler;
2245     else
2246         This->contentHandler = contentHandler;
2247
2248     return S_OK;
2249 }
2250
2251 static HRESULT internal_getDTDHandler(
2252         saxreader* This,
2253         void *pDTDHandler,
2254         BOOL vbInterface)
2255 {
2256     FIXME("(%p)->(%p) stub\n", This, pDTDHandler);
2257     return E_NOTIMPL;
2258 }
2259
2260 static HRESULT internal_putDTDHandler(
2261         saxreader* This,
2262         void *pDTDHandler,
2263         BOOL vbInterface)
2264 {
2265     FIXME("(%p)->(%p) stub\n", This, pDTDHandler);
2266     return E_NOTIMPL;
2267 }
2268
2269 static HRESULT internal_getErrorHandler(
2270         saxreader* This,
2271         void *pErrorHandler,
2272         BOOL vbInterface)
2273 {
2274     TRACE("(%p)->(%p)\n", This, pErrorHandler);
2275     if(pErrorHandler == NULL)
2276         return E_POINTER;
2277
2278     if(vbInterface && This->vberrorHandler)
2279         IVBSAXErrorHandler_AddRef(This->vberrorHandler);
2280     else if(!vbInterface && This->errorHandler)
2281         ISAXErrorHandler_AddRef(This->errorHandler);
2282
2283     if(vbInterface)
2284         *(IVBSAXErrorHandler**)pErrorHandler = This->vberrorHandler;
2285     else
2286         *(ISAXErrorHandler**)pErrorHandler = This->errorHandler;
2287
2288     return S_OK;
2289
2290 }
2291
2292 static HRESULT internal_putErrorHandler(
2293         saxreader* This,
2294         void *errorHandler,
2295         BOOL vbInterface)
2296 {
2297     TRACE("(%p)->(%p)\n", This, errorHandler);
2298     if(errorHandler)
2299     {
2300         if(vbInterface)
2301             IVBSAXErrorHandler_AddRef((IVBSAXErrorHandler*)errorHandler);
2302         else
2303             ISAXErrorHandler_AddRef((ISAXErrorHandler*)errorHandler);
2304     }
2305
2306     if(vbInterface && This->vberrorHandler)
2307         IVBSAXErrorHandler_Release(This->vberrorHandler);
2308     else if(!vbInterface && This->errorHandler)
2309         ISAXErrorHandler_Release(This->errorHandler);
2310
2311     if(vbInterface)
2312         This->vberrorHandler = errorHandler;
2313     else
2314         This->errorHandler = errorHandler;
2315
2316     return S_OK;
2317
2318 }
2319
2320 static HRESULT internal_parse(
2321         saxreader* This,
2322         VARIANT varInput,
2323         BOOL vbInterface)
2324 {
2325     HRESULT hr;
2326
2327     TRACE("(%p)->(%s)\n", This, debugstr_variant(&varInput));
2328
2329     /* Dispose of the BSTRs in the pool from a prior run, if any. */
2330     free_bstr_pool(&This->pool);
2331
2332     switch(V_VT(&varInput))
2333     {
2334         case VT_BSTR:
2335             hr = internal_parseBuffer(This, (const char*)V_BSTR(&varInput),
2336                     SysStringByteLen(V_BSTR(&varInput)), vbInterface);
2337             break;
2338         case VT_ARRAY|VT_UI1: {
2339             void *pSAData;
2340             LONG lBound, uBound;
2341             ULONG dataRead;
2342
2343             hr = SafeArrayGetLBound(V_ARRAY(&varInput), 1, &lBound);
2344             if(hr != S_OK) break;
2345             hr = SafeArrayGetUBound(V_ARRAY(&varInput), 1, &uBound);
2346             if(hr != S_OK) break;
2347             dataRead = (uBound-lBound)*SafeArrayGetElemsize(V_ARRAY(&varInput));
2348             hr = SafeArrayAccessData(V_ARRAY(&varInput), &pSAData);
2349             if(hr != S_OK) break;
2350             hr = internal_parseBuffer(This, pSAData, dataRead, vbInterface);
2351             SafeArrayUnaccessData(V_ARRAY(&varInput));
2352             break;
2353         }
2354         case VT_UNKNOWN:
2355         case VT_DISPATCH: {
2356             IPersistStream *persistStream;
2357             IStream *stream = NULL;
2358             IXMLDOMDocument *xmlDoc;
2359
2360             if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2361                         &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK)
2362             {
2363                 BSTR bstrData;
2364
2365                 IXMLDOMDocument_get_xml(xmlDoc, &bstrData);
2366                 hr = internal_parseBuffer(This, (const char*)bstrData,
2367                         SysStringByteLen(bstrData), vbInterface);
2368                 IXMLDOMDocument_Release(xmlDoc);
2369                 SysFreeString(bstrData);
2370                 break;
2371             }
2372
2373             if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2374                         &IID_IPersistStream, (void**)&persistStream) == S_OK)
2375             {
2376                 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2377                 if(hr != S_OK)
2378                 {
2379                     IPersistStream_Release(persistStream);
2380                     return hr;
2381                 }
2382
2383                 hr = IPersistStream_Save(persistStream, stream, TRUE);
2384                 IPersistStream_Release(persistStream);
2385                 if(hr != S_OK)
2386                 {
2387                     IStream_Release(stream);
2388                     stream = NULL;
2389                 }
2390             }
2391
2392             if(stream || IUnknown_QueryInterface(V_UNKNOWN(&varInput),
2393                         &IID_IStream, (void**)&stream) == S_OK)
2394             {
2395                 hr = internal_parseStream(This, stream, vbInterface);
2396                 IStream_Release(stream);
2397                 break;
2398             }
2399         }
2400         default:
2401             WARN("vt %d not implemented\n", V_VT(&varInput));
2402             hr = E_INVALIDARG;
2403     }
2404
2405     return hr;
2406 }
2407
2408 static HRESULT internal_vbonDataAvailable(void *obj, char *ptr, DWORD len)
2409 {
2410     saxreader *This = obj;
2411
2412     return internal_parseBuffer(This, ptr, len, TRUE);
2413 }
2414
2415 static HRESULT internal_onDataAvailable(void *obj, char *ptr, DWORD len)
2416 {
2417     saxreader *This = obj;
2418
2419     return internal_parseBuffer(This, ptr, len, FALSE);
2420 }
2421
2422 static HRESULT internal_parseURL(
2423         saxreader* This,
2424         const WCHAR *url,
2425         BOOL vbInterface)
2426 {
2427     IMoniker *mon;
2428     bsc_t *bsc;
2429     HRESULT hr;
2430
2431     TRACE("(%p)->(%s)\n", This, debugstr_w(url));
2432
2433     hr = create_moniker_from_url(url, &mon);
2434     if(FAILED(hr))
2435         return hr;
2436
2437     if(vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, This, &bsc);
2438     else hr = bind_url(mon, internal_onDataAvailable, This, &bsc);
2439     IMoniker_Release(mon);
2440
2441     if(FAILED(hr))
2442         return hr;
2443
2444     return detach_bsc(bsc);
2445 }
2446
2447 static HRESULT internal_putProperty(
2448     saxreader* This,
2449     const WCHAR *prop,
2450     VARIANT value,
2451     BOOL vbInterface)
2452 {
2453     TRACE("(%p)->(%s %s)\n", This, debugstr_w(prop), debugstr_variant(&value));
2454
2455     if(!memcmp(prop, PropertyDeclHandlerW, sizeof(PropertyDeclHandlerW)))
2456     {
2457         if(This->isParsing) return E_FAIL;
2458
2459         switch (V_VT(&value))
2460         {
2461         case VT_EMPTY:
2462             if (vbInterface)
2463             {
2464                 if (This->vbdeclHandler)
2465                 {
2466                     IVBSAXDeclHandler_Release(This->vbdeclHandler);
2467                     This->vbdeclHandler = NULL;
2468                 }
2469             }
2470             else
2471                 if (This->declHandler)
2472                 {
2473                     ISAXDeclHandler_Release(This->declHandler);
2474                     This->declHandler = NULL;
2475                 }
2476             break;
2477         case VT_UNKNOWN:
2478             if (V_UNKNOWN(&value)) IUnknown_AddRef(V_UNKNOWN(&value));
2479
2480             if ((vbInterface && This->vbdeclHandler) ||
2481                (!vbInterface && This->declHandler))
2482             {
2483                 if (vbInterface)
2484                     IVBSAXDeclHandler_Release(This->vbdeclHandler);
2485                 else
2486                     ISAXDeclHandler_Release(This->declHandler);
2487             }
2488
2489             if (vbInterface)
2490                 This->vbdeclHandler = (IVBSAXDeclHandler*)V_UNKNOWN(&value);
2491             else
2492                 This->declHandler = (ISAXDeclHandler*)V_UNKNOWN(&value);
2493             break;
2494         default:
2495             return E_INVALIDARG;
2496         }
2497
2498         return S_OK;
2499     }
2500
2501     if(!memcmp(prop, PropertyLexicalHandlerW, sizeof(PropertyLexicalHandlerW)))
2502     {
2503         if(This->isParsing) return E_FAIL;
2504
2505         switch (V_VT(&value))
2506         {
2507         case VT_EMPTY:
2508             if (vbInterface)
2509             {
2510                 if (This->vblexicalHandler)
2511                 {
2512                     IVBSAXLexicalHandler_Release(This->vblexicalHandler);
2513                     This->vblexicalHandler = NULL;
2514                 }
2515             }
2516             else
2517                 if (This->lexicalHandler)
2518                 {
2519                     ISAXLexicalHandler_Release(This->lexicalHandler);
2520                     This->lexicalHandler = NULL;
2521                 }
2522             break;
2523         case VT_UNKNOWN:
2524             if (V_UNKNOWN(&value)) IUnknown_AddRef(V_UNKNOWN(&value));
2525
2526             if ((vbInterface && This->vblexicalHandler) ||
2527                (!vbInterface && This->lexicalHandler))
2528             {
2529                 if (vbInterface)
2530                     IVBSAXLexicalHandler_Release(This->vblexicalHandler);
2531                 else
2532                     ISAXLexicalHandler_Release(This->lexicalHandler);
2533             }
2534
2535             if (vbInterface)
2536                 This->vblexicalHandler = (IVBSAXLexicalHandler*)V_UNKNOWN(&value);
2537             else
2538                 This->lexicalHandler = (ISAXLexicalHandler*)V_UNKNOWN(&value);
2539             break;
2540         default:
2541             return E_INVALIDARG;
2542         }
2543
2544         return S_OK;
2545     }
2546
2547     if(!memcmp(prop, PropertyMaxXMLSizeW, sizeof(PropertyMaxXMLSizeW)))
2548     {
2549         if (V_VT(&value) == VT_I4 && V_I4(&value) == 0) return S_OK;
2550         FIXME("(%p)->(%s): max-xml-size unsupported\n", This, debugstr_variant(&value));
2551         return E_NOTIMPL;
2552     }
2553
2554     if(!memcmp(prop, PropertyMaxElementDepthW, sizeof(PropertyMaxElementDepthW)))
2555     {
2556         if (V_VT(&value) == VT_I4 && V_I4(&value) == 0) return S_OK;
2557         FIXME("(%p)->(%s): max-element-depth unsupported\n", This, debugstr_variant(&value));
2558         return E_NOTIMPL;
2559     }
2560
2561     FIXME("(%p)->(%s:%s): unsupported property\n", This, debugstr_w(prop), debugstr_variant(&value));
2562
2563     if(!memcmp(prop, PropertyCharsetW, sizeof(PropertyCharsetW)))
2564         return E_NOTIMPL;
2565
2566     if(!memcmp(prop, PropertyDomNodeW, sizeof(PropertyDomNodeW)))
2567         return E_FAIL;
2568
2569     if(!memcmp(prop, PropertyInputSourceW, sizeof(PropertyInputSourceW)))
2570         return E_NOTIMPL;
2571
2572     if(!memcmp(prop, PropertySchemaDeclHandlerW, sizeof(PropertySchemaDeclHandlerW)))
2573         return E_NOTIMPL;
2574
2575     if(!memcmp(prop, PropertyXMLDeclEncodingW, sizeof(PropertyXMLDeclEncodingW)))
2576         return E_FAIL;
2577
2578     if(!memcmp(prop, PropertyXMLDeclStandaloneW, sizeof(PropertyXMLDeclStandaloneW)))
2579         return E_FAIL;
2580
2581     if(!memcmp(prop, PropertyXMLDeclVersionW, sizeof(PropertyXMLDeclVersionW)))
2582         return E_FAIL;
2583
2584     return E_INVALIDARG;
2585 }
2586
2587 static HRESULT internal_getProperty(const saxreader* This, const WCHAR *prop, VARIANT *value, BOOL vb)
2588 {
2589     TRACE("(%p)->(%s)\n", This, debugstr_w(prop));
2590
2591     if (!value) return E_POINTER;
2592
2593     if (!memcmp(PropertyLexicalHandlerW, prop, sizeof(PropertyLexicalHandlerW)))
2594     {
2595         V_VT(value) = VT_UNKNOWN;
2596         V_UNKNOWN(value) = vb ? (IUnknown*)This->vblexicalHandler : (IUnknown*)This->lexicalHandler;
2597         if (V_UNKNOWN(value)) IUnknown_AddRef(V_UNKNOWN(value));
2598         return S_OK;
2599     }
2600
2601     if (!memcmp(PropertyDeclHandlerW, prop, sizeof(PropertyDeclHandlerW)))
2602     {
2603         V_VT(value) = VT_UNKNOWN;
2604         V_UNKNOWN(value) = vb ? (IUnknown*)This->vbdeclHandler : (IUnknown*)This->declHandler;
2605         if (V_UNKNOWN(value)) IUnknown_AddRef(V_UNKNOWN(value));
2606         return S_OK;
2607     }
2608
2609     FIXME("(%p)->(%s) unsupported property\n", This, debugstr_w(prop));
2610
2611     return E_NOTIMPL;
2612 }
2613
2614 /*** IVBSAXXMLReader interface ***/
2615 /*** IUnknown methods ***/
2616 static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID riid, void **ppvObject)
2617 {
2618     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2619
2620     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2621
2622     *ppvObject = NULL;
2623
2624     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2625          IsEqualGUID( riid, &IID_IDispatch ) ||
2626          IsEqualGUID( riid, &IID_IVBSAXXMLReader ))
2627     {
2628         *ppvObject = iface;
2629     }
2630     else if( IsEqualGUID( riid, &IID_ISAXXMLReader ))
2631     {
2632         *ppvObject = &This->ISAXXMLReader_iface;
2633     }
2634     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
2635     {
2636         return *ppvObject ? S_OK : E_NOINTERFACE;
2637     }
2638     else
2639     {
2640         FIXME("interface %s not implemented\n", debugstr_guid(riid));
2641         return E_NOINTERFACE;
2642     }
2643
2644     IVBSAXXMLReader_AddRef( iface );
2645
2646     return S_OK;
2647 }
2648
2649 static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader* iface)
2650 {
2651     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2652     TRACE("%p\n", This );
2653     return InterlockedIncrement( &This->ref );
2654 }
2655
2656 static ULONG WINAPI saxxmlreader_Release(
2657     IVBSAXXMLReader* iface)
2658 {
2659     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2660     LONG ref;
2661
2662     TRACE("%p\n", This );
2663
2664     ref = InterlockedDecrement( &This->ref );
2665     if ( ref == 0 )
2666     {
2667         if(This->contentHandler)
2668             ISAXContentHandler_Release(This->contentHandler);
2669
2670         if(This->vbcontentHandler)
2671             IVBSAXContentHandler_Release(This->vbcontentHandler);
2672
2673         if(This->errorHandler)
2674             ISAXErrorHandler_Release(This->errorHandler);
2675
2676         if(This->vberrorHandler)
2677             IVBSAXErrorHandler_Release(This->vberrorHandler);
2678
2679         if(This->lexicalHandler)
2680             ISAXLexicalHandler_Release(This->lexicalHandler);
2681
2682         if(This->vblexicalHandler)
2683             IVBSAXLexicalHandler_Release(This->vblexicalHandler);
2684
2685         if(This->declHandler)
2686             ISAXDeclHandler_Release(This->declHandler);
2687
2688         if(This->vbdeclHandler)
2689             IVBSAXDeclHandler_Release(This->vbdeclHandler);
2690
2691         free_bstr_pool(&This->pool);
2692
2693         release_dispex(&This->dispex);
2694         heap_free( This );
2695     }
2696
2697     return ref;
2698 }
2699 /*** IDispatch ***/
2700 static HRESULT WINAPI saxxmlreader_GetTypeInfoCount( IVBSAXXMLReader *iface, UINT* pctinfo )
2701 {
2702     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2703     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2704 }
2705
2706 static HRESULT WINAPI saxxmlreader_GetTypeInfo(
2707     IVBSAXXMLReader *iface,
2708     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2709 {
2710     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2711     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
2712         iTInfo, lcid, ppTInfo);
2713 }
2714
2715 static HRESULT WINAPI saxxmlreader_GetIDsOfNames(
2716     IVBSAXXMLReader *iface,
2717     REFIID riid,
2718     LPOLESTR* rgszNames,
2719     UINT cNames,
2720     LCID lcid,
2721     DISPID* rgDispId)
2722 {
2723     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2724     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
2725         riid, rgszNames, cNames, lcid, rgDispId);
2726 }
2727
2728 static HRESULT WINAPI saxxmlreader_Invoke(
2729     IVBSAXXMLReader *iface,
2730     DISPID dispIdMember,
2731     REFIID riid,
2732     LCID lcid,
2733     WORD wFlags,
2734     DISPPARAMS* pDispParams,
2735     VARIANT* pVarResult,
2736     EXCEPINFO* pExcepInfo,
2737     UINT* puArgErr)
2738 {
2739     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2740     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
2741         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2742 }
2743
2744 /*** IVBSAXXMLReader methods ***/
2745 static HRESULT WINAPI saxxmlreader_getFeature(
2746     IVBSAXXMLReader* iface,
2747     const WCHAR *feature,
2748     VARIANT_BOOL *value)
2749 {
2750     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2751
2752     if (!strcmpW(FeatureNamespacesW, feature))
2753         return get_feature_value(This, Namespaces, value);
2754
2755     FIXME("(%p)->(%s %p) stub\n", This, debugstr_w(feature), value);
2756     return E_NOTIMPL;
2757 }
2758
2759 static HRESULT WINAPI saxxmlreader_putFeature(
2760     IVBSAXXMLReader* iface,
2761     const WCHAR *feature,
2762     VARIANT_BOOL value)
2763 {
2764     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2765
2766     TRACE("(%p)->(%s %x)\n", This, debugstr_w(feature), value);
2767
2768     if (!strcmpW(FeatureExternalGeneralEntitiesW, feature) && value == VARIANT_FALSE)
2769         return set_feature_value(This, ExternalGeneralEntities, value);
2770
2771     if (!strcmpW(FeatureExternalParameterEntitiesW, feature) && value == VARIANT_FALSE)
2772         return set_feature_value(This, ExternalParameterEntities, value);
2773
2774     if (!strcmpW(FeatureLexicalHandlerParEntitiesW, feature))
2775     {
2776         FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature), value);
2777         return set_feature_value(This, LexicalHandlerParEntities, value);
2778     }
2779
2780     if (!strcmpW(FeatureProhibitDTDW, feature))
2781     {
2782         FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature), value);
2783         return set_feature_value(This, ProhibitDTD, value);
2784     }
2785
2786     if (!strcmpW(FeatureNamespacesW, feature) && value == VARIANT_TRUE)
2787         return set_feature_value(This, Namespaces, value);
2788
2789     FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature), value);
2790     return E_NOTIMPL;
2791 }
2792
2793 static HRESULT WINAPI saxxmlreader_getProperty(
2794     IVBSAXXMLReader* iface,
2795     const WCHAR *prop,
2796     VARIANT *value)
2797 {
2798     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2799     return internal_getProperty(This, prop, value, TRUE);
2800 }
2801
2802 static HRESULT WINAPI saxxmlreader_putProperty(
2803     IVBSAXXMLReader* iface,
2804     const WCHAR *pProp,
2805     VARIANT value)
2806 {
2807     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2808     return internal_putProperty(This, pProp, value, TRUE);
2809 }
2810
2811 static HRESULT WINAPI saxxmlreader_get_entityResolver(
2812     IVBSAXXMLReader* iface,
2813     IVBSAXEntityResolver **pEntityResolver)
2814 {
2815     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2816     return internal_getEntityResolver(This, pEntityResolver, TRUE);
2817 }
2818
2819 static HRESULT WINAPI saxxmlreader_put_entityResolver(
2820     IVBSAXXMLReader* iface,
2821     IVBSAXEntityResolver *pEntityResolver)
2822 {
2823     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2824     return internal_putEntityResolver(This, pEntityResolver, TRUE);
2825 }
2826
2827 static HRESULT WINAPI saxxmlreader_get_contentHandler(
2828     IVBSAXXMLReader* iface,
2829     IVBSAXContentHandler **ppContentHandler)
2830 {
2831     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2832     return internal_getContentHandler(This, ppContentHandler, TRUE);
2833 }
2834
2835 static HRESULT WINAPI saxxmlreader_put_contentHandler(
2836     IVBSAXXMLReader* iface,
2837     IVBSAXContentHandler *contentHandler)
2838 {
2839     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2840     return internal_putContentHandler(This, contentHandler, TRUE);
2841 }
2842
2843 static HRESULT WINAPI saxxmlreader_get_dtdHandler(
2844     IVBSAXXMLReader* iface,
2845     IVBSAXDTDHandler **pDTDHandler)
2846 {
2847     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2848     return internal_getDTDHandler(This, pDTDHandler, TRUE);
2849 }
2850
2851 static HRESULT WINAPI saxxmlreader_put_dtdHandler(
2852     IVBSAXXMLReader* iface,
2853     IVBSAXDTDHandler *pDTDHandler)
2854 {
2855     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2856     return internal_putDTDHandler(This, pDTDHandler, TRUE);
2857 }
2858
2859 static HRESULT WINAPI saxxmlreader_get_errorHandler(
2860     IVBSAXXMLReader* iface,
2861     IVBSAXErrorHandler **pErrorHandler)
2862 {
2863     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2864     return internal_getErrorHandler(This, pErrorHandler, TRUE);
2865 }
2866
2867 static HRESULT WINAPI saxxmlreader_put_errorHandler(
2868     IVBSAXXMLReader* iface,
2869     IVBSAXErrorHandler *errorHandler)
2870 {
2871     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2872     return internal_putErrorHandler(This, errorHandler, TRUE);
2873 }
2874
2875 static HRESULT WINAPI saxxmlreader_get_baseURL(
2876     IVBSAXXMLReader* iface,
2877     const WCHAR **pBaseUrl)
2878 {
2879     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2880
2881     FIXME("(%p)->(%p) stub\n", This, pBaseUrl);
2882     return E_NOTIMPL;
2883 }
2884
2885 static HRESULT WINAPI saxxmlreader_put_baseURL(
2886     IVBSAXXMLReader* iface,
2887     const WCHAR *pBaseUrl)
2888 {
2889     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2890
2891     FIXME("(%p)->(%s) stub\n", This, debugstr_w(pBaseUrl));
2892     return E_NOTIMPL;
2893 }
2894
2895 static HRESULT WINAPI saxxmlreader_get_secureBaseURL(
2896     IVBSAXXMLReader* iface,
2897     const WCHAR **pSecureBaseUrl)
2898 {
2899     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2900
2901     FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
2902     return E_NOTIMPL;
2903 }
2904
2905
2906 static HRESULT WINAPI saxxmlreader_put_secureBaseURL(
2907     IVBSAXXMLReader* iface,
2908     const WCHAR *secureBaseUrl)
2909 {
2910     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2911
2912     FIXME("(%p)->(%s) stub\n", This, debugstr_w(secureBaseUrl));
2913     return E_NOTIMPL;
2914 }
2915
2916 static HRESULT WINAPI saxxmlreader_parse(
2917     IVBSAXXMLReader* iface,
2918     VARIANT varInput)
2919 {
2920     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2921     return internal_parse(This, varInput, TRUE);
2922 }
2923
2924 static HRESULT WINAPI saxxmlreader_parseURL(
2925     IVBSAXXMLReader* iface,
2926     const WCHAR *url)
2927 {
2928     saxreader *This = impl_from_IVBSAXXMLReader( iface );
2929     return internal_parseURL(This, url, TRUE);
2930 }
2931
2932 static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl =
2933 {
2934     saxxmlreader_QueryInterface,
2935     saxxmlreader_AddRef,
2936     saxxmlreader_Release,
2937     saxxmlreader_GetTypeInfoCount,
2938     saxxmlreader_GetTypeInfo,
2939     saxxmlreader_GetIDsOfNames,
2940     saxxmlreader_Invoke,
2941     saxxmlreader_getFeature,
2942     saxxmlreader_putFeature,
2943     saxxmlreader_getProperty,
2944     saxxmlreader_putProperty,
2945     saxxmlreader_get_entityResolver,
2946     saxxmlreader_put_entityResolver,
2947     saxxmlreader_get_contentHandler,
2948     saxxmlreader_put_contentHandler,
2949     saxxmlreader_get_dtdHandler,
2950     saxxmlreader_put_dtdHandler,
2951     saxxmlreader_get_errorHandler,
2952     saxxmlreader_put_errorHandler,
2953     saxxmlreader_get_baseURL,
2954     saxxmlreader_put_baseURL,
2955     saxxmlreader_get_secureBaseURL,
2956     saxxmlreader_put_secureBaseURL,
2957     saxxmlreader_parse,
2958     saxxmlreader_parseURL
2959 };
2960
2961 /*** ISAXXMLReader interface ***/
2962 /*** IUnknown methods ***/
2963 static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader* iface, REFIID riid, void **ppvObject)
2964 {
2965     saxreader *This = impl_from_ISAXXMLReader( iface );
2966     return saxxmlreader_QueryInterface(&This->IVBSAXXMLReader_iface, riid, ppvObject);
2967 }
2968
2969 static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader* iface)
2970 {
2971     saxreader *This = impl_from_ISAXXMLReader( iface );
2972     return saxxmlreader_AddRef(&This->IVBSAXXMLReader_iface);
2973 }
2974
2975 static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader* iface)
2976 {
2977     saxreader *This = impl_from_ISAXXMLReader( iface );
2978     return saxxmlreader_Release(&This->IVBSAXXMLReader_iface);
2979 }
2980
2981 /*** ISAXXMLReader methods ***/
2982 static HRESULT WINAPI isaxxmlreader_getFeature(
2983         ISAXXMLReader* iface,
2984         const WCHAR *pFeature,
2985         VARIANT_BOOL *pValue)
2986 {
2987     saxreader *This = impl_from_ISAXXMLReader( iface );
2988     return IVBSAXXMLReader_getFeature(&This->IVBSAXXMLReader_iface, pFeature, pValue);
2989 }
2990
2991 static HRESULT WINAPI isaxxmlreader_putFeature(
2992         ISAXXMLReader* iface,
2993         const WCHAR *pFeature,
2994         VARIANT_BOOL vfValue)
2995 {
2996     saxreader *This = impl_from_ISAXXMLReader( iface );
2997     return IVBSAXXMLReader_putFeature(&This->IVBSAXXMLReader_iface, pFeature, vfValue);
2998 }
2999
3000 static HRESULT WINAPI isaxxmlreader_getProperty(
3001         ISAXXMLReader* iface,
3002         const WCHAR *prop,
3003         VARIANT *value)
3004 {
3005     saxreader *This = impl_from_ISAXXMLReader( iface );
3006     return internal_getProperty(This, prop, value, FALSE);
3007 }
3008
3009 static HRESULT WINAPI isaxxmlreader_putProperty(
3010         ISAXXMLReader* iface,
3011         const WCHAR *pProp,
3012         VARIANT value)
3013 {
3014     saxreader *This = impl_from_ISAXXMLReader( iface );
3015     return internal_putProperty(This, pProp, value, FALSE);
3016 }
3017
3018 static HRESULT WINAPI isaxxmlreader_getEntityResolver(
3019         ISAXXMLReader* iface,
3020         ISAXEntityResolver **ppEntityResolver)
3021 {
3022     saxreader *This = impl_from_ISAXXMLReader( iface );
3023     return internal_getEntityResolver(This, ppEntityResolver, FALSE);
3024 }
3025
3026 static HRESULT WINAPI isaxxmlreader_putEntityResolver(
3027         ISAXXMLReader* iface,
3028         ISAXEntityResolver *pEntityResolver)
3029 {
3030     saxreader *This = impl_from_ISAXXMLReader( iface );
3031     return internal_putEntityResolver(This, pEntityResolver, FALSE);
3032 }
3033
3034 static HRESULT WINAPI isaxxmlreader_getContentHandler(
3035         ISAXXMLReader* iface,
3036         ISAXContentHandler **pContentHandler)
3037 {
3038     saxreader *This = impl_from_ISAXXMLReader( iface );
3039     return internal_getContentHandler(This, pContentHandler, FALSE);
3040 }
3041
3042 static HRESULT WINAPI isaxxmlreader_putContentHandler(
3043         ISAXXMLReader* iface,
3044         ISAXContentHandler *contentHandler)
3045 {
3046     saxreader *This = impl_from_ISAXXMLReader( iface );
3047     return internal_putContentHandler(This, contentHandler, FALSE);
3048 }
3049
3050 static HRESULT WINAPI isaxxmlreader_getDTDHandler(
3051         ISAXXMLReader* iface,
3052         ISAXDTDHandler **pDTDHandler)
3053 {
3054     saxreader *This = impl_from_ISAXXMLReader( iface );
3055     return internal_getDTDHandler(This, pDTDHandler, FALSE);
3056 }
3057
3058 static HRESULT WINAPI isaxxmlreader_putDTDHandler(
3059         ISAXXMLReader* iface,
3060         ISAXDTDHandler *pDTDHandler)
3061 {
3062     saxreader *This = impl_from_ISAXXMLReader( iface );
3063     return internal_putDTDHandler(This, pDTDHandler, FALSE);
3064 }
3065
3066 static HRESULT WINAPI isaxxmlreader_getErrorHandler(
3067         ISAXXMLReader* iface,
3068         ISAXErrorHandler **pErrorHandler)
3069 {
3070     saxreader *This = impl_from_ISAXXMLReader( iface );
3071     return internal_getErrorHandler(This, pErrorHandler, FALSE);
3072 }
3073
3074 static HRESULT WINAPI isaxxmlreader_putErrorHandler(
3075         ISAXXMLReader* iface,
3076         ISAXErrorHandler *errorHandler)
3077 {
3078     saxreader *This = impl_from_ISAXXMLReader( iface );
3079     return internal_putErrorHandler(This, errorHandler, FALSE);
3080 }
3081
3082 static HRESULT WINAPI isaxxmlreader_getBaseURL(
3083         ISAXXMLReader* iface,
3084         const WCHAR **pBaseUrl)
3085 {
3086     saxreader *This = impl_from_ISAXXMLReader( iface );
3087     return IVBSAXXMLReader_get_baseURL(&This->IVBSAXXMLReader_iface, pBaseUrl);
3088 }
3089
3090 static HRESULT WINAPI isaxxmlreader_putBaseURL(
3091         ISAXXMLReader* iface,
3092         const WCHAR *pBaseUrl)
3093 {
3094     saxreader *This = impl_from_ISAXXMLReader( iface );
3095     return IVBSAXXMLReader_put_baseURL(&This->IVBSAXXMLReader_iface, pBaseUrl);
3096 }
3097
3098 static HRESULT WINAPI isaxxmlreader_getSecureBaseURL(
3099         ISAXXMLReader* iface,
3100         const WCHAR **pSecureBaseUrl)
3101 {
3102     saxreader *This = impl_from_ISAXXMLReader( iface );
3103     return IVBSAXXMLReader_get_secureBaseURL(&This->IVBSAXXMLReader_iface, pSecureBaseUrl);
3104 }
3105
3106 static HRESULT WINAPI isaxxmlreader_putSecureBaseURL(
3107         ISAXXMLReader* iface,
3108         const WCHAR *secureBaseUrl)
3109 {
3110     saxreader *This = impl_from_ISAXXMLReader( iface );
3111     return IVBSAXXMLReader_put_secureBaseURL(&This->IVBSAXXMLReader_iface, secureBaseUrl);
3112 }
3113
3114 static HRESULT WINAPI isaxxmlreader_parse(
3115         ISAXXMLReader* iface,
3116         VARIANT varInput)
3117 {
3118     saxreader *This = impl_from_ISAXXMLReader( iface );
3119     return internal_parse(This, varInput, FALSE);
3120 }
3121
3122 static HRESULT WINAPI isaxxmlreader_parseURL(
3123         ISAXXMLReader* iface,
3124         const WCHAR *url)
3125 {
3126     saxreader *This = impl_from_ISAXXMLReader( iface );
3127     return internal_parseURL(This, url, FALSE);
3128 }
3129
3130 static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl =
3131 {
3132     isaxxmlreader_QueryInterface,
3133     isaxxmlreader_AddRef,
3134     isaxxmlreader_Release,
3135     isaxxmlreader_getFeature,
3136     isaxxmlreader_putFeature,
3137     isaxxmlreader_getProperty,
3138     isaxxmlreader_putProperty,
3139     isaxxmlreader_getEntityResolver,
3140     isaxxmlreader_putEntityResolver,
3141     isaxxmlreader_getContentHandler,
3142     isaxxmlreader_putContentHandler,
3143     isaxxmlreader_getDTDHandler,
3144     isaxxmlreader_putDTDHandler,
3145     isaxxmlreader_getErrorHandler,
3146     isaxxmlreader_putErrorHandler,
3147     isaxxmlreader_getBaseURL,
3148     isaxxmlreader_putBaseURL,
3149     isaxxmlreader_getSecureBaseURL,
3150     isaxxmlreader_putSecureBaseURL,
3151     isaxxmlreader_parse,
3152     isaxxmlreader_parseURL
3153 };
3154
3155 static const tid_t saxreader_iface_tids[] = {
3156     IVBSAXXMLReader_tid,
3157     0
3158 };
3159 static dispex_static_data_t saxreader_dispex = {
3160     NULL,
3161     IVBSAXXMLReader_tid,
3162     NULL,
3163     saxreader_iface_tids
3164 };
3165
3166 HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *outer, LPVOID *ppObj)
3167 {
3168     saxreader *reader;
3169
3170     TRACE("(%p, %p)\n", outer, ppObj);
3171
3172     reader = heap_alloc( sizeof (*reader) );
3173     if( !reader )
3174         return E_OUTOFMEMORY;
3175
3176     reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl;
3177     reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl;
3178     reader->ref = 1;
3179     reader->contentHandler = NULL;
3180     reader->vbcontentHandler = NULL;
3181     reader->errorHandler = NULL;
3182     reader->vberrorHandler = NULL;
3183     reader->lexicalHandler = NULL;
3184     reader->vblexicalHandler = NULL;
3185     reader->declHandler = NULL;
3186     reader->vbdeclHandler = NULL;
3187     reader->isParsing = FALSE;
3188     reader->pool.pool = NULL;
3189     reader->pool.index = 0;
3190     reader->pool.len = 0;
3191     reader->features = Namespaces;
3192     reader->version = version;
3193
3194     init_dispex(&reader->dispex, (IUnknown*)&reader->IVBSAXXMLReader_iface, &saxreader_dispex);
3195
3196     memset(&reader->sax, 0, sizeof(xmlSAXHandler));
3197     reader->sax.initialized = XML_SAX2_MAGIC;
3198     reader->sax.startDocument = libxmlStartDocument;
3199     reader->sax.endDocument = libxmlEndDocument;
3200     reader->sax.startElementNs = libxmlStartElementNS;
3201     reader->sax.endElementNs = libxmlEndElementNS;
3202     reader->sax.characters = libxmlCharacters;
3203     reader->sax.setDocumentLocator = libxmlSetDocumentLocator;
3204     reader->sax.comment = libxmlComment;
3205     reader->sax.error = libxmlFatalError;
3206     reader->sax.fatalError = libxmlFatalError;
3207     reader->sax.cdataBlock = libxmlCDataBlock;
3208
3209     *ppObj = &reader->IVBSAXXMLReader_iface;
3210
3211     TRACE("returning iface %p\n", *ppObj);
3212
3213     return S_OK;
3214 }
3215
3216 #else
3217
3218 HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *pUnkOuter, LPVOID *ppObj)
3219 {
3220     MESSAGE("This program tried to use a SAX XML Reader object, but\n"
3221             "libxml2 support was not present at compile time.\n");
3222     return E_NOTIMPL;
3223 }
3224
3225 #endif