crypt32: Free the encoded msg (Coverity).
[wine] / dlls / xmllite / reader.c
1 /*
2  * IXmlReader implementation
3  *
4  * Copyright 2010, 2012-2013 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/list.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
36
37 /* not defined in public headers */
38 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
39
40 typedef enum
41 {
42     XmlEncoding_UTF16,
43     XmlEncoding_UTF8,
44     XmlEncoding_Unknown
45 } xml_encoding;
46
47 typedef enum
48 {
49     XmlReadInState_Initial,
50     XmlReadInState_XmlDecl,
51     XmlReadInState_Misc_DTD,
52     XmlReadInState_DTD
53 } XmlReaderInternalState;
54
55 typedef enum
56 {
57     StringValue_LocalName,
58     StringValue_QualifiedName,
59     StringValue_Value,
60     StringValue_Last
61 } XmlReaderStringValue;
62
63 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
64 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
65
66 static const WCHAR dblquoteW[] = {'\"',0};
67 static const WCHAR quoteW[] = {'\'',0};
68
69 struct xml_encoding_data
70 {
71     const WCHAR *name;
72     xml_encoding enc;
73     UINT cp;
74 };
75
76 static const struct xml_encoding_data xml_encoding_map[] = {
77     { utf16W, XmlEncoding_UTF16, ~0 },
78     { utf8W,  XmlEncoding_UTF8,  CP_UTF8 }
79 };
80
81 typedef struct
82 {
83     char *data;
84     char *cur;
85     unsigned int allocated;
86     unsigned int written;
87 } encoded_buffer;
88
89 typedef struct input_buffer input_buffer;
90
91 typedef struct
92 {
93     IXmlReaderInput IXmlReaderInput_iface;
94     LONG ref;
95     /* reference passed on IXmlReaderInput creation, is kept when input is created */
96     IUnknown *input;
97     IMalloc *imalloc;
98     xml_encoding encoding;
99     BOOL hint;
100     WCHAR *baseuri;
101     /* stream reference set after SetInput() call from reader,
102        stored as sequential stream, cause currently
103        optimizations possible with IStream aren't implemented */
104     ISequentialStream *stream;
105     input_buffer *buffer;
106 } xmlreaderinput;
107
108 typedef struct
109 {
110     WCHAR *str;
111     UINT len;
112 } strval;
113
114 static WCHAR emptyW[] = {0};
115 static const strval strval_empty = {emptyW, 0};
116
117 struct attribute
118 {
119     struct list entry;
120     strval localname;
121     strval value;
122 };
123
124 typedef struct
125 {
126     IXmlReader IXmlReader_iface;
127     LONG ref;
128     xmlreaderinput *input;
129     IMalloc *imalloc;
130     XmlReadState state;
131     XmlReaderInternalState instate;
132     XmlNodeType nodetype;
133     DtdProcessing dtdmode;
134     UINT line, pos;           /* reader position in XML stream */
135     struct list attrs; /* attributes list for current node */
136     struct attribute *attr; /* current attribute */
137     UINT attr_count;
138     strval strvalues[StringValue_Last];
139 } xmlreader;
140
141 struct input_buffer
142 {
143     encoded_buffer utf16;
144     encoded_buffer encoded;
145     UINT code_page;
146     xmlreaderinput *input;
147 };
148
149 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
150 {
151     return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
152 }
153
154 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
155 {
156     return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
157 }
158
159 static inline void *m_alloc(IMalloc *imalloc, size_t len)
160 {
161     if (imalloc)
162         return IMalloc_Alloc(imalloc, len);
163     else
164         return heap_alloc(len);
165 }
166
167 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
168 {
169     if (imalloc)
170         return IMalloc_Realloc(imalloc, mem, len);
171     else
172         return heap_realloc(mem, len);
173 }
174
175 static inline void m_free(IMalloc *imalloc, void *mem)
176 {
177     if (imalloc)
178         IMalloc_Free(imalloc, mem);
179     else
180         heap_free(mem);
181 }
182
183 /* reader memory allocation functions */
184 static inline void *reader_alloc(xmlreader *reader, size_t len)
185 {
186     return m_alloc(reader->imalloc, len);
187 }
188
189 static inline void reader_free(xmlreader *reader, void *mem)
190 {
191     m_free(reader->imalloc, mem);
192 }
193
194 /* reader input memory allocation functions */
195 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
196 {
197     return m_alloc(input->imalloc, len);
198 }
199
200 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
201 {
202     return m_realloc(input->imalloc, mem, len);
203 }
204
205 static inline void readerinput_free(xmlreaderinput *input, void *mem)
206 {
207     m_free(input->imalloc, mem);
208 }
209
210 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
211 {
212     LPWSTR ret = NULL;
213
214     if(str) {
215         DWORD size;
216
217         size = (strlenW(str)+1)*sizeof(WCHAR);
218         ret = readerinput_alloc(input, size);
219         if (ret) memcpy(ret, str, size);
220     }
221
222     return ret;
223 }
224
225 static void reader_clear_attrs(xmlreader *reader)
226 {
227     struct attribute *attr, *attr2;
228     LIST_FOR_EACH_ENTRY_SAFE(attr, attr2, &reader->attrs, struct attribute, entry)
229     {
230         reader_free(reader, attr);
231     }
232     list_init(&reader->attrs);
233     reader->attr_count = 0;
234 }
235
236 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
237    while we are on a node with attributes */
238 static HRESULT reader_add_attr(xmlreader *reader, strval *localname, strval *value)
239 {
240     struct attribute *attr;
241
242     attr = reader_alloc(reader, sizeof(*attr));
243     if (!attr) return E_OUTOFMEMORY;
244
245     attr->localname = *localname;
246     attr->value = *value;
247     list_add_tail(&reader->attrs, &attr->entry);
248     reader->attr_count++;
249
250     return S_OK;
251 }
252
253 static void reader_free_strvalue(xmlreader *reader, XmlReaderStringValue type)
254 {
255     strval *v = &reader->strvalues[type];
256
257     if (v->str != strval_empty.str)
258     {
259         reader_free(reader, v->str);
260         *v = strval_empty;
261     }
262 }
263
264 static void reader_free_strvalues(xmlreader *reader)
265 {
266     int type;
267     for (type = 0; type < StringValue_Last; type++)
268         reader_free_strvalue(reader, type);
269 }
270
271 /* always make a copy, cause strings are supposed to be null terminated */
272 static void reader_set_strvalue(xmlreader *reader, XmlReaderStringValue type, const strval *value)
273 {
274     strval *v = &reader->strvalues[type];
275
276     reader_free_strvalue(reader, type);
277     if (value->str == strval_empty.str)
278         *v = *value;
279     else
280     {
281         v->str = reader_alloc(reader, (value->len + 1)*sizeof(WCHAR));
282         memcpy(v->str, value->str, value->len*sizeof(WCHAR));
283         v->str[value->len] = 0;
284         v->len = value->len;
285     }
286 }
287
288 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
289 {
290     const int initial_len = 0x2000;
291     buffer->data = readerinput_alloc(input, initial_len);
292     if (!buffer->data) return E_OUTOFMEMORY;
293
294     memset(buffer->data, 0, 4);
295     buffer->cur = buffer->data;
296     buffer->allocated = initial_len;
297     buffer->written = 0;
298
299     return S_OK;
300 }
301
302 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
303 {
304     readerinput_free(input, buffer->data);
305 }
306
307 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
308 {
309     if (encoding == XmlEncoding_Unknown)
310     {
311         FIXME("unsupported encoding %d\n", encoding);
312         return E_NOTIMPL;
313     }
314
315     *cp = xml_encoding_map[encoding].cp;
316
317     return S_OK;
318 }
319
320 static xml_encoding parse_encoding_name(const WCHAR *name, int len)
321 {
322     int min, max, n, c;
323
324     if (!name) return XmlEncoding_Unknown;
325
326     min = 0;
327     max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
328
329     while (min <= max)
330     {
331         n = (min+max)/2;
332
333         if (len != -1)
334             c = strncmpiW(xml_encoding_map[n].name, name, len);
335         else
336             c = strcmpiW(xml_encoding_map[n].name, name);
337         if (!c)
338             return xml_encoding_map[n].enc;
339
340         if (c > 0)
341             max = n-1;
342         else
343             min = n+1;
344     }
345
346     return XmlEncoding_Unknown;
347 }
348
349 static HRESULT alloc_input_buffer(xmlreaderinput *input)
350 {
351     input_buffer *buffer;
352     HRESULT hr;
353
354     input->buffer = NULL;
355
356     buffer = readerinput_alloc(input, sizeof(*buffer));
357     if (!buffer) return E_OUTOFMEMORY;
358
359     buffer->input = input;
360     buffer->code_page = ~0; /* code page is unknown at this point */
361     hr = init_encoded_buffer(input, &buffer->utf16);
362     if (hr != S_OK) {
363         readerinput_free(input, buffer);
364         return hr;
365     }
366
367     hr = init_encoded_buffer(input, &buffer->encoded);
368     if (hr != S_OK) {
369         free_encoded_buffer(input, &buffer->utf16);
370         readerinput_free(input, buffer);
371         return hr;
372     }
373
374     input->buffer = buffer;
375     return S_OK;
376 }
377
378 static void free_input_buffer(input_buffer *buffer)
379 {
380     free_encoded_buffer(buffer->input, &buffer->encoded);
381     free_encoded_buffer(buffer->input, &buffer->utf16);
382     readerinput_free(buffer->input, buffer);
383 }
384
385 static void readerinput_release_stream(xmlreaderinput *readerinput)
386 {
387     if (readerinput->stream) {
388         ISequentialStream_Release(readerinput->stream);
389         readerinput->stream = NULL;
390     }
391 }
392
393 /* Queries already stored interface for IStream/ISequentialStream.
394    Interface supplied on creation will be overwritten */
395 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
396 {
397     HRESULT hr;
398
399     readerinput_release_stream(readerinput);
400     hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
401     if (hr != S_OK)
402         hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
403
404     return hr;
405 }
406
407 /* reads a chunk to raw buffer */
408 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
409 {
410     encoded_buffer *buffer = &readerinput->buffer->encoded;
411     /* to make sure aligned length won't exceed allocated length */
412     ULONG len = buffer->allocated - buffer->written - 4;
413     ULONG read;
414     HRESULT hr;
415
416     /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
417        variable width encodings like UTF-8 */
418     len = (len + 3) & ~3;
419     /* try to use allocated space or grow */
420     if (buffer->allocated - buffer->written < len)
421     {
422         buffer->allocated *= 2;
423         buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
424         len = buffer->allocated - buffer->written;
425     }
426
427     hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
428     if (FAILED(hr)) return hr;
429     TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
430     buffer->written += read;
431
432     return hr;
433 }
434
435 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
436 static void readerinput_grow(xmlreaderinput *readerinput, int length)
437 {
438     encoded_buffer *buffer = &readerinput->buffer->utf16;
439
440     /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
441     if (buffer->allocated < buffer->written + length + 4)
442     {
443         int grown_size = max(2*buffer->allocated, buffer->allocated + length);
444         buffer->data = readerinput_realloc(readerinput, buffer->data, grown_size);
445         buffer->allocated = grown_size;
446     }
447 }
448
449 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
450 {
451     encoded_buffer *buffer = &readerinput->buffer->encoded;
452     static char startA[] = {'<','?'};
453     static char commentA[] = {'<','!'};
454     static WCHAR startW[] = {'<','?'};
455     static WCHAR commentW[] = {'<','!'};
456     static char utf8bom[] = {0xef,0xbb,0xbf};
457     static char utf16lebom[] = {0xff,0xfe};
458
459     *enc = XmlEncoding_Unknown;
460
461     if (buffer->written <= 3) return MX_E_INPUTEND;
462
463     /* try start symbols if we have enough data to do that, input buffer should contain
464        first chunk already */
465     if (!memcmp(buffer->data, startA, sizeof(startA)) ||
466         !memcmp(buffer->data, commentA, sizeof(commentA)))
467         *enc = XmlEncoding_UTF8;
468     else if (!memcmp(buffer->data, startW, sizeof(startW)) ||
469              !memcmp(buffer->data, commentW, sizeof(commentW)))
470         *enc = XmlEncoding_UTF16;
471     /* try with BOM now */
472     else if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom)))
473     {
474         buffer->cur += sizeof(utf8bom);
475         *enc = XmlEncoding_UTF8;
476     }
477     else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
478     {
479         buffer->cur += sizeof(utf16lebom);
480         *enc = XmlEncoding_UTF16;
481     }
482
483     return S_OK;
484 }
485
486 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
487 {
488     encoded_buffer *buffer = &readerinput->buffer->encoded;
489     int len = buffer->written;
490
491     /* complete single byte char */
492     if (!(buffer->data[len-1] & 0x80)) return len;
493
494     /* find start byte of multibyte char */
495     while (--len && !(buffer->data[len] & 0xc0))
496         ;
497
498     return len;
499 }
500
501 /* Returns byte length of complete char sequence for buffer code page,
502    it's relative to current buffer position which is currently used for BOM handling
503    only. */
504 static int readerinput_get_convlen(xmlreaderinput *readerinput)
505 {
506     encoded_buffer *buffer = &readerinput->buffer->encoded;
507     int len;
508
509     if (readerinput->buffer->code_page == CP_UTF8)
510         len = readerinput_get_utf8_convlen(readerinput);
511     else
512         len = buffer->written;
513
514     TRACE("%d\n", len - (int)(buffer->cur - buffer->data));
515     return len - (buffer->cur - buffer->data);
516 }
517
518 /* It's possbile that raw buffer has some leftovers from last conversion - some char
519    sequence that doesn't represent a full code point. Length argument should be calculated with
520    readerinput_get_convlen(). */
521 static void readerinput_shrinkraw(xmlreaderinput *readerinput, int len)
522 {
523     encoded_buffer *buffer = &readerinput->buffer->encoded;
524     memmove(buffer->data, buffer->cur + (buffer->written - len), len);
525     /* everything lower cur is lost too */
526     buffer->written -= len + (buffer->cur - buffer->data);
527     /* after this point we don't need cur pointer really,
528        it's used only to mark where actual data begins when first chunk is read */
529     buffer->cur = buffer->data;
530 }
531
532 /* note that raw buffer content is kept */
533 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
534 {
535     encoded_buffer *src = &readerinput->buffer->encoded;
536     encoded_buffer *dest = &readerinput->buffer->utf16;
537     int len, dest_len;
538     HRESULT hr;
539     WCHAR *ptr;
540     UINT cp;
541
542     hr = get_code_page(enc, &cp);
543     if (FAILED(hr)) return;
544
545     readerinput->buffer->code_page = cp;
546     len = readerinput_get_convlen(readerinput);
547
548     TRACE("switching to cp %d\n", cp);
549
550     /* just copy in this case */
551     if (enc == XmlEncoding_UTF16)
552     {
553         readerinput_grow(readerinput, len);
554         memcpy(dest->data, src->cur, len);
555         dest->written += len*sizeof(WCHAR);
556         return;
557     }
558
559     dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
560     readerinput_grow(readerinput, dest_len);
561     ptr = (WCHAR*)dest->data;
562     MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
563     ptr[dest_len] = 0;
564     dest->written += dest_len*sizeof(WCHAR);
565 }
566
567 /* shrinks parsed data a buffer begins with */
568 static void reader_shrink(xmlreader *reader)
569 {
570     encoded_buffer *buffer = &reader->input->buffer->utf16;
571
572     /* avoid to move too often using threshold shrink length */
573     if (buffer->cur - buffer->data > buffer->written / 2)
574     {
575         buffer->written -= buffer->cur - buffer->data;
576         memmove(buffer->data, buffer->cur, buffer->written);
577         buffer->cur = buffer->data;
578         *(WCHAR*)&buffer->cur[buffer->written] = 0;
579     }
580 }
581
582 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
583    It won't attempt to shrink but will grow destination buffer if needed */
584 static void reader_more(xmlreader *reader)
585 {
586     xmlreaderinput *readerinput = reader->input;
587     encoded_buffer *src = &readerinput->buffer->encoded;
588     encoded_buffer *dest = &readerinput->buffer->utf16;
589     UINT cp = readerinput->buffer->code_page;
590     int len, dest_len;
591     WCHAR *ptr;
592
593     /* get some raw data from stream first */
594     readerinput_growraw(readerinput);
595     len = readerinput_get_convlen(readerinput);
596
597     /* just copy for UTF-16 case */
598     if (cp == ~0)
599     {
600         readerinput_grow(readerinput, len);
601         memcpy(dest->data, src->cur, len);
602         dest->written += len*sizeof(WCHAR);
603         return;
604     }
605
606     dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
607     readerinput_grow(readerinput, dest_len);
608     ptr = (WCHAR*)dest->data;
609     MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
610     ptr[dest_len] = 0;
611     dest->written += dest_len*sizeof(WCHAR);
612     /* get rid of processed data */
613     readerinput_shrinkraw(readerinput, len);
614 }
615
616 static inline WCHAR *reader_get_cur(xmlreader *reader)
617 {
618     WCHAR *ptr = (WCHAR*)reader->input->buffer->utf16.cur;
619     if (!*ptr) reader_more(reader);
620     return ptr;
621 }
622
623 static int reader_cmp(xmlreader *reader, const WCHAR *str)
624 {
625     const WCHAR *ptr = reader_get_cur(reader);
626     return strncmpW(str, ptr, strlenW(str));
627 }
628
629 /* moves cursor n WCHARs forward */
630 static void reader_skipn(xmlreader *reader, int n)
631 {
632     encoded_buffer *buffer = &reader->input->buffer->utf16;
633     const WCHAR *ptr = reader_get_cur(reader);
634
635     while (*ptr++ && n--)
636     {
637         buffer->cur += sizeof(WCHAR);
638         reader->pos++;
639     }
640 }
641
642 static inline int is_wchar_space(WCHAR ch)
643 {
644     return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
645 }
646
647 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
648 static int reader_skipspaces(xmlreader *reader)
649 {
650     encoded_buffer *buffer = &reader->input->buffer->utf16;
651     const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
652
653     while (is_wchar_space(*ptr))
654     {
655         buffer->cur += sizeof(WCHAR);
656         if (*ptr == '\r')
657             reader->pos = 0;
658         else if (*ptr == '\n')
659         {
660             reader->line++;
661             reader->pos = 0;
662         }
663         else
664             reader->pos++;
665         ptr++;
666     }
667
668     return ptr - start;
669 }
670
671 /* [26] VersionNum ::= '1.' [0-9]+ */
672 static HRESULT reader_parse_versionnum(xmlreader *reader, strval *val)
673 {
674     WCHAR *ptr, *ptr2, *start = reader_get_cur(reader);
675     static const WCHAR onedotW[] = {'1','.',0};
676
677     if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
678     /* skip "1." */
679     reader_skipn(reader, 2);
680
681     ptr2 = ptr = reader_get_cur(reader);
682     while (*ptr >= '0' && *ptr <= '9')
683         ptr++;
684
685     if (ptr2 == ptr) return WC_E_DIGIT;
686     TRACE("version=%s\n", debugstr_wn(start, ptr-start));
687     val->str = start;
688     val->len = ptr-start;
689     reader_skipn(reader, ptr-ptr2);
690     return S_OK;
691 }
692
693 /* [25] Eq ::= S? '=' S? */
694 static HRESULT reader_parse_eq(xmlreader *reader)
695 {
696     static const WCHAR eqW[] = {'=',0};
697     reader_skipspaces(reader);
698     if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
699     /* skip '=' */
700     reader_skipn(reader, 1);
701     reader_skipspaces(reader);
702     return S_OK;
703 }
704
705 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
706 static HRESULT reader_parse_versioninfo(xmlreader *reader)
707 {
708     static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
709     strval val, name;
710     HRESULT hr;
711
712     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
713
714     if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
715     name.str = reader_get_cur(reader);
716     name.len = 7;
717     /* skip 'version' */
718     reader_skipn(reader, 7);
719
720     hr = reader_parse_eq(reader);
721     if (FAILED(hr)) return hr;
722
723     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
724         return WC_E_QUOTE;
725     /* skip "'"|'"' */
726     reader_skipn(reader, 1);
727
728     hr = reader_parse_versionnum(reader, &val);
729     if (FAILED(hr)) return hr;
730
731     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
732         return WC_E_QUOTE;
733
734     /* skip "'"|'"' */
735     reader_skipn(reader, 1);
736
737     return reader_add_attr(reader, &name, &val);
738 }
739
740 /* ([A-Za-z0-9._] | '-') */
741 static inline int is_wchar_encname(WCHAR ch)
742 {
743     return ((ch >= 'A' && ch <= 'Z') ||
744             (ch >= 'a' && ch <= 'z') ||
745             (ch >= '0' && ch <= '9') ||
746             (ch == '.') || (ch == '_') ||
747             (ch == '-'));
748 }
749
750 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
751 static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
752 {
753     WCHAR *start = reader_get_cur(reader), *ptr;
754     xml_encoding enc;
755     int len;
756
757     if ((*start < 'A' || *start > 'Z') && (*start < 'a' || *start > 'z'))
758         return WC_E_ENCNAME;
759
760     ptr = start;
761     while (is_wchar_encname(*++ptr))
762         ;
763
764     len = ptr - start;
765     enc = parse_encoding_name(start, len);
766     TRACE("encoding name %s\n", debugstr_wn(start, len));
767     val->str = start;
768     val->len = len;
769
770     if (enc == XmlEncoding_Unknown)
771         return WC_E_ENCNAME;
772
773     /* skip encoding name */
774     reader_skipn(reader, len);
775     return S_OK;
776 }
777
778 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
779 static HRESULT reader_parse_encdecl(xmlreader *reader)
780 {
781     static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
782     strval name, val;
783     HRESULT hr;
784
785     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
786
787     if (reader_cmp(reader, encodingW)) return S_FALSE;
788     name.str = reader_get_cur(reader);
789     name.len = 8;
790     /* skip 'encoding' */
791     reader_skipn(reader, 8);
792
793     hr = reader_parse_eq(reader);
794     if (FAILED(hr)) return hr;
795
796     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
797         return WC_E_QUOTE;
798     /* skip "'"|'"' */
799     reader_skipn(reader, 1);
800
801     hr = reader_parse_encname(reader, &val);
802     if (FAILED(hr)) return hr;
803
804     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
805         return WC_E_QUOTE;
806
807     /* skip "'"|'"' */
808     reader_skipn(reader, 1);
809
810     return reader_add_attr(reader, &name, &val);
811 }
812
813 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
814 static HRESULT reader_parse_sddecl(xmlreader *reader)
815 {
816     static const WCHAR standaloneW[] = {'s','t','a','n','d','a','l','o','n','e',0};
817     static const WCHAR yesW[] = {'y','e','s',0};
818     static const WCHAR noW[] = {'n','o',0};
819     WCHAR *start, *ptr;
820     strval name, val;
821     HRESULT hr;
822
823     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
824
825     if (reader_cmp(reader, standaloneW)) return S_FALSE;
826     name.str = reader_get_cur(reader);
827     name.len = 10;
828     /* skip 'standalone' */
829     reader_skipn(reader, 10);
830
831     hr = reader_parse_eq(reader);
832     if (FAILED(hr)) return hr;
833
834     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
835         return WC_E_QUOTE;
836     /* skip "'"|'"' */
837     reader_skipn(reader, 1);
838
839     if (reader_cmp(reader, yesW) && reader_cmp(reader, noW))
840         return WC_E_XMLDECL;
841
842     start = reader_get_cur(reader);
843     /* skip 'yes'|'no' */
844     reader_skipn(reader, reader_cmp(reader, yesW) ? 2 : 3);
845     ptr = reader_get_cur(reader);
846     TRACE("standalone=%s\n", debugstr_wn(start, ptr-start));
847     val.str = start;
848     val.len = ptr-start;
849
850     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
851         return WC_E_QUOTE;
852     /* skip "'"|'"' */
853     reader_skipn(reader, 1);
854
855     return reader_add_attr(reader, &name, &val);
856 }
857
858 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
859 static HRESULT reader_parse_xmldecl(xmlreader *reader)
860 {
861     static const WCHAR xmldeclW[] = {'<','?','x','m','l',' ',0};
862     static const WCHAR declcloseW[] = {'?','>',0};
863     HRESULT hr;
864
865     /* check if we have "<?xml " */
866     if (reader_cmp(reader, xmldeclW)) return S_FALSE;
867
868     reader_skipn(reader, 5);
869     hr = reader_parse_versioninfo(reader);
870     if (FAILED(hr))
871         return hr;
872
873     hr = reader_parse_encdecl(reader);
874     if (FAILED(hr))
875         return hr;
876
877     hr = reader_parse_sddecl(reader);
878     if (FAILED(hr))
879         return hr;
880
881     reader_skipspaces(reader);
882     if (reader_cmp(reader, declcloseW)) return WC_E_XMLDECL;
883     reader_skipn(reader, 2);
884
885     reader->nodetype = XmlNodeType_XmlDeclaration;
886     reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
887     reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
888     reader_set_strvalue(reader, StringValue_Value, &strval_empty);
889
890     return S_OK;
891 }
892
893 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
894 static HRESULT reader_parse_comment(xmlreader *reader)
895 {
896     WCHAR *start, *ptr;
897
898     /* skip '<!--' */
899     reader_skipn(reader, 4);
900     reader_shrink(reader);
901     ptr = start = reader_get_cur(reader);
902
903     while (*ptr)
904     {
905         if (ptr[0] == '-')
906         {
907             if (ptr[1] == '-')
908             {
909                 if (ptr[2] == '>')
910                 {
911                     strval value = { start, ptr-start };
912
913                     TRACE("%s\n", debugstr_wn(start, ptr-start));
914                     /* skip '-->' */
915                     reader_skipn(reader, 3);
916                     reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
917                     reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
918                     reader_set_strvalue(reader, StringValue_Value, &value);
919                     reader->nodetype = XmlNodeType_Comment;
920                     return S_OK;
921                 }
922                 else
923                     return WC_E_COMMENT;
924             }
925             else
926             {
927                 ptr++;
928                 reader_more(reader);
929             }
930         }
931         else
932         {
933             reader_skipn(reader, 1);
934             ptr = reader_get_cur(reader);
935         }
936     }
937
938     return MX_E_INPUTEND;
939 }
940
941 static inline int is_namestartchar(WCHAR ch)
942 {
943     return (ch == ':') || (ch >= 'A' && ch <= 'Z') ||
944            (ch == '_') || (ch >= 'a' && ch <= 'z') ||
945            (ch >= 0xc0   && ch <= 0xd6)   ||
946            (ch >= 0xd8   && ch <= 0xf6)   ||
947            (ch >= 0xf8   && ch <= 0x2ff)  ||
948            (ch >= 0x370  && ch <= 0x37d)  ||
949            (ch >= 0x37f  && ch <= 0x1fff) ||
950            (ch >= 0x200c && ch <= 0x200d) ||
951            (ch >= 0x2070 && ch <= 0x218f) ||
952            (ch >= 0x2c00 && ch <= 0x2fef) ||
953            (ch >= 0x3001 && ch <= 0xd7ff) ||
954            (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
955            (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
956            (ch >= 0xf900 && ch <= 0xfdcf) ||
957            (ch >= 0xfdf0 && ch <= 0xfffd);
958 }
959
960 static inline int is_namechar(WCHAR ch)
961 {
962     return (ch == ':') || (ch >= 'A' && ch <= 'Z') ||
963            (ch == '_') || (ch >= 'a' && ch <= 'z') ||
964            (ch == '-') || (ch == '.') ||
965            (ch >= '0'    && ch <= '9')    ||
966            (ch == 0xb7)                   ||
967            (ch >= 0xc0   && ch <= 0xd6)   ||
968            (ch >= 0xd8   && ch <= 0xf6)   ||
969            (ch >= 0xf8   && ch <= 0x2ff)  ||
970            (ch >= 0x300  && ch <= 0x36f)  ||
971            (ch >= 0x370  && ch <= 0x37d)  ||
972            (ch >= 0x37f  && ch <= 0x1fff) ||
973            (ch >= 0x200c && ch <= 0x200d) ||
974            (ch >= 0x203f && ch <= 0x2040) ||
975            (ch >= 0x2070 && ch <= 0x218f) ||
976            (ch >= 0x2c00 && ch <= 0x2fef) ||
977            (ch >= 0x3001 && ch <= 0xd7ff) ||
978            (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
979            (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
980            (ch >= 0xf900 && ch <= 0xfdcf) ||
981            (ch >= 0xfdf0 && ch <= 0xfffd);
982 }
983
984 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
985                             [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
986                             [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
987    [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
988    [5]  Name     ::= NameStartChar (NameChar)* */
989 static HRESULT reader_parse_name(xmlreader *reader, strval *name)
990 {
991     WCHAR *ptr, *start = reader_get_cur(reader);
992
993     ptr = start;
994     if (!is_namestartchar(*ptr)) return WC_E_NAMECHARACTER;
995
996     while (is_namechar(*ptr))
997     {
998         reader_skipn(reader, 1);
999         ptr = reader_get_cur(reader);
1000     }
1001
1002     TRACE("name %s:%d\n", debugstr_wn(start, ptr-start), (int)(ptr-start));
1003     name->str = start;
1004     name->len = ptr-start;
1005
1006     return S_OK;
1007 }
1008
1009 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1010 static HRESULT reader_parse_pitarget(xmlreader *reader, strval *target)
1011 {
1012     static const WCHAR xmlW[] = {'x','m','l'};
1013     strval name;
1014     HRESULT hr;
1015     int i;
1016
1017     hr = reader_parse_name(reader, &name);
1018     if (FAILED(hr)) return WC_E_PI;
1019
1020     /* now that we got name check for illegal content */
1021     if (name.len == 3 && !strncmpiW(name.str, xmlW, 3))
1022         return WC_E_LEADINGXML;
1023
1024     /* PITarget can't be a qualified name */
1025     for (i = 0; i < name.len; i++)
1026         if (name.str[i] == ':')
1027             return i ? NC_E_NAMECOLON : WC_E_PI;
1028
1029     TRACE("pitarget %s:%d\n", debugstr_wn(name.str, name.len), name.len);
1030     *target = name;
1031     return S_OK;
1032 }
1033
1034 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1035 static HRESULT reader_parse_pi(xmlreader *reader)
1036 {
1037     WCHAR *ptr, *start;
1038     strval target;
1039     HRESULT hr;
1040
1041     /* skip '<?' */
1042     reader_skipn(reader, 2);
1043     reader_shrink(reader);
1044
1045     hr = reader_parse_pitarget(reader, &target);
1046     if (FAILED(hr)) return hr;
1047
1048     ptr = reader_get_cur(reader);
1049     /* exit earlier if there's no content */
1050     if (ptr[0] == '?' && ptr[1] == '>')
1051     {
1052         /* skip '?>' */
1053         reader_skipn(reader, 2);
1054         reader->nodetype = XmlNodeType_ProcessingInstruction;
1055         reader_set_strvalue(reader, StringValue_LocalName, &target);
1056         reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1057         reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1058         return S_OK;
1059     }
1060
1061     /* now at least a single space char should be there */
1062     if (!is_wchar_space(*ptr)) return WC_E_WHITESPACE;
1063     reader_skipspaces(reader);
1064
1065     ptr = start = reader_get_cur(reader);
1066
1067     while (*ptr)
1068     {
1069         if (ptr[0] == '?')
1070         {
1071             if (ptr[1] == '>')
1072             {
1073                 strval value = { start, ptr-start };
1074
1075                 TRACE("%s\n", debugstr_wn(start, ptr-start));
1076                 /* skip '?>' */
1077                 reader_skipn(reader, 2);
1078                 reader->nodetype = XmlNodeType_ProcessingInstruction;
1079                 reader_set_strvalue(reader, StringValue_LocalName, &target);
1080                 reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1081                 reader_set_strvalue(reader, StringValue_Value, &value);
1082                 return S_OK;
1083             }
1084             else
1085             {
1086                 ptr++;
1087                 reader_more(reader);
1088             }
1089         }
1090         else
1091         {
1092             reader_skipn(reader, 1);
1093             ptr = reader_get_cur(reader);
1094         }
1095     }
1096
1097     return S_OK;
1098 }
1099
1100 /* [27] Misc ::= Comment | PI | S */
1101 static HRESULT reader_parse_misc(xmlreader *reader)
1102 {
1103     HRESULT hr = S_FALSE;
1104
1105     while (1)
1106     {
1107         static const WCHAR commentW[] = {'<','!','-','-',0};
1108         static const WCHAR piW[] = {'<','?',0};
1109         const WCHAR *cur = reader_get_cur(reader);
1110
1111         if (is_wchar_space(*cur))
1112             reader_skipspaces(reader);
1113         else if (!reader_cmp(reader, commentW))
1114             hr = reader_parse_comment(reader);
1115         else if (!reader_cmp(reader, piW))
1116             hr = reader_parse_pi(reader);
1117         else
1118             break;
1119
1120         if (FAILED(hr)) return hr;
1121     }
1122
1123     return hr;
1124 }
1125
1126 static HRESULT reader_parse_nextnode(xmlreader *reader)
1127 {
1128     HRESULT hr;
1129
1130     while (1)
1131     {
1132         switch (reader->instate)
1133         {
1134         /* if it's a first call for a new input we need to detect stream encoding */
1135         case XmlReadInState_Initial:
1136             {
1137                 xml_encoding enc;
1138
1139                 hr = readerinput_growraw(reader->input);
1140                 if (FAILED(hr)) return hr;
1141
1142                 /* try to detect encoding by BOM or data and set input code page */
1143                 hr = readerinput_detectencoding(reader->input, &enc);
1144                 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
1145                 if (FAILED(hr)) return hr;
1146
1147                 /* always switch first time cause we have to put something in */
1148                 readerinput_switchencoding(reader->input, enc);
1149
1150                 /* parse xml declaration */
1151                 hr = reader_parse_xmldecl(reader);
1152                 if (FAILED(hr)) return hr;
1153
1154                 reader->instate = XmlReadInState_Misc_DTD;
1155                 if (hr == S_OK) return hr;
1156             }
1157             break;
1158         case XmlReadInState_Misc_DTD:
1159             hr = reader_parse_misc(reader);
1160             if (FAILED(hr)) return hr;
1161             if (hr == S_FALSE)
1162             {
1163                 reader->instate = XmlReadInState_DTD;
1164                 return S_OK;
1165             }
1166             break;
1167         case XmlReadInState_DTD:
1168             FIXME("DTD parsing not supported\n");
1169             return E_NOTIMPL;
1170         default:
1171             FIXME("internal state %d not handled\n", reader->instate);
1172             return E_NOTIMPL;
1173         }
1174     }
1175
1176     return E_NOTIMPL;
1177 }
1178
1179 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
1180 {
1181     xmlreader *This = impl_from_IXmlReader(iface);
1182
1183     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
1184
1185     if (IsEqualGUID(riid, &IID_IUnknown) ||
1186         IsEqualGUID(riid, &IID_IXmlReader))
1187     {
1188         *ppvObject = iface;
1189     }
1190     else
1191     {
1192         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1193         return E_NOINTERFACE;
1194     }
1195
1196     IXmlReader_AddRef(iface);
1197
1198     return S_OK;
1199 }
1200
1201 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
1202 {
1203     xmlreader *This = impl_from_IXmlReader(iface);
1204     ULONG ref = InterlockedIncrement(&This->ref);
1205     TRACE("(%p)->(%d)\n", This, ref);
1206     return ref;
1207 }
1208
1209 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
1210 {
1211     xmlreader *This = impl_from_IXmlReader(iface);
1212     LONG ref = InterlockedDecrement(&This->ref);
1213
1214     TRACE("(%p)->(%d)\n", This, ref);
1215
1216     if (ref == 0)
1217     {
1218         IMalloc *imalloc = This->imalloc;
1219         if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
1220         reader_clear_attrs(This);
1221         reader_free_strvalues(This);
1222         reader_free(This, This);
1223         if (imalloc) IMalloc_Release(imalloc);
1224     }
1225
1226     return ref;
1227 }
1228
1229 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
1230 {
1231     xmlreader *This = impl_from_IXmlReader(iface);
1232     HRESULT hr;
1233
1234     TRACE("(%p)->(%p)\n", This, input);
1235
1236     if (This->input)
1237     {
1238         readerinput_release_stream(This->input);
1239         IUnknown_Release(&This->input->IXmlReaderInput_iface);
1240         This->input = NULL;
1241     }
1242
1243     This->line = This->pos = 0;
1244
1245     /* just reset current input */
1246     if (!input)
1247     {
1248         This->state = XmlReadState_Initial;
1249         return S_OK;
1250     }
1251
1252     /* now try IXmlReaderInput, ISequentialStream, IStream */
1253     hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input);
1254     if (hr != S_OK)
1255     {
1256         IXmlReaderInput *readerinput;
1257
1258         /* create IXmlReaderInput basing on supplied interface */
1259         hr = CreateXmlReaderInputWithEncodingName(input,
1260                                          NULL, NULL, FALSE, NULL, &readerinput);
1261         if (hr != S_OK) return hr;
1262         This->input = impl_from_IXmlReaderInput(readerinput);
1263     }
1264
1265     /* set stream for supplied IXmlReaderInput */
1266     hr = readerinput_query_for_stream(This->input);
1267     if (hr == S_OK)
1268     {
1269         This->state = XmlReadState_Initial;
1270         This->instate = XmlReadInState_Initial;
1271     }
1272
1273     return hr;
1274 }
1275
1276 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
1277 {
1278     xmlreader *This = impl_from_IXmlReader(iface);
1279
1280     TRACE("(%p %u %p)\n", This, property, value);
1281
1282     if (!value) return E_INVALIDARG;
1283
1284     switch (property)
1285     {
1286         case XmlReaderProperty_DtdProcessing:
1287             *value = This->dtdmode;
1288             break;
1289         case XmlReaderProperty_ReadState:
1290             *value = This->state;
1291             break;
1292         default:
1293             FIXME("Unimplemented property (%u)\n", property);
1294             return E_NOTIMPL;
1295     }
1296
1297     return S_OK;
1298 }
1299
1300 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
1301 {
1302     xmlreader *This = impl_from_IXmlReader(iface);
1303
1304     TRACE("(%p %u %lu)\n", iface, property, value);
1305
1306     switch (property)
1307     {
1308         case XmlReaderProperty_DtdProcessing:
1309             if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
1310             This->dtdmode = value;
1311             break;
1312         default:
1313             FIXME("Unimplemented property (%u)\n", property);
1314             return E_NOTIMPL;
1315     }
1316
1317     return S_OK;
1318 }
1319
1320 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
1321 {
1322     xmlreader *This = impl_from_IXmlReader(iface);
1323     XmlNodeType oldtype = This->nodetype;
1324     HRESULT hr;
1325
1326     TRACE("(%p)->(%p)\n", This, nodetype);
1327
1328     if (This->state == XmlReadState_Closed) return S_FALSE;
1329
1330     hr = reader_parse_nextnode(This);
1331     if (oldtype == XmlNodeType_None && This->nodetype != oldtype)
1332         This->state = XmlReadState_Interactive;
1333     if (hr == S_OK) *nodetype = This->nodetype;
1334
1335     return hr;
1336 }
1337
1338 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
1339 {
1340     xmlreader *This = impl_from_IXmlReader(iface);
1341     TRACE("(%p)->(%p)\n", This, node_type);
1342
1343     /* When we're on attribute always return attribute type, container node type is kept.
1344        Note that container is not necessarily an element, and attribute doesn't mean it's
1345        an attribute in XML spec terms. */
1346     *node_type = This->attr ? XmlNodeType_Attribute : This->nodetype;
1347     return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
1348 }
1349
1350 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
1351 {
1352     xmlreader *This = impl_from_IXmlReader(iface);
1353
1354     TRACE("(%p)\n", This);
1355
1356     if (!This->attr_count) return S_FALSE;
1357     This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
1358     return S_OK;
1359 }
1360
1361 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
1362 {
1363     xmlreader *This = impl_from_IXmlReader(iface);
1364     const struct list *next;
1365
1366     TRACE("(%p)\n", This);
1367
1368     if (!This->attr_count) return S_FALSE;
1369
1370     if (!This->attr)
1371         return IXmlReader_MoveToFirstAttribute(iface);
1372
1373     next = list_next(&This->attrs, &This->attr->entry);
1374     if (next)
1375         This->attr = LIST_ENTRY(next, struct attribute, entry);
1376
1377     return next ? S_OK : S_FALSE;
1378 }
1379
1380 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
1381                                                       LPCWSTR local_name,
1382                                                       LPCWSTR namespaceUri)
1383 {
1384     FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
1385     return E_NOTIMPL;
1386 }
1387
1388 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
1389 {
1390     xmlreader *This = impl_from_IXmlReader(iface);
1391
1392     TRACE("(%p)\n", This);
1393
1394     if (!This->attr_count) return S_FALSE;
1395     This->attr = NULL;
1396     return S_OK;
1397 }
1398
1399 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *name, UINT *len)
1400 {
1401     xmlreader *This = impl_from_IXmlReader(iface);
1402
1403     TRACE("(%p)->(%p %p)\n", This, name, len);
1404     *name = This->strvalues[StringValue_QualifiedName].str;
1405     *len  = This->strvalues[StringValue_QualifiedName].len;
1406     return S_OK;
1407 }
1408
1409 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
1410                                                 LPCWSTR *namespaceUri,
1411                                                 UINT *namespaceUri_length)
1412 {
1413     FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
1414     return E_NOTIMPL;
1415 }
1416
1417 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, UINT *len)
1418 {
1419     xmlreader *This = impl_from_IXmlReader(iface);
1420
1421     TRACE("(%p)->(%p %p)\n", This, name, len);
1422     *name = This->strvalues[StringValue_LocalName].str;
1423     *len  = This->strvalues[StringValue_LocalName].len;
1424     return S_OK;
1425 }
1426
1427 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
1428                                           LPCWSTR *prefix,
1429                                           UINT *prefix_length)
1430 {
1431     FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
1432     return E_NOTIMPL;
1433 }
1434
1435 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, LPCWSTR *value, UINT *len)
1436 {
1437     xmlreader *This = impl_from_IXmlReader(iface);
1438
1439     TRACE("(%p)->(%p %p)\n", This, value, len);
1440     *value = This->strvalues[StringValue_Value].str;
1441     if (len) *len = This->strvalues[StringValue_Value].len;
1442     return S_OK;
1443 }
1444
1445 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
1446                                                WCHAR *buffer,
1447                                                UINT   chunk_size,
1448                                                UINT  *read)
1449 {
1450     FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
1451     return E_NOTIMPL;
1452 }
1453
1454 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
1455                                            LPCWSTR *baseUri,
1456                                            UINT *baseUri_length)
1457 {
1458     FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
1459     return E_NOTIMPL;
1460 }
1461
1462 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
1463 {
1464     FIXME("(%p): stub\n", iface);
1465     return E_NOTIMPL;
1466 }
1467
1468 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
1469 {
1470     FIXME("(%p): stub\n", iface);
1471     return E_NOTIMPL;
1472 }
1473
1474 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
1475 {
1476     xmlreader *This = impl_from_IXmlReader(iface);
1477
1478     TRACE("(%p %p)\n", This, lineNumber);
1479
1480     if (!lineNumber) return E_INVALIDARG;
1481
1482     *lineNumber = This->line;
1483
1484     return S_OK;
1485 }
1486
1487 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
1488 {
1489     xmlreader *This = impl_from_IXmlReader(iface);
1490
1491     TRACE("(%p %p)\n", This, linePosition);
1492
1493     if (!linePosition) return E_INVALIDARG;
1494
1495     *linePosition = This->pos;
1496
1497     return S_OK;
1498 }
1499
1500 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
1501 {
1502     xmlreader *This = impl_from_IXmlReader(iface);
1503
1504     TRACE("(%p)->(%p)\n", This, count);
1505
1506     if (!count) return E_INVALIDARG;
1507
1508     *count = This->attr_count;
1509     return S_OK;
1510 }
1511
1512 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
1513 {
1514     FIXME("(%p %p): stub\n", iface, depth);
1515     return E_NOTIMPL;
1516 }
1517
1518 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
1519 {
1520     FIXME("(%p): stub\n", iface);
1521     return E_NOTIMPL;
1522 }
1523
1524 static const struct IXmlReaderVtbl xmlreader_vtbl =
1525 {
1526     xmlreader_QueryInterface,
1527     xmlreader_AddRef,
1528     xmlreader_Release,
1529     xmlreader_SetInput,
1530     xmlreader_GetProperty,
1531     xmlreader_SetProperty,
1532     xmlreader_Read,
1533     xmlreader_GetNodeType,
1534     xmlreader_MoveToFirstAttribute,
1535     xmlreader_MoveToNextAttribute,
1536     xmlreader_MoveToAttributeByName,
1537     xmlreader_MoveToElement,
1538     xmlreader_GetQualifiedName,
1539     xmlreader_GetNamespaceUri,
1540     xmlreader_GetLocalName,
1541     xmlreader_GetPrefix,
1542     xmlreader_GetValue,
1543     xmlreader_ReadValueChunk,
1544     xmlreader_GetBaseUri,
1545     xmlreader_IsDefault,
1546     xmlreader_IsEmptyElement,
1547     xmlreader_GetLineNumber,
1548     xmlreader_GetLinePosition,
1549     xmlreader_GetAttributeCount,
1550     xmlreader_GetDepth,
1551     xmlreader_IsEOF
1552 };
1553
1554 /** IXmlReaderInput **/
1555 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
1556 {
1557     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1558
1559     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
1560
1561     if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
1562         IsEqualGUID(riid, &IID_IUnknown))
1563     {
1564         *ppvObject = iface;
1565     }
1566     else
1567     {
1568         WARN("interface %s not implemented\n", debugstr_guid(riid));
1569         return E_NOINTERFACE;
1570     }
1571
1572     IUnknown_AddRef(iface);
1573
1574     return S_OK;
1575 }
1576
1577 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
1578 {
1579     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1580     ULONG ref = InterlockedIncrement(&This->ref);
1581     TRACE("(%p)->(%d)\n", This, ref);
1582     return ref;
1583 }
1584
1585 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
1586 {
1587     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1588     LONG ref = InterlockedDecrement(&This->ref);
1589
1590     TRACE("(%p)->(%d)\n", This, ref);
1591
1592     if (ref == 0)
1593     {
1594         IMalloc *imalloc = This->imalloc;
1595         if (This->input) IUnknown_Release(This->input);
1596         if (This->stream) ISequentialStream_Release(This->stream);
1597         if (This->buffer) free_input_buffer(This->buffer);
1598         readerinput_free(This, This->baseuri);
1599         readerinput_free(This, This);
1600         if (imalloc) IMalloc_Release(imalloc);
1601     }
1602
1603     return ref;
1604 }
1605
1606 static const struct IUnknownVtbl xmlreaderinput_vtbl =
1607 {
1608     xmlreaderinput_QueryInterface,
1609     xmlreaderinput_AddRef,
1610     xmlreaderinput_Release
1611 };
1612
1613 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
1614 {
1615     xmlreader *reader;
1616     int i;
1617
1618     TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
1619
1620     if (!IsEqualGUID(riid, &IID_IXmlReader))
1621     {
1622         ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
1623         return E_FAIL;
1624     }
1625
1626     if (imalloc)
1627         reader = IMalloc_Alloc(imalloc, sizeof(*reader));
1628     else
1629         reader = heap_alloc(sizeof(*reader));
1630     if(!reader) return E_OUTOFMEMORY;
1631
1632     reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
1633     reader->ref = 1;
1634     reader->input = NULL;
1635     reader->state = XmlReadState_Closed;
1636     reader->instate = XmlReadInState_Initial;
1637     reader->dtdmode = DtdProcessing_Prohibit;
1638     reader->line  = reader->pos = 0;
1639     reader->imalloc = imalloc;
1640     if (imalloc) IMalloc_AddRef(imalloc);
1641     reader->nodetype = XmlNodeType_None;
1642     list_init(&reader->attrs);
1643     reader->attr_count = 0;
1644     reader->attr = NULL;
1645
1646     for (i = 0; i < StringValue_Last; i++)
1647         reader->strvalues[i] = strval_empty;
1648
1649     *obj = &reader->IXmlReader_iface;
1650
1651     TRACE("returning iface %p\n", *obj);
1652
1653     return S_OK;
1654 }
1655
1656 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
1657                                                     IMalloc *imalloc,
1658                                                     LPCWSTR encoding,
1659                                                     BOOL hint,
1660                                                     LPCWSTR base_uri,
1661                                                     IXmlReaderInput **ppInput)
1662 {
1663     xmlreaderinput *readerinput;
1664     HRESULT hr;
1665
1666     TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
1667                                        hint, wine_dbgstr_w(base_uri), ppInput);
1668
1669     if (!stream || !ppInput) return E_INVALIDARG;
1670
1671     if (imalloc)
1672         readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
1673     else
1674         readerinput = heap_alloc(sizeof(*readerinput));
1675     if(!readerinput) return E_OUTOFMEMORY;
1676
1677     readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinput_vtbl;
1678     readerinput->ref = 1;
1679     readerinput->imalloc = imalloc;
1680     readerinput->stream = NULL;
1681     if (imalloc) IMalloc_AddRef(imalloc);
1682     readerinput->encoding = parse_encoding_name(encoding, -1);
1683     readerinput->hint = hint;
1684     readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
1685
1686     hr = alloc_input_buffer(readerinput);
1687     if (hr != S_OK)
1688     {
1689         readerinput_free(readerinput, readerinput);
1690         return hr;
1691     }
1692     IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
1693
1694     *ppInput = &readerinput->IXmlReaderInput_iface;
1695
1696     TRACE("returning iface %p\n", *ppInput);
1697
1698     return S_OK;
1699 }