msvcp100: Added _Container_base0::operator= implementation.
[wine] / dlls / xmllite / reader.c
1 /*
2  * IXmlReader implementation
3  *
4  * Copyright 2010, 2012 Nikolay Sivov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "initguid.h"
27 #include "objbase.h"
28 #include "xmllite.h"
29 #include "xmllite_private.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
35
36 /* not defined in public headers */
37 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
38
39 typedef enum
40 {
41     XmlEncoding_UTF16,
42     XmlEncoding_UTF8,
43     XmlEncoding_Unknown
44 } xml_encoding;
45
46 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
47 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
48
49 struct xml_encoding_data
50 {
51     const WCHAR *name;
52     xml_encoding enc;
53     UINT cp;
54 };
55
56 static const struct xml_encoding_data xml_encoding_map[] = {
57     { utf16W, XmlEncoding_UTF16, ~0 },
58     { utf8W,  XmlEncoding_UTF8,  CP_UTF8 }
59 };
60
61 typedef struct
62 {
63     char *data;
64     char *cur;
65     unsigned int allocated;
66     unsigned int written;
67 } encoded_buffer;
68
69 typedef struct input_buffer input_buffer;
70
71 typedef struct _xmlreaderinput
72 {
73     IXmlReaderInput IXmlReaderInput_iface;
74     LONG ref;
75     /* reference passed on IXmlReaderInput creation, is kept when input is created */
76     IUnknown *input;
77     IMalloc *imalloc;
78     xml_encoding encoding;
79     BOOL hint;
80     WCHAR *baseuri;
81     /* stream reference set after SetInput() call from reader,
82        stored as sequential stream, cause currently
83        optimizations possible with IStream aren't implemented */
84     ISequentialStream *stream;
85     input_buffer *buffer;
86 } xmlreaderinput;
87
88 typedef struct _xmlreader
89 {
90     IXmlReader IXmlReader_iface;
91     LONG ref;
92     xmlreaderinput *input;
93     IMalloc *imalloc;
94     XmlReadState state;
95     XmlNodeType nodetype;
96     DtdProcessing dtdmode;
97     UINT line, pos;           /* reader position in XML stream */
98 } xmlreader;
99
100 struct input_buffer
101 {
102     encoded_buffer utf16;
103     encoded_buffer encoded;
104     UINT code_page;
105     xmlreaderinput *input;
106 };
107
108 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
109 {
110     return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
111 }
112
113 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
114 {
115     return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
116 }
117
118 static inline void *m_alloc(IMalloc *imalloc, size_t len)
119 {
120     if (imalloc)
121         return IMalloc_Alloc(imalloc, len);
122     else
123         return heap_alloc(len);
124 }
125
126 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
127 {
128     if (imalloc)
129         return IMalloc_Realloc(imalloc, mem, len);
130     else
131         return heap_realloc(mem, len);
132 }
133
134 static inline void m_free(IMalloc *imalloc, void *mem)
135 {
136     if (imalloc)
137         IMalloc_Free(imalloc, mem);
138     else
139         heap_free(mem);
140 }
141
142 /* reader memory allocation functions */
143 static inline void *reader_alloc(xmlreader *reader, size_t len)
144 {
145     return m_alloc(reader->imalloc, len);
146 }
147
148 static inline void reader_free(xmlreader *reader, void *mem)
149 {
150     m_free(reader->imalloc, mem);
151 }
152
153 /* reader input memory allocation functions */
154 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
155 {
156     return m_alloc(input->imalloc, len);
157 }
158
159 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
160 {
161     return m_realloc(input->imalloc, mem, len);
162 }
163
164 static inline void readerinput_free(xmlreaderinput *input, void *mem)
165 {
166     m_free(input->imalloc, mem);
167 }
168
169 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
170 {
171     LPWSTR ret = NULL;
172
173     if(str) {
174         DWORD size;
175
176         size = (strlenW(str)+1)*sizeof(WCHAR);
177         ret = readerinput_alloc(input, size);
178         if (ret) memcpy(ret, str, size);
179     }
180
181     return ret;
182 }
183
184 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
185 {
186     const int initial_len = 0x2000;
187     buffer->data = readerinput_alloc(input, initial_len);
188     if (!buffer->data) return E_OUTOFMEMORY;
189
190     memset(buffer->data, 0, 4);
191     buffer->cur = buffer->data;
192     buffer->allocated = initial_len;
193     buffer->written = 0;
194
195     return S_OK;
196 }
197
198 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
199 {
200     readerinput_free(input, buffer->data);
201 }
202
203 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
204 {
205     if (encoding == XmlEncoding_Unknown)
206     {
207         FIXME("unsupported encoding %d\n", encoding);
208         return E_NOTIMPL;
209     }
210
211     *cp = xml_encoding_map[encoding].cp;
212
213     return S_OK;
214 }
215
216 static xml_encoding parse_encoding_name(const WCHAR *name)
217 {
218     int min, max, n, c;
219
220     if (!name) return XmlEncoding_Unknown;
221
222     min = 0;
223     max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
224
225     while (min <= max)
226     {
227         n = (min+max)/2;
228
229         c = strcmpiW(xml_encoding_map[n].name, name);
230         if (!c)
231             return xml_encoding_map[n].enc;
232
233         if (c > 0)
234             max = n-1;
235         else
236             min = n+1;
237     }
238
239     return XmlEncoding_Unknown;
240 }
241
242 static HRESULT alloc_input_buffer(xmlreaderinput *input)
243 {
244     input_buffer *buffer;
245     HRESULT hr;
246
247     input->buffer = NULL;
248
249     buffer = readerinput_alloc(input, sizeof(*buffer));
250     if (!buffer) return E_OUTOFMEMORY;
251
252     buffer->input = input;
253     buffer->code_page = ~0; /* code page is unknown at this point */
254     hr = init_encoded_buffer(input, &buffer->utf16);
255     if (hr != S_OK) {
256         readerinput_free(input, buffer);
257         return hr;
258     }
259
260     hr = init_encoded_buffer(input, &buffer->encoded);
261     if (hr != S_OK) {
262         free_encoded_buffer(input, &buffer->utf16);
263         readerinput_free(input, buffer);
264         return hr;
265     }
266
267     input->buffer = buffer;
268     return S_OK;
269 }
270
271 static void free_input_buffer(input_buffer *buffer)
272 {
273     free_encoded_buffer(buffer->input, &buffer->encoded);
274     free_encoded_buffer(buffer->input, &buffer->utf16);
275     readerinput_free(buffer->input, buffer);
276 }
277
278 static void readerinput_release_stream(xmlreaderinput *readerinput)
279 {
280     if (readerinput->stream) {
281         ISequentialStream_Release(readerinput->stream);
282         readerinput->stream = NULL;
283     }
284 }
285
286 /* Queries already stored interface for IStream/ISequentialStream.
287    Interface supplied on creation will be overwritten */
288 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
289 {
290     HRESULT hr;
291
292     readerinput_release_stream(readerinput);
293     hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
294     if (hr != S_OK)
295         hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
296
297     return hr;
298 }
299
300 /* reads a chunk to raw buffer */
301 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
302 {
303     encoded_buffer *buffer = &readerinput->buffer->encoded;
304     ULONG len = buffer->allocated - buffer->written, read;
305     HRESULT hr;
306
307     /* always try to get aligned to 4 bytes, so the only case we can get partialy read characters is
308        variable width encodings like UTF-8 */
309     len = (len + 3) & ~3;
310     /* try to use allocated space or grow */
311     if (buffer->allocated - buffer->written < len)
312     {
313         buffer->allocated *= 2;
314         buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
315         len = buffer->allocated - buffer->written;
316     }
317
318     hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
319     if (FAILED(hr)) return hr;
320     TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
321     buffer->written += read;
322
323     return hr;
324 }
325
326 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
327 static void readerinput_grow(xmlreaderinput *readerinput, int length)
328 {
329     encoded_buffer *buffer = &readerinput->buffer->utf16;
330
331     /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
332     if (buffer->allocated < buffer->written + length + 4)
333     {
334         int grown_size = max(2*buffer->allocated, buffer->allocated + length);
335         buffer->data = readerinput_realloc(readerinput, buffer->data, grown_size);
336         buffer->allocated = grown_size;
337     }
338 }
339
340 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
341 {
342     encoded_buffer *buffer = &readerinput->buffer->encoded;
343     static char startA[] = {'<','?','x','m'};
344     static WCHAR startW[] = {'<','?'};
345     static char utf8bom[] = {0xef,0xbb,0xbf};
346     static char utf16lebom[] = {0xff,0xfe};
347
348     *enc = XmlEncoding_Unknown;
349
350     if (buffer->written <= 3) return MX_E_INPUTEND;
351
352     /* try start symbols if we have enough data to do that, input buffer should contain
353        first chunk already */
354     if (!memcmp(buffer->data, startA, sizeof(startA)))
355         *enc = XmlEncoding_UTF8;
356     else if (!memcmp(buffer->data, startW, sizeof(startW)))
357         *enc = XmlEncoding_UTF16;
358     /* try with BOM now */
359     else if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom)))
360     {
361         buffer->cur += sizeof(utf8bom);
362         *enc = XmlEncoding_UTF8;
363     }
364     else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
365     {
366         buffer->cur += sizeof(utf16lebom);
367         *enc = XmlEncoding_UTF16;
368     }
369
370     return S_OK;
371 }
372
373 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
374 {
375     encoded_buffer *buffer = &readerinput->buffer->encoded;
376     int len = buffer->written;
377
378     /* complete single byte char */
379     if (!(buffer->data[len-1] & 0x80)) return len;
380
381     /* find start byte of multibyte char */
382     while (--len && !(buffer->data[len] & 0xc0))
383         ;
384
385     return len;
386 }
387
388 /* returns byte length of complete char sequence for specified code page, */
389 static int readerinput_get_convlen(xmlreaderinput *readerinput, UINT cp)
390 {
391     encoded_buffer *buffer = &readerinput->buffer->encoded;
392     int len = buffer->written;
393
394     if (cp == CP_UTF8)
395         len = readerinput_get_utf8_convlen(readerinput);
396     else
397         len = buffer->written;
398
399     return len - (buffer->cur - buffer->data);
400 }
401
402 /* note that raw buffer content is kept */
403 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
404 {
405     encoded_buffer *src = &readerinput->buffer->encoded;
406     encoded_buffer *dest = &readerinput->buffer->utf16;
407     int len, dest_len;
408     HRESULT hr;
409     UINT cp;
410
411     hr = get_code_page(enc, &cp);
412     if (FAILED(hr)) return;
413
414     len = readerinput_get_convlen(readerinput, cp);
415
416     TRACE("switching to cp %d\n", cp);
417
418     /* just copy in this case */
419     if (enc == XmlEncoding_UTF16)
420     {
421         readerinput_grow(readerinput, len);
422         memcpy(dest->data, src->cur, len);
423         readerinput->buffer->code_page = cp;
424         return;
425     }
426
427     dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
428     readerinput_grow(readerinput, dest_len);
429     MultiByteToWideChar(cp, 0, src->cur, len, (WCHAR*)dest->data, dest_len);
430     dest->data[dest_len] = 0;
431     readerinput->buffer->code_page = cp;
432 }
433
434 static inline const WCHAR *reader_get_cur(xmlreader *reader)
435 {
436     return (WCHAR*)reader->input->buffer->utf16.cur;
437 }
438
439 static int reader_cmp(xmlreader *reader, const WCHAR *str)
440 {
441     const WCHAR *ptr = reader_get_cur(reader);
442     int i = 0;
443
444     return strncmpW(str, ptr, strlenW(str));
445
446     while (str[i]) {
447         if (ptr[i] != str[i]) return 0;
448         i++;
449     }
450
451     return 1;
452 }
453
454 /* moves cursor n WCHARs forward */
455 static void reader_skipn(xmlreader *reader, int n)
456 {
457     encoded_buffer *buffer = &reader->input->buffer->utf16;
458     const WCHAR *ptr = reader_get_cur(reader);
459
460     while (*ptr++ && n--)
461     {
462         buffer->cur += sizeof(WCHAR);
463         reader->pos++;
464     }
465 }
466
467 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
468 static int reader_skipspaces(xmlreader *reader)
469 {
470     encoded_buffer *buffer = &reader->input->buffer->utf16;
471     const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
472
473     while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n')
474     {
475         buffer->cur += sizeof(WCHAR);
476         if (*ptr == '\r')
477             reader->pos = 0;
478         else if (*ptr == '\n')
479         {
480             reader->line++;
481             reader->pos = 0;
482         }
483         else
484             reader->pos++;
485         ptr++;
486     }
487
488     return ptr - start;
489 }
490
491 /* [26] VersionNum ::= '1.' [0-9]+ */
492 static HRESULT reader_parse_versionnum(xmlreader *reader)
493 {
494     const WCHAR *ptr, *start = reader_get_cur(reader);
495     static const WCHAR onedotW[] = {'1','.',0};
496
497     if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
498     /* skip "1." */
499     reader_skipn(reader, 2);
500
501     ptr = reader_get_cur(reader);
502     while (*ptr >= '0' && *ptr <= '9')
503         ptr++;
504
505     if (ptr == start) return WC_E_DIGIT;
506     TRACE("version=%s\n", debugstr_wn(start, ptr-start));
507     reader_skipn(reader, ptr-start);
508     return S_OK;
509 }
510
511 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
512 static HRESULT reader_parse_versioninfo(xmlreader *reader)
513 {
514     static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
515     static const WCHAR dblquoteW[] = {'\"',0};
516     static const WCHAR quoteW[] = {'\'',0};
517     static const WCHAR eqW[] = {'=',0};
518     HRESULT hr;
519
520     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
521
522     if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
523     /* skip 'version' */
524     reader_skipn(reader, 7);
525
526     if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
527     /* skip '=' */
528     reader_skipn(reader, 1);
529
530     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
531         return WC_E_QUOTE;
532     /* skip "'"|'"' */
533     reader_skipn(reader, 1);
534
535     hr = reader_parse_versionnum(reader);
536     if (FAILED(hr)) return hr;
537
538     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
539         return WC_E_QUOTE;
540
541     /* skip "'"|'"' */
542     reader_skipn(reader, 1);
543
544     return S_OK;
545 }
546
547 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
548 static HRESULT reader_parse_xmldecl(xmlreader *reader)
549 {
550     static const WCHAR xmldeclW[] = {'<','?','x','m','l',0};
551     HRESULT hr;
552
553     /* check if we have "<?xml" */
554     if (reader_cmp(reader, xmldeclW)) return S_OK;
555
556     reader_skipn(reader, 5);
557     hr = reader_parse_versioninfo(reader);
558     if (FAILED(hr))
559         return hr;
560
561     return E_NOTIMPL;
562 }
563
564 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
565 {
566     xmlreader *This = impl_from_IXmlReader(iface);
567
568     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
569
570     if (IsEqualGUID(riid, &IID_IUnknown) ||
571         IsEqualGUID(riid, &IID_IXmlReader))
572     {
573         *ppvObject = iface;
574     }
575     else
576     {
577         FIXME("interface %s not implemented\n", debugstr_guid(riid));
578         return E_NOINTERFACE;
579     }
580
581     IXmlReader_AddRef(iface);
582
583     return S_OK;
584 }
585
586 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
587 {
588     xmlreader *This = impl_from_IXmlReader(iface);
589     ULONG ref = InterlockedIncrement(&This->ref);
590     TRACE("(%p)->(%d)\n", This, ref);
591     return ref;
592 }
593
594 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
595 {
596     xmlreader *This = impl_from_IXmlReader(iface);
597     LONG ref = InterlockedDecrement(&This->ref);
598
599     TRACE("(%p)->(%d)\n", This, ref);
600
601     if (ref == 0)
602     {
603         IMalloc *imalloc = This->imalloc;
604         if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
605         reader_free(This, This);
606         if (imalloc) IMalloc_Release(imalloc);
607     }
608
609     return ref;
610 }
611
612 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
613 {
614     xmlreader *This = impl_from_IXmlReader(iface);
615     HRESULT hr;
616
617     TRACE("(%p %p)\n", This, input);
618
619     if (This->input)
620     {
621         readerinput_release_stream(This->input);
622         IUnknown_Release(&This->input->IXmlReaderInput_iface);
623         This->input = NULL;
624     }
625
626     This->line = This->pos = 0;
627
628     /* just reset current input */
629     if (!input)
630     {
631         This->state = XmlReadState_Initial;
632         return S_OK;
633     }
634
635     /* now try IXmlReaderInput, ISequentialStream, IStream */
636     hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input);
637     if (hr != S_OK)
638     {
639         IXmlReaderInput *readerinput;
640
641         /* create IXmlReaderInput basing on supplied interface */
642         hr = CreateXmlReaderInputWithEncodingName(input,
643                                          NULL, NULL, FALSE, NULL, &readerinput);
644         if (hr != S_OK) return hr;
645         This->input = impl_from_IXmlReaderInput(readerinput);
646     }
647
648     /* set stream for supplied IXmlReaderInput */
649     hr = readerinput_query_for_stream(This->input);
650     if (hr == S_OK)
651         This->state = XmlReadState_Initial;
652
653     return hr;
654 }
655
656 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
657 {
658     xmlreader *This = impl_from_IXmlReader(iface);
659
660     TRACE("(%p %u %p)\n", This, property, value);
661
662     if (!value) return E_INVALIDARG;
663
664     switch (property)
665     {
666         case XmlReaderProperty_DtdProcessing:
667             *value = This->dtdmode;
668             break;
669         case XmlReaderProperty_ReadState:
670             *value = This->state;
671             break;
672         default:
673             FIXME("Unimplemented property (%u)\n", property);
674             return E_NOTIMPL;
675     }
676
677     return S_OK;
678 }
679
680 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
681 {
682     xmlreader *This = impl_from_IXmlReader(iface);
683
684     TRACE("(%p %u %lu)\n", iface, property, value);
685
686     switch (property)
687     {
688         case XmlReaderProperty_DtdProcessing:
689             if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
690             This->dtdmode = value;
691             break;
692         default:
693             FIXME("Unimplemented property (%u)\n", property);
694             return E_NOTIMPL;
695     }
696
697     return S_OK;
698 }
699
700 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *node_type)
701 {
702     xmlreader *This = impl_from_IXmlReader(iface);
703
704     FIXME("(%p)->(%p): stub\n", This, node_type);
705
706     if (This->state == XmlReadState_Closed) return S_FALSE;
707
708     /* if it's a first call for a new input we need to detect stream encoding */
709     if (This->state == XmlReadState_Initial)
710     {
711         xml_encoding enc;
712         HRESULT hr;
713
714         hr = readerinput_growraw(This->input);
715         if (FAILED(hr)) return hr;
716
717         /* try to detect encoding by BOM or data and set input code page */
718         hr = readerinput_detectencoding(This->input, &enc);
719         TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
720         if (FAILED(hr)) return hr;
721
722         /* always switch first time cause we have to put something in */
723         readerinput_switchencoding(This->input, enc);
724
725         /* parse xml declaration */
726         hr = reader_parse_xmldecl(This);
727         if (FAILED(hr)) return hr;
728
729         This->state = XmlReadState_Interactive;
730     }
731
732     return E_NOTIMPL;
733 }
734
735 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
736 {
737     xmlreader *This = impl_from_IXmlReader(iface);
738     TRACE("(%p)->(%p)\n", This, node_type);
739     *node_type = This->nodetype;
740     return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
741 }
742
743 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
744 {
745     FIXME("(%p): stub\n", iface);
746     return E_NOTIMPL;
747 }
748
749 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
750 {
751     FIXME("(%p): stub\n", iface);
752     return E_NOTIMPL;
753 }
754
755 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
756                                                       LPCWSTR local_name,
757                                                       LPCWSTR namespaceUri)
758 {
759     FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
760     return E_NOTIMPL;
761 }
762
763 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
764 {
765     FIXME("(%p): stub\n", iface);
766     return E_NOTIMPL;
767 }
768
769 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *qualifiedName,
770                                                  UINT *qualifiedName_length)
771 {
772     FIXME("(%p %p %p): stub\n", iface, qualifiedName, qualifiedName_length);
773     return E_NOTIMPL;
774 }
775
776 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
777                                                 LPCWSTR *namespaceUri,
778                                                 UINT *namespaceUri_length)
779 {
780     FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
781     return E_NOTIMPL;
782 }
783
784 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface,
785                                              LPCWSTR *local_name,
786                                              UINT *local_name_length)
787 {
788     FIXME("(%p %p %p): stub\n", iface, local_name, local_name_length);
789     return E_NOTIMPL;
790 }
791
792 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
793                                           LPCWSTR *prefix,
794                                           UINT *prefix_length)
795 {
796     FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
797     return E_NOTIMPL;
798 }
799
800 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface,
801                                          LPCWSTR *value,
802                                          UINT *value_length)
803 {
804     FIXME("(%p %p %p): stub\n", iface, value, value_length);
805     return E_NOTIMPL;
806 }
807
808 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
809                                                WCHAR *buffer,
810                                                UINT   chunk_size,
811                                                UINT  *read)
812 {
813     FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
814     return E_NOTIMPL;
815 }
816
817 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
818                                            LPCWSTR *baseUri,
819                                            UINT *baseUri_length)
820 {
821     FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
822     return E_NOTIMPL;
823 }
824
825 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
826 {
827     FIXME("(%p): stub\n", iface);
828     return E_NOTIMPL;
829 }
830
831 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
832 {
833     FIXME("(%p): stub\n", iface);
834     return E_NOTIMPL;
835 }
836
837 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
838 {
839     xmlreader *This = impl_from_IXmlReader(iface);
840
841     TRACE("(%p %p)\n", This, lineNumber);
842
843     if (!lineNumber) return E_INVALIDARG;
844
845     *lineNumber = This->line;
846
847     return S_OK;
848 }
849
850 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
851 {
852     xmlreader *This = impl_from_IXmlReader(iface);
853
854     TRACE("(%p %p)\n", This, linePosition);
855
856     if (!linePosition) return E_INVALIDARG;
857
858     *linePosition = This->pos;
859
860     return S_OK;
861 }
862
863 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *attributeCount)
864 {
865     FIXME("(%p %p): stub\n", iface, attributeCount);
866     return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
870 {
871     FIXME("(%p %p): stub\n", iface, depth);
872     return E_NOTIMPL;
873 }
874
875 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
876 {
877     FIXME("(%p): stub\n", iface);
878     return E_NOTIMPL;
879 }
880
881 static const struct IXmlReaderVtbl xmlreader_vtbl =
882 {
883     xmlreader_QueryInterface,
884     xmlreader_AddRef,
885     xmlreader_Release,
886     xmlreader_SetInput,
887     xmlreader_GetProperty,
888     xmlreader_SetProperty,
889     xmlreader_Read,
890     xmlreader_GetNodeType,
891     xmlreader_MoveToFirstAttribute,
892     xmlreader_MoveToNextAttribute,
893     xmlreader_MoveToAttributeByName,
894     xmlreader_MoveToElement,
895     xmlreader_GetQualifiedName,
896     xmlreader_GetNamespaceUri,
897     xmlreader_GetLocalName,
898     xmlreader_GetPrefix,
899     xmlreader_GetValue,
900     xmlreader_ReadValueChunk,
901     xmlreader_GetBaseUri,
902     xmlreader_IsDefault,
903     xmlreader_IsEmptyElement,
904     xmlreader_GetLineNumber,
905     xmlreader_GetLinePosition,
906     xmlreader_GetAttributeCount,
907     xmlreader_GetDepth,
908     xmlreader_IsEOF
909 };
910
911 /** IXmlReaderInput **/
912 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
913 {
914     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
915
916     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
917
918     if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
919         IsEqualGUID(riid, &IID_IUnknown))
920     {
921         *ppvObject = iface;
922     }
923     else
924     {
925         WARN("interface %s not implemented\n", debugstr_guid(riid));
926         return E_NOINTERFACE;
927     }
928
929     IUnknown_AddRef(iface);
930
931     return S_OK;
932 }
933
934 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
935 {
936     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
937     ULONG ref = InterlockedIncrement(&This->ref);
938     TRACE("(%p)->(%d)\n", This, ref);
939     return ref;
940 }
941
942 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
943 {
944     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
945     LONG ref = InterlockedDecrement(&This->ref);
946
947     TRACE("(%p)->(%d)\n", This, ref);
948
949     if (ref == 0)
950     {
951         IMalloc *imalloc = This->imalloc;
952         if (This->input) IUnknown_Release(This->input);
953         if (This->stream) ISequentialStream_Release(This->stream);
954         if (This->buffer) free_input_buffer(This->buffer);
955         readerinput_free(This, This->baseuri);
956         readerinput_free(This, This);
957         if (imalloc) IMalloc_Release(imalloc);
958     }
959
960     return ref;
961 }
962
963 static const struct IUnknownVtbl xmlreaderinput_vtbl =
964 {
965     xmlreaderinput_QueryInterface,
966     xmlreaderinput_AddRef,
967     xmlreaderinput_Release
968 };
969
970 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
971 {
972     xmlreader *reader;
973
974     TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
975
976     if (!IsEqualGUID(riid, &IID_IXmlReader))
977     {
978         ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
979         return E_FAIL;
980     }
981
982     if (imalloc)
983         reader = IMalloc_Alloc(imalloc, sizeof(*reader));
984     else
985         reader = heap_alloc(sizeof(*reader));
986     if(!reader) return E_OUTOFMEMORY;
987
988     reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
989     reader->ref = 1;
990     reader->input = NULL;
991     reader->state = XmlReadState_Closed;
992     reader->dtdmode = DtdProcessing_Prohibit;
993     reader->line  = reader->pos = 0;
994     reader->imalloc = imalloc;
995     if (imalloc) IMalloc_AddRef(imalloc);
996     reader->nodetype = XmlNodeType_None;
997
998     *obj = &reader->IXmlReader_iface;
999
1000     TRACE("returning iface %p\n", *obj);
1001
1002     return S_OK;
1003 }
1004
1005 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
1006                                                     IMalloc *imalloc,
1007                                                     LPCWSTR encoding,
1008                                                     BOOL hint,
1009                                                     LPCWSTR base_uri,
1010                                                     IXmlReaderInput **ppInput)
1011 {
1012     xmlreaderinput *readerinput;
1013     HRESULT hr;
1014
1015     TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
1016                                        hint, wine_dbgstr_w(base_uri), ppInput);
1017
1018     if (!stream || !ppInput) return E_INVALIDARG;
1019
1020     if (imalloc)
1021         readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
1022     else
1023         readerinput = heap_alloc(sizeof(*readerinput));
1024     if(!readerinput) return E_OUTOFMEMORY;
1025
1026     readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinput_vtbl;
1027     readerinput->ref = 1;
1028     readerinput->imalloc = imalloc;
1029     readerinput->stream = NULL;
1030     if (imalloc) IMalloc_AddRef(imalloc);
1031     readerinput->encoding = parse_encoding_name(encoding);
1032     readerinput->hint = hint;
1033     readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
1034
1035     hr = alloc_input_buffer(readerinput);
1036     if (hr != S_OK)
1037     {
1038         readerinput_free(readerinput, readerinput);
1039         return hr;
1040     }
1041     IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
1042
1043     *ppInput = &readerinput->IXmlReaderInput_iface;
1044
1045     TRACE("returning iface %p\n", *ppInput);
1046
1047     return S_OK;
1048 }