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