wbemprox: Return an empty object if the path is NULL or empty.
[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     XmlReadInState_DTD_Misc,
54     XmlReadInState_Element,
55     XmlReadInState_Content,
56     XmlReadInState_MiscEnd
57 } XmlReaderInternalState;
58
59 typedef enum
60 {
61     StringValue_LocalName,
62     StringValue_QualifiedName,
63     StringValue_Value,
64     StringValue_Last
65 } XmlReaderStringValue;
66
67 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
68 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
69
70 static const WCHAR dblquoteW[] = {'\"',0};
71 static const WCHAR quoteW[] = {'\'',0};
72 static const WCHAR ltW[] = {'<',0};
73 static const WCHAR gtW[] = {'>',0};
74 static const WCHAR commentW[] = {'<','!','-','-',0};
75 static const WCHAR piW[] = {'<','?',0};
76
77 struct xml_encoding_data
78 {
79     const WCHAR *name;
80     xml_encoding enc;
81     UINT cp;
82 };
83
84 static const struct xml_encoding_data xml_encoding_map[] = {
85     { utf16W, XmlEncoding_UTF16, ~0 },
86     { utf8W,  XmlEncoding_UTF8,  CP_UTF8 }
87 };
88
89 typedef struct
90 {
91     char *data;
92     char *cur;
93     unsigned int allocated;
94     unsigned int written;
95 } encoded_buffer;
96
97 typedef struct input_buffer input_buffer;
98
99 typedef struct
100 {
101     IXmlReaderInput IXmlReaderInput_iface;
102     LONG ref;
103     /* reference passed on IXmlReaderInput creation, is kept when input is created */
104     IUnknown *input;
105     IMalloc *imalloc;
106     xml_encoding encoding;
107     BOOL hint;
108     WCHAR *baseuri;
109     /* stream reference set after SetInput() call from reader,
110        stored as sequential stream, cause currently
111        optimizations possible with IStream aren't implemented */
112     ISequentialStream *stream;
113     input_buffer *buffer;
114     unsigned int pending : 1;
115 } xmlreaderinput;
116
117 static const struct IUnknownVtbl xmlreaderinputvtbl;
118
119 typedef struct
120 {
121     WCHAR *str;
122     UINT len;
123 } strval;
124
125 static WCHAR emptyW[] = {0};
126 static const strval strval_empty = {emptyW, 0};
127
128 struct attribute
129 {
130     struct list entry;
131     strval localname;
132     strval value;
133 };
134
135 struct element
136 {
137     struct list entry;
138     strval qname;
139 };
140
141 typedef struct
142 {
143     IXmlReader IXmlReader_iface;
144     LONG ref;
145     xmlreaderinput *input;
146     IMalloc *imalloc;
147     XmlReadState state;
148     XmlReaderInternalState instate;
149     XmlNodeType nodetype;
150     DtdProcessing dtdmode;
151     UINT line, pos;           /* reader position in XML stream */
152     struct list attrs; /* attributes list for current node */
153     struct attribute *attr; /* current attribute */
154     UINT attr_count;
155     struct list elements;
156     strval strvalues[StringValue_Last];
157     UINT depth;
158     WCHAR *save;
159 } xmlreader;
160
161 struct input_buffer
162 {
163     encoded_buffer utf16;
164     encoded_buffer encoded;
165     UINT code_page;
166     xmlreaderinput *input;
167 };
168
169 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
170 {
171     return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
172 }
173
174 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
175 {
176     return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
177 }
178
179 static inline void *m_alloc(IMalloc *imalloc, size_t len)
180 {
181     if (imalloc)
182         return IMalloc_Alloc(imalloc, len);
183     else
184         return heap_alloc(len);
185 }
186
187 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
188 {
189     if (imalloc)
190         return IMalloc_Realloc(imalloc, mem, len);
191     else
192         return heap_realloc(mem, len);
193 }
194
195 static inline void m_free(IMalloc *imalloc, void *mem)
196 {
197     if (imalloc)
198         IMalloc_Free(imalloc, mem);
199     else
200         heap_free(mem);
201 }
202
203 /* reader memory allocation functions */
204 static inline void *reader_alloc(xmlreader *reader, size_t len)
205 {
206     return m_alloc(reader->imalloc, len);
207 }
208
209 static inline void reader_free(xmlreader *reader, void *mem)
210 {
211     m_free(reader->imalloc, mem);
212 }
213
214 static HRESULT reader_strvaldup(xmlreader *reader, const strval *src, strval *dest)
215 {
216     *dest = *src;
217
218     if (src->str != strval_empty.str)
219     {
220         dest->str = reader_alloc(reader, (dest->len+1)*sizeof(WCHAR));
221         if (!dest->str) return E_OUTOFMEMORY;
222         memcpy(dest->str, src->str, dest->len*sizeof(WCHAR));
223         dest->str[dest->len] = 0;
224     }
225
226     return S_OK;
227 }
228
229 /* reader input memory allocation functions */
230 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
231 {
232     return m_alloc(input->imalloc, len);
233 }
234
235 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
236 {
237     return m_realloc(input->imalloc, mem, len);
238 }
239
240 static inline void readerinput_free(xmlreaderinput *input, void *mem)
241 {
242     m_free(input->imalloc, mem);
243 }
244
245 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
246 {
247     LPWSTR ret = NULL;
248
249     if(str) {
250         DWORD size;
251
252         size = (strlenW(str)+1)*sizeof(WCHAR);
253         ret = readerinput_alloc(input, size);
254         if (ret) memcpy(ret, str, size);
255     }
256
257     return ret;
258 }
259
260 static void reader_clear_attrs(xmlreader *reader)
261 {
262     struct attribute *attr, *attr2;
263     LIST_FOR_EACH_ENTRY_SAFE(attr, attr2, &reader->attrs, struct attribute, entry)
264     {
265         reader_free(reader, attr);
266     }
267     list_init(&reader->attrs);
268     reader->attr_count = 0;
269 }
270
271 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
272    while we are on a node with attributes */
273 static HRESULT reader_add_attr(xmlreader *reader, strval *localname, strval *value)
274 {
275     struct attribute *attr;
276
277     attr = reader_alloc(reader, sizeof(*attr));
278     if (!attr) return E_OUTOFMEMORY;
279
280     attr->localname = *localname;
281     attr->value = *value;
282     list_add_tail(&reader->attrs, &attr->entry);
283     reader->attr_count++;
284
285     return S_OK;
286 }
287
288 /* This one frees stored string value if needed */
289 static void reader_free_strvalued(xmlreader *reader, strval *v)
290 {
291     if (v->str != strval_empty.str)
292     {
293         reader_free(reader, v->str);
294         *v = strval_empty;
295     }
296 }
297
298 static void reader_free_strvalue(xmlreader *reader, XmlReaderStringValue type)
299 {
300     reader_free_strvalued(reader, &reader->strvalues[type]);
301 }
302
303 static void reader_free_strvalues(xmlreader *reader)
304 {
305     int type;
306     for (type = 0; type < StringValue_Last; type++)
307         reader_free_strvalue(reader, type);
308 }
309
310 /* This helper should only be used to test if strings are the same,
311    it doesn't try to sort. */
312 static inline int strval_eq(const strval *str1, const strval *str2)
313 {
314     if (str1->len != str2->len) return 0;
315     return !memcmp(str1->str, str2->str, str1->len*sizeof(WCHAR));
316 }
317
318 static void reader_clear_elements(xmlreader *reader)
319 {
320     struct element *elem, *elem2;
321     LIST_FOR_EACH_ENTRY_SAFE(elem, elem2, &reader->elements, struct element, entry)
322     {
323         reader_free_strvalued(reader, &elem->qname);
324         reader_free(reader, elem);
325     }
326     list_init(&reader->elements);
327 }
328
329 static HRESULT reader_inc_depth(xmlreader *reader)
330 {
331     /* FIXME: handle XmlReaderProperty_MaxElementDepth property */
332     reader->depth++;
333     return S_OK;
334 }
335
336 static HRESULT reader_push_element(xmlreader *reader, strval *qname)
337 {
338     struct element *elem;
339     HRESULT hr;
340
341     elem = reader_alloc(reader, sizeof(*elem));
342     if (!elem) return E_OUTOFMEMORY;
343
344     hr = reader_strvaldup(reader, qname, &elem->qname);
345     if (FAILED(hr)) return hr;
346
347     if (!list_empty(&reader->elements))
348     {
349         hr = reader_inc_depth(reader);
350         if (FAILED(hr)) return hr;
351     }
352
353     list_add_head(&reader->elements, &elem->entry);
354     return hr;
355 }
356
357 static void reader_pop_element(xmlreader *reader)
358 {
359     struct element *elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
360
361     if (elem)
362     {
363         list_remove(&elem->entry);
364         reader_free_strvalued(reader, &elem->qname);
365         reader_free(reader, elem);
366     }
367 }
368
369 /* Always make a copy, cause strings are supposed to be null terminated. Null pointer for 'value'
370    means node value is to be determined. */
371 static void reader_set_strvalue(xmlreader *reader, XmlReaderStringValue type, const strval *value)
372 {
373     strval *v = &reader->strvalues[type];
374
375     reader_free_strvalue(reader, type);
376     if (!value)
377     {
378         v->str = NULL;
379         v->len = 0;
380         return;
381     }
382
383     if (value->str == strval_empty.str)
384         *v = *value;
385     else
386     {
387         v->str = reader_alloc(reader, (value->len + 1)*sizeof(WCHAR));
388         memcpy(v->str, value->str, value->len*sizeof(WCHAR));
389         v->str[value->len] = 0;
390         v->len = value->len;
391     }
392 }
393
394 static inline int is_reader_pending(xmlreader *reader)
395 {
396     return reader->input->pending;
397 }
398
399 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
400 {
401     const int initial_len = 0x2000;
402     buffer->data = readerinput_alloc(input, initial_len);
403     if (!buffer->data) return E_OUTOFMEMORY;
404
405     memset(buffer->data, 0, 4);
406     buffer->cur = buffer->data;
407     buffer->allocated = initial_len;
408     buffer->written = 0;
409
410     return S_OK;
411 }
412
413 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
414 {
415     readerinput_free(input, buffer->data);
416 }
417
418 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
419 {
420     if (encoding == XmlEncoding_Unknown)
421     {
422         FIXME("unsupported encoding %d\n", encoding);
423         return E_NOTIMPL;
424     }
425
426     *cp = xml_encoding_map[encoding].cp;
427
428     return S_OK;
429 }
430
431 static xml_encoding parse_encoding_name(const WCHAR *name, int len)
432 {
433     int min, max, n, c;
434
435     if (!name) return XmlEncoding_Unknown;
436
437     min = 0;
438     max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
439
440     while (min <= max)
441     {
442         n = (min+max)/2;
443
444         if (len != -1)
445             c = strncmpiW(xml_encoding_map[n].name, name, len);
446         else
447             c = strcmpiW(xml_encoding_map[n].name, name);
448         if (!c)
449             return xml_encoding_map[n].enc;
450
451         if (c > 0)
452             max = n-1;
453         else
454             min = n+1;
455     }
456
457     return XmlEncoding_Unknown;
458 }
459
460 static HRESULT alloc_input_buffer(xmlreaderinput *input)
461 {
462     input_buffer *buffer;
463     HRESULT hr;
464
465     input->buffer = NULL;
466
467     buffer = readerinput_alloc(input, sizeof(*buffer));
468     if (!buffer) return E_OUTOFMEMORY;
469
470     buffer->input = input;
471     buffer->code_page = ~0; /* code page is unknown at this point */
472     hr = init_encoded_buffer(input, &buffer->utf16);
473     if (hr != S_OK) {
474         readerinput_free(input, buffer);
475         return hr;
476     }
477
478     hr = init_encoded_buffer(input, &buffer->encoded);
479     if (hr != S_OK) {
480         free_encoded_buffer(input, &buffer->utf16);
481         readerinput_free(input, buffer);
482         return hr;
483     }
484
485     input->buffer = buffer;
486     return S_OK;
487 }
488
489 static void free_input_buffer(input_buffer *buffer)
490 {
491     free_encoded_buffer(buffer->input, &buffer->encoded);
492     free_encoded_buffer(buffer->input, &buffer->utf16);
493     readerinput_free(buffer->input, buffer);
494 }
495
496 static void readerinput_release_stream(xmlreaderinput *readerinput)
497 {
498     if (readerinput->stream) {
499         ISequentialStream_Release(readerinput->stream);
500         readerinput->stream = NULL;
501     }
502 }
503
504 /* Queries already stored interface for IStream/ISequentialStream.
505    Interface supplied on creation will be overwritten */
506 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
507 {
508     HRESULT hr;
509
510     readerinput_release_stream(readerinput);
511     hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
512     if (hr != S_OK)
513         hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
514
515     return hr;
516 }
517
518 /* reads a chunk to raw buffer */
519 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
520 {
521     encoded_buffer *buffer = &readerinput->buffer->encoded;
522     /* to make sure aligned length won't exceed allocated length */
523     ULONG len = buffer->allocated - buffer->written - 4;
524     ULONG read;
525     HRESULT hr;
526
527     /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
528        variable width encodings like UTF-8 */
529     len = (len + 3) & ~3;
530     /* try to use allocated space or grow */
531     if (buffer->allocated - buffer->written < len)
532     {
533         buffer->allocated *= 2;
534         buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
535         len = buffer->allocated - buffer->written;
536     }
537
538     read = 0;
539     hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
540     TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
541     readerinput->pending = hr == E_PENDING;
542     if (FAILED(hr)) return hr;
543     buffer->written += read;
544
545     return hr;
546 }
547
548 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
549 static void readerinput_grow(xmlreaderinput *readerinput, int length)
550 {
551     encoded_buffer *buffer = &readerinput->buffer->utf16;
552
553     /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
554     if (buffer->allocated < buffer->written + length + 4)
555     {
556         int grown_size = max(2*buffer->allocated, buffer->allocated + length);
557         buffer->data = readerinput_realloc(readerinput, buffer->data, grown_size);
558         buffer->allocated = grown_size;
559     }
560 }
561
562 static inline int readerinput_is_utf8(xmlreaderinput *readerinput)
563 {
564     static char startA[] = {'<','?'};
565     static char commentA[] = {'<','!'};
566     encoded_buffer *buffer = &readerinput->buffer->encoded;
567     unsigned char *ptr = (unsigned char*)buffer->data;
568
569     return !memcmp(buffer->data, startA, sizeof(startA)) ||
570            !memcmp(buffer->data, commentA, sizeof(commentA)) ||
571            /* test start byte */
572            (ptr[0] == '<' &&
573             (
574              (ptr[1] && (ptr[1] <= 0x7f)) ||
575              (buffer->data[1] >> 5) == 0x6  || /* 2 bytes */
576              (buffer->data[1] >> 4) == 0xe  || /* 3 bytes */
577              (buffer->data[1] >> 3) == 0x1e)   /* 4 bytes */
578            );
579 }
580
581 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
582 {
583     encoded_buffer *buffer = &readerinput->buffer->encoded;
584     static WCHAR startW[] = {'<','?'};
585     static WCHAR commentW[] = {'<','!'};
586     static char utf8bom[] = {0xef,0xbb,0xbf};
587     static char utf16lebom[] = {0xff,0xfe};
588
589     *enc = XmlEncoding_Unknown;
590
591     if (buffer->written <= 3) return MX_E_INPUTEND;
592
593     /* try start symbols if we have enough data to do that, input buffer should contain
594        first chunk already */
595     if (readerinput_is_utf8(readerinput))
596         *enc = XmlEncoding_UTF8;
597     else if (!memcmp(buffer->data, startW, sizeof(startW)) ||
598              !memcmp(buffer->data, commentW, sizeof(commentW)))
599         *enc = XmlEncoding_UTF16;
600     /* try with BOM now */
601     else if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom)))
602     {
603         buffer->cur += sizeof(utf8bom);
604         *enc = XmlEncoding_UTF8;
605     }
606     else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
607     {
608         buffer->cur += sizeof(utf16lebom);
609         *enc = XmlEncoding_UTF16;
610     }
611
612     return S_OK;
613 }
614
615 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
616 {
617     encoded_buffer *buffer = &readerinput->buffer->encoded;
618     int len = buffer->written;
619
620     /* complete single byte char */
621     if (!(buffer->data[len-1] & 0x80)) return len;
622
623     /* find start byte of multibyte char */
624     while (--len && !(buffer->data[len] & 0xc0))
625         ;
626
627     return len;
628 }
629
630 /* Returns byte length of complete char sequence for buffer code page,
631    it's relative to current buffer position which is currently used for BOM handling
632    only. */
633 static int readerinput_get_convlen(xmlreaderinput *readerinput)
634 {
635     encoded_buffer *buffer = &readerinput->buffer->encoded;
636     int len;
637
638     if (readerinput->buffer->code_page == CP_UTF8)
639         len = readerinput_get_utf8_convlen(readerinput);
640     else
641         len = buffer->written;
642
643     TRACE("%d\n", len - (int)(buffer->cur - buffer->data));
644     return len - (buffer->cur - buffer->data);
645 }
646
647 /* It's possible that raw buffer has some leftovers from last conversion - some char
648    sequence that doesn't represent a full code point. Length argument should be calculated with
649    readerinput_get_convlen(), if it's -1 it will be calculated here. */
650 static void readerinput_shrinkraw(xmlreaderinput *readerinput, int len)
651 {
652     encoded_buffer *buffer = &readerinput->buffer->encoded;
653
654     if (len == -1)
655         len = readerinput_get_convlen(readerinput);
656
657     memmove(buffer->data, buffer->cur + (buffer->written - len), len);
658     /* everything below cur is lost too */
659     buffer->written -= len + (buffer->cur - buffer->data);
660     /* after this point we don't need cur pointer really,
661        it's used only to mark where actual data begins when first chunk is read */
662     buffer->cur = buffer->data;
663 }
664
665 /* note that raw buffer content is kept */
666 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
667 {
668     encoded_buffer *src = &readerinput->buffer->encoded;
669     encoded_buffer *dest = &readerinput->buffer->utf16;
670     int len, dest_len;
671     HRESULT hr;
672     WCHAR *ptr;
673     UINT cp;
674
675     hr = get_code_page(enc, &cp);
676     if (FAILED(hr)) return;
677
678     readerinput->buffer->code_page = cp;
679     len = readerinput_get_convlen(readerinput);
680
681     TRACE("switching to cp %d\n", cp);
682
683     /* just copy in this case */
684     if (enc == XmlEncoding_UTF16)
685     {
686         readerinput_grow(readerinput, len);
687         memcpy(dest->data, src->cur, len);
688         dest->written += len*sizeof(WCHAR);
689         return;
690     }
691
692     dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
693     readerinput_grow(readerinput, dest_len);
694     ptr = (WCHAR*)dest->data;
695     MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
696     ptr[dest_len] = 0;
697     dest->written += dest_len*sizeof(WCHAR);
698 }
699
700 /* shrinks parsed data a buffer begins with */
701 static void reader_shrink(xmlreader *reader)
702 {
703     encoded_buffer *buffer = &reader->input->buffer->utf16;
704
705     /* avoid to move too often using threshold shrink length */
706     if (buffer->cur - buffer->data > buffer->written / 2)
707     {
708         buffer->written -= buffer->cur - buffer->data;
709         memmove(buffer->data, buffer->cur, buffer->written);
710         buffer->cur = buffer->data;
711         *(WCHAR*)&buffer->cur[buffer->written] = 0;
712     }
713 }
714
715 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
716    It won't attempt to shrink but will grow destination buffer if needed */
717 static HRESULT reader_more(xmlreader *reader)
718 {
719     xmlreaderinput *readerinput = reader->input;
720     encoded_buffer *src = &readerinput->buffer->encoded;
721     encoded_buffer *dest = &readerinput->buffer->utf16;
722     UINT cp = readerinput->buffer->code_page;
723     int len, dest_len;
724     HRESULT hr;
725     WCHAR *ptr;
726
727     /* get some raw data from stream first */
728     hr = readerinput_growraw(readerinput);
729     len = readerinput_get_convlen(readerinput);
730
731     /* just copy for UTF-16 case */
732     if (cp == ~0)
733     {
734         readerinput_grow(readerinput, len);
735         memcpy(dest->data, src->cur, len);
736         dest->written += len*sizeof(WCHAR);
737         return hr;
738     }
739
740     dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
741     readerinput_grow(readerinput, dest_len);
742     ptr = (WCHAR*)dest->data;
743     MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
744     ptr[dest_len] = 0;
745     dest->written += dest_len*sizeof(WCHAR);
746     /* get rid of processed data */
747     readerinput_shrinkraw(readerinput, len);
748
749     return hr;
750 }
751
752 static inline WCHAR *reader_get_cur(xmlreader *reader)
753 {
754     WCHAR *ptr = (WCHAR*)reader->input->buffer->utf16.cur;
755     if (!*ptr) reader_more(reader);
756     return ptr;
757 }
758
759 static int reader_cmp(xmlreader *reader, const WCHAR *str)
760 {
761     const WCHAR *ptr = reader_get_cur(reader);
762     return strncmpW(str, ptr, strlenW(str));
763 }
764
765 /* moves cursor n WCHARs forward */
766 static void reader_skipn(xmlreader *reader, int n)
767 {
768     encoded_buffer *buffer = &reader->input->buffer->utf16;
769     const WCHAR *ptr = reader_get_cur(reader);
770
771     while (*ptr++ && n--)
772     {
773         buffer->cur += sizeof(WCHAR);
774         reader->pos++;
775     }
776 }
777
778 static inline int is_wchar_space(WCHAR ch)
779 {
780     return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
781 }
782
783 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
784 static int reader_skipspaces(xmlreader *reader)
785 {
786     encoded_buffer *buffer = &reader->input->buffer->utf16;
787     const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
788
789     while (is_wchar_space(*ptr))
790     {
791         buffer->cur += sizeof(WCHAR);
792         if (*ptr == '\r')
793             reader->pos = 0;
794         else if (*ptr == '\n')
795         {
796             reader->line++;
797             reader->pos = 0;
798         }
799         else
800             reader->pos++;
801         ptr++;
802     }
803
804     return ptr - start;
805 }
806
807 /* [26] VersionNum ::= '1.' [0-9]+ */
808 static HRESULT reader_parse_versionnum(xmlreader *reader, strval *val)
809 {
810     WCHAR *ptr, *ptr2, *start = reader_get_cur(reader);
811     static const WCHAR onedotW[] = {'1','.',0};
812
813     if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
814     /* skip "1." */
815     reader_skipn(reader, 2);
816
817     ptr2 = ptr = reader_get_cur(reader);
818     while (*ptr >= '0' && *ptr <= '9')
819         ptr++;
820
821     if (ptr2 == ptr) return WC_E_DIGIT;
822     TRACE("version=%s\n", debugstr_wn(start, ptr-start));
823     val->str = start;
824     val->len = ptr-start;
825     reader_skipn(reader, ptr-ptr2);
826     return S_OK;
827 }
828
829 /* [25] Eq ::= S? '=' S? */
830 static HRESULT reader_parse_eq(xmlreader *reader)
831 {
832     static const WCHAR eqW[] = {'=',0};
833     reader_skipspaces(reader);
834     if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
835     /* skip '=' */
836     reader_skipn(reader, 1);
837     reader_skipspaces(reader);
838     return S_OK;
839 }
840
841 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
842 static HRESULT reader_parse_versioninfo(xmlreader *reader)
843 {
844     static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
845     strval val, name;
846     HRESULT hr;
847
848     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
849
850     if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
851     name.str = reader_get_cur(reader);
852     name.len = 7;
853     /* skip 'version' */
854     reader_skipn(reader, 7);
855
856     hr = reader_parse_eq(reader);
857     if (FAILED(hr)) return hr;
858
859     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
860         return WC_E_QUOTE;
861     /* skip "'"|'"' */
862     reader_skipn(reader, 1);
863
864     hr = reader_parse_versionnum(reader, &val);
865     if (FAILED(hr)) return hr;
866
867     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
868         return WC_E_QUOTE;
869
870     /* skip "'"|'"' */
871     reader_skipn(reader, 1);
872
873     return reader_add_attr(reader, &name, &val);
874 }
875
876 /* ([A-Za-z0-9._] | '-') */
877 static inline int is_wchar_encname(WCHAR ch)
878 {
879     return ((ch >= 'A' && ch <= 'Z') ||
880             (ch >= 'a' && ch <= 'z') ||
881             (ch >= '0' && ch <= '9') ||
882             (ch == '.') || (ch == '_') ||
883             (ch == '-'));
884 }
885
886 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
887 static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
888 {
889     WCHAR *start = reader_get_cur(reader), *ptr;
890     xml_encoding enc;
891     int len;
892
893     if ((*start < 'A' || *start > 'Z') && (*start < 'a' || *start > 'z'))
894         return WC_E_ENCNAME;
895
896     ptr = start;
897     while (is_wchar_encname(*++ptr))
898         ;
899
900     len = ptr - start;
901     enc = parse_encoding_name(start, len);
902     TRACE("encoding name %s\n", debugstr_wn(start, len));
903     val->str = start;
904     val->len = len;
905
906     if (enc == XmlEncoding_Unknown)
907         return WC_E_ENCNAME;
908
909     /* skip encoding name */
910     reader_skipn(reader, len);
911     return S_OK;
912 }
913
914 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
915 static HRESULT reader_parse_encdecl(xmlreader *reader)
916 {
917     static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
918     strval name, val;
919     HRESULT hr;
920
921     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
922
923     if (reader_cmp(reader, encodingW)) return S_FALSE;
924     name.str = reader_get_cur(reader);
925     name.len = 8;
926     /* skip 'encoding' */
927     reader_skipn(reader, 8);
928
929     hr = reader_parse_eq(reader);
930     if (FAILED(hr)) return hr;
931
932     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
933         return WC_E_QUOTE;
934     /* skip "'"|'"' */
935     reader_skipn(reader, 1);
936
937     hr = reader_parse_encname(reader, &val);
938     if (FAILED(hr)) return hr;
939
940     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
941         return WC_E_QUOTE;
942
943     /* skip "'"|'"' */
944     reader_skipn(reader, 1);
945
946     return reader_add_attr(reader, &name, &val);
947 }
948
949 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
950 static HRESULT reader_parse_sddecl(xmlreader *reader)
951 {
952     static const WCHAR standaloneW[] = {'s','t','a','n','d','a','l','o','n','e',0};
953     static const WCHAR yesW[] = {'y','e','s',0};
954     static const WCHAR noW[] = {'n','o',0};
955     WCHAR *start, *ptr;
956     strval name, val;
957     HRESULT hr;
958
959     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
960
961     if (reader_cmp(reader, standaloneW)) return S_FALSE;
962     name.str = reader_get_cur(reader);
963     name.len = 10;
964     /* skip 'standalone' */
965     reader_skipn(reader, 10);
966
967     hr = reader_parse_eq(reader);
968     if (FAILED(hr)) return hr;
969
970     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
971         return WC_E_QUOTE;
972     /* skip "'"|'"' */
973     reader_skipn(reader, 1);
974
975     if (reader_cmp(reader, yesW) && reader_cmp(reader, noW))
976         return WC_E_XMLDECL;
977
978     start = reader_get_cur(reader);
979     /* skip 'yes'|'no' */
980     reader_skipn(reader, reader_cmp(reader, yesW) ? 2 : 3);
981     ptr = reader_get_cur(reader);
982     TRACE("standalone=%s\n", debugstr_wn(start, ptr-start));
983     val.str = start;
984     val.len = ptr-start;
985
986     if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
987         return WC_E_QUOTE;
988     /* skip "'"|'"' */
989     reader_skipn(reader, 1);
990
991     return reader_add_attr(reader, &name, &val);
992 }
993
994 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
995 static HRESULT reader_parse_xmldecl(xmlreader *reader)
996 {
997     static const WCHAR xmldeclW[] = {'<','?','x','m','l',' ',0};
998     static const WCHAR declcloseW[] = {'?','>',0};
999     HRESULT hr;
1000
1001     /* check if we have "<?xml " */
1002     if (reader_cmp(reader, xmldeclW)) return S_FALSE;
1003
1004     reader_skipn(reader, 5);
1005     hr = reader_parse_versioninfo(reader);
1006     if (FAILED(hr))
1007         return hr;
1008
1009     hr = reader_parse_encdecl(reader);
1010     if (FAILED(hr))
1011         return hr;
1012
1013     hr = reader_parse_sddecl(reader);
1014     if (FAILED(hr))
1015         return hr;
1016
1017     reader_skipspaces(reader);
1018     if (reader_cmp(reader, declcloseW)) return WC_E_XMLDECL;
1019     reader_skipn(reader, 2);
1020
1021     reader->nodetype = XmlNodeType_XmlDeclaration;
1022     reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1023     reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1024     reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1025
1026     return S_OK;
1027 }
1028
1029 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1030 static HRESULT reader_parse_comment(xmlreader *reader)
1031 {
1032     WCHAR *start, *ptr;
1033
1034     if (reader->save)
1035     {
1036         start = reader->save;
1037         ptr = reader_get_cur(reader);
1038         reader->save = NULL;
1039     }
1040     else
1041     {
1042         /* skip '<!--' */
1043         reader_skipn(reader, 4);
1044         reader_shrink(reader);
1045         ptr = start = reader_get_cur(reader);
1046         reader->nodetype = XmlNodeType_Comment;
1047         reader_set_strvalue(reader, StringValue_LocalName, NULL);
1048         reader_set_strvalue(reader, StringValue_QualifiedName, NULL);
1049         reader_set_strvalue(reader, StringValue_Value, NULL);
1050     }
1051
1052     /* will exit when there's no more data, it won't attempt to
1053        read more from stream */
1054     while (*ptr)
1055     {
1056         if (ptr[0] == '-')
1057         {
1058             if (ptr[1] == '-')
1059             {
1060                 if (ptr[2] == '>')
1061                 {
1062                     strval value = { start, ptr-start };
1063
1064                     TRACE("%s\n", debugstr_wn(start, ptr-start));
1065                     /* skip '-->' */
1066                     reader_skipn(reader, 3);
1067                     reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1068                     reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1069                     reader_set_strvalue(reader, StringValue_Value, &value);
1070                     reader->nodetype = XmlNodeType_Comment;
1071                     return S_OK;
1072                 }
1073                 else
1074                     return WC_E_COMMENT;
1075             }
1076             else
1077                 ptr++;
1078         }
1079         else
1080         {
1081             reader_skipn(reader, 1);
1082             ptr++;
1083         }
1084     }
1085
1086     return S_OK;
1087 }
1088
1089 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1090 static inline int is_char(WCHAR ch)
1091 {
1092     return (ch == '\t') || (ch == '\r') || (ch == '\n') ||
1093            (ch >= 0x20 && ch <= 0xd7ff) ||
1094            (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1095            (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1096            (ch >= 0xe000 && ch <= 0xfffd);
1097 }
1098
1099 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1100 static inline int is_pubchar(WCHAR ch)
1101 {
1102     return (ch == ' ') ||
1103            (ch >= 'a' && ch <= 'z') ||
1104            (ch >= 'A' && ch <= 'Z') ||
1105            (ch >= '0' && ch <= '9') ||
1106            (ch >= '-' && ch <= ';') || /* '()*+,-./:; */
1107            (ch == '=') || (ch == '?') ||
1108            (ch == '@') || (ch == '!') ||
1109            (ch >= '#' && ch <= '%') || /* #$% */
1110            (ch == '_') || (ch == '\r') || (ch == '\n');
1111 }
1112
1113 static inline int is_namestartchar(WCHAR ch)
1114 {
1115     return (ch == ':') || (ch >= 'A' && ch <= 'Z') ||
1116            (ch == '_') || (ch >= 'a' && ch <= 'z') ||
1117            (ch >= 0xc0   && ch <= 0xd6)   ||
1118            (ch >= 0xd8   && ch <= 0xf6)   ||
1119            (ch >= 0xf8   && ch <= 0x2ff)  ||
1120            (ch >= 0x370  && ch <= 0x37d)  ||
1121            (ch >= 0x37f  && ch <= 0x1fff) ||
1122            (ch >= 0x200c && ch <= 0x200d) ||
1123            (ch >= 0x2070 && ch <= 0x218f) ||
1124            (ch >= 0x2c00 && ch <= 0x2fef) ||
1125            (ch >= 0x3001 && ch <= 0xd7ff) ||
1126            (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1127            (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1128            (ch >= 0xf900 && ch <= 0xfdcf) ||
1129            (ch >= 0xfdf0 && ch <= 0xfffd);
1130 }
1131
1132 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1133 static inline int is_ncnamechar(WCHAR ch)
1134 {
1135     return (ch >= 'A' && ch <= 'Z') ||
1136            (ch == '_') || (ch >= 'a' && ch <= 'z') ||
1137            (ch == '-') || (ch == '.') ||
1138            (ch >= '0'    && ch <= '9')    ||
1139            (ch == 0xb7)                   ||
1140            (ch >= 0xc0   && ch <= 0xd6)   ||
1141            (ch >= 0xd8   && ch <= 0xf6)   ||
1142            (ch >= 0xf8   && ch <= 0x2ff)  ||
1143            (ch >= 0x300  && ch <= 0x36f)  ||
1144            (ch >= 0x370  && ch <= 0x37d)  ||
1145            (ch >= 0x37f  && ch <= 0x1fff) ||
1146            (ch >= 0x200c && ch <= 0x200d) ||
1147            (ch >= 0x203f && ch <= 0x2040) ||
1148            (ch >= 0x2070 && ch <= 0x218f) ||
1149            (ch >= 0x2c00 && ch <= 0x2fef) ||
1150            (ch >= 0x3001 && ch <= 0xd7ff) ||
1151            (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1152            (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1153            (ch >= 0xf900 && ch <= 0xfdcf) ||
1154            (ch >= 0xfdf0 && ch <= 0xfffd);
1155 }
1156
1157 static inline int is_namechar(WCHAR ch)
1158 {
1159     return (ch == ':') || is_ncnamechar(ch);
1160 }
1161
1162 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
1163                             [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
1164                             [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
1165    [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
1166    [5]  Name     ::= NameStartChar (NameChar)* */
1167 static HRESULT reader_parse_name(xmlreader *reader, strval *name)
1168 {
1169     WCHAR *ptr, *start = reader_get_cur(reader);
1170
1171     ptr = start;
1172     if (!is_namestartchar(*ptr)) return WC_E_NAMECHARACTER;
1173
1174     while (is_namechar(*ptr))
1175     {
1176         reader_skipn(reader, 1);
1177         ptr = reader_get_cur(reader);
1178     }
1179
1180     TRACE("name %s:%d\n", debugstr_wn(start, ptr-start), (int)(ptr-start));
1181     name->str = start;
1182     name->len = ptr-start;
1183
1184     return S_OK;
1185 }
1186
1187 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1188 static HRESULT reader_parse_pitarget(xmlreader *reader, strval *target)
1189 {
1190     static const WCHAR xmlW[] = {'x','m','l'};
1191     strval name;
1192     HRESULT hr;
1193     int i;
1194
1195     hr = reader_parse_name(reader, &name);
1196     if (FAILED(hr)) return WC_E_PI;
1197
1198     /* now that we got name check for illegal content */
1199     if (name.len == 3 && !strncmpiW(name.str, xmlW, 3))
1200         return WC_E_LEADINGXML;
1201
1202     /* PITarget can't be a qualified name */
1203     for (i = 0; i < name.len; i++)
1204         if (name.str[i] == ':')
1205             return i ? NC_E_NAMECOLON : WC_E_PI;
1206
1207     TRACE("pitarget %s:%d\n", debugstr_wn(name.str, name.len), name.len);
1208     *target = name;
1209     return S_OK;
1210 }
1211
1212 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1213 static HRESULT reader_parse_pi(xmlreader *reader)
1214 {
1215     WCHAR *ptr, *start;
1216     strval target;
1217     HRESULT hr;
1218
1219     /* skip '<?' */
1220     reader_skipn(reader, 2);
1221     reader_shrink(reader);
1222
1223     hr = reader_parse_pitarget(reader, &target);
1224     if (FAILED(hr)) return hr;
1225
1226     ptr = reader_get_cur(reader);
1227     /* exit earlier if there's no content */
1228     if (ptr[0] == '?' && ptr[1] == '>')
1229     {
1230         /* skip '?>' */
1231         reader_skipn(reader, 2);
1232         reader->nodetype = XmlNodeType_ProcessingInstruction;
1233         reader_set_strvalue(reader, StringValue_LocalName, &target);
1234         reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1235         reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1236         return S_OK;
1237     }
1238
1239     /* now at least a single space char should be there */
1240     if (!is_wchar_space(*ptr)) return WC_E_WHITESPACE;
1241     reader_skipspaces(reader);
1242
1243     ptr = start = reader_get_cur(reader);
1244
1245     while (*ptr)
1246     {
1247         if (ptr[0] == '?')
1248         {
1249             if (ptr[1] == '>')
1250             {
1251                 strval value = { start, ptr-start };
1252
1253                 TRACE("%s\n", debugstr_wn(start, ptr-start));
1254                 /* skip '?>' */
1255                 reader_skipn(reader, 2);
1256                 reader->nodetype = XmlNodeType_ProcessingInstruction;
1257                 reader_set_strvalue(reader, StringValue_LocalName, &target);
1258                 reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1259                 reader_set_strvalue(reader, StringValue_Value, &value);
1260                 return S_OK;
1261             }
1262             else
1263             {
1264                 ptr++;
1265                 reader_more(reader);
1266             }
1267         }
1268         else
1269         {
1270             reader_skipn(reader, 1);
1271             ptr = reader_get_cur(reader);
1272         }
1273     }
1274
1275     return S_OK;
1276 }
1277
1278 /* This one is used to parse significant whitespace nodes, like in Misc production */
1279 static HRESULT reader_parse_whitespace(xmlreader *reader)
1280 {
1281     WCHAR *start, *ptr;
1282
1283     reader_shrink(reader);
1284     start = reader_get_cur(reader);
1285
1286     reader_skipspaces(reader);
1287     ptr = reader_get_cur(reader);
1288     TRACE("%s\n", debugstr_wn(start, ptr-start));
1289
1290     reader->nodetype = XmlNodeType_Whitespace;
1291     reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1292     reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1293     reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1294     return S_OK;
1295 }
1296
1297 /* [27] Misc ::= Comment | PI | S */
1298 static HRESULT reader_parse_misc(xmlreader *reader)
1299 {
1300     HRESULT hr = S_FALSE;
1301
1302     if (is_reader_pending(reader))
1303     {
1304         hr = reader_more(reader);
1305         if (FAILED(hr)) return hr;
1306
1307         /* finish current node */
1308         if (reader->nodetype == XmlNodeType_Comment)
1309             return reader_parse_comment(reader);
1310     }
1311
1312     while (1)
1313     {
1314         const WCHAR *cur = reader_get_cur(reader);
1315
1316         if (is_wchar_space(*cur))
1317             hr = reader_parse_whitespace(reader);
1318         else if (!reader_cmp(reader, commentW))
1319             hr = reader_parse_comment(reader);
1320         else if (!reader_cmp(reader, piW))
1321             hr = reader_parse_pi(reader);
1322         else
1323             break;
1324
1325         if (hr != S_FALSE) return hr;
1326     }
1327
1328     return hr;
1329 }
1330
1331 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1332 static HRESULT reader_parse_sys_literal(xmlreader *reader, strval *literal)
1333 {
1334     WCHAR *start = reader_get_cur(reader), *cur, quote;
1335
1336     if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1337
1338     quote = *start;
1339     reader_skipn(reader, 1);
1340
1341     cur = start = reader_get_cur(reader);
1342     while (is_char(*cur) && *cur != quote)
1343     {
1344         reader_skipn(reader, 1);
1345         cur = reader_get_cur(reader);
1346     }
1347     if (*cur == quote) reader_skipn(reader, 1);
1348
1349     literal->str = start;
1350     literal->len = cur-start;
1351     TRACE("%s\n", debugstr_wn(start, cur-start));
1352     return S_OK;
1353 }
1354
1355 /* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1356    [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1357 static HRESULT reader_parse_pub_literal(xmlreader *reader, strval *literal)
1358 {
1359     WCHAR *start = reader_get_cur(reader), *cur, quote;
1360
1361     if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1362
1363     quote = *start;
1364     reader_skipn(reader, 1);
1365
1366     cur = start;
1367     while (is_pubchar(*cur) && *cur != quote)
1368     {
1369         reader_skipn(reader, 1);
1370         cur = reader_get_cur(reader);
1371     }
1372
1373     literal->str = start;
1374     literal->len = cur-start;
1375     TRACE("%s\n", debugstr_wn(start, cur-start));
1376     return S_OK;
1377 }
1378
1379 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1380 static HRESULT reader_parse_externalid(xmlreader *reader)
1381 {
1382     static WCHAR systemW[] = {'S','Y','S','T','E','M',0};
1383     static WCHAR publicW[] = {'P','U','B','L','I','C',0};
1384     strval name;
1385     HRESULT hr;
1386     int cnt;
1387
1388     if (reader_cmp(reader, systemW))
1389     {
1390         if (reader_cmp(reader, publicW))
1391             return S_FALSE;
1392         else
1393         {
1394             strval pub;
1395
1396             /* public id */
1397             reader_skipn(reader, 6);
1398             cnt = reader_skipspaces(reader);
1399             if (!cnt) return WC_E_WHITESPACE;
1400
1401             hr = reader_parse_pub_literal(reader, &pub);
1402             if (FAILED(hr)) return hr;
1403
1404             name.str = publicW;
1405             name.len = strlenW(publicW);
1406             return reader_add_attr(reader, &name, &pub);
1407         }
1408     }
1409     else
1410     {
1411         strval sys;
1412
1413         /* system id */
1414         reader_skipn(reader, 6);
1415         cnt = reader_skipspaces(reader);
1416         if (!cnt) return WC_E_WHITESPACE;
1417
1418         hr = reader_parse_sys_literal(reader, &sys);
1419         if (FAILED(hr)) return hr;
1420
1421         name.str = systemW;
1422         name.len = strlenW(systemW);
1423         return reader_add_attr(reader, &name, &sys);
1424     }
1425
1426     return hr;
1427 }
1428
1429 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1430 static HRESULT reader_parse_dtd(xmlreader *reader)
1431 {
1432     static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',0};
1433     strval name;
1434     WCHAR *cur;
1435     HRESULT hr;
1436
1437     /* check if we have "<!DOCTYPE" */
1438     if (reader_cmp(reader, doctypeW)) return S_FALSE;
1439     reader_shrink(reader);
1440
1441     /* DTD processing is not allowed by default */
1442     if (reader->dtdmode == DtdProcessing_Prohibit) return WC_E_DTDPROHIBITED;
1443
1444     reader_skipn(reader, 9);
1445     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
1446
1447     /* name */
1448     hr = reader_parse_name(reader, &name);
1449     if (FAILED(hr)) return WC_E_DECLDOCTYPE;
1450
1451     reader_skipspaces(reader);
1452
1453     hr = reader_parse_externalid(reader);
1454     if (FAILED(hr)) return hr;
1455
1456     reader_skipspaces(reader);
1457
1458     cur = reader_get_cur(reader);
1459     if (*cur != '>')
1460     {
1461         FIXME("internal subset parsing not implemented\n");
1462         return E_NOTIMPL;
1463     }
1464
1465     /* skip '>' */
1466     reader_skipn(reader, 1);
1467
1468     reader->nodetype = XmlNodeType_DocumentType;
1469     reader_set_strvalue(reader, StringValue_LocalName, &name);
1470     reader_set_strvalue(reader, StringValue_QualifiedName, &name);
1471
1472     return S_OK;
1473 }
1474
1475 /* [7 NS]  QName ::= PrefixedName | UnprefixedName
1476    [8 NS]  PrefixedName ::= Prefix ':' LocalPart
1477    [9 NS]  UnprefixedName ::= LocalPart
1478    [10 NS] Prefix ::= NCName
1479    [11 NS] LocalPart ::= NCName */
1480 static HRESULT reader_parse_qname(xmlreader *reader, strval *prefix, strval *local, strval *qname)
1481 {
1482     WCHAR *ptr, *start = reader_get_cur(reader);
1483
1484     ptr = start;
1485     if (!is_ncnamechar(*ptr)) return NC_E_QNAMECHARACTER;
1486
1487     while (is_ncnamechar(*ptr))
1488     {
1489         reader_skipn(reader, 1);
1490         ptr = reader_get_cur(reader);
1491     }
1492
1493     /* got a qualified name */
1494     if (*ptr == ':')
1495     {
1496         prefix->str = start;
1497         prefix->len = ptr-start;
1498
1499         reader_skipn(reader, 1);
1500         start = ptr = reader_get_cur(reader);
1501
1502         while (is_ncnamechar(*ptr))
1503         {
1504             reader_skipn(reader, 1);
1505             ptr = reader_get_cur(reader);
1506         }
1507     }
1508     else
1509     {
1510         prefix->str = NULL;
1511         prefix->len = 0;
1512     }
1513
1514     local->str = start;
1515     local->len = ptr-start;
1516
1517     if (prefix->len)
1518         TRACE("qname %s:%s\n", debugstr_wn(prefix->str, prefix->len), debugstr_wn(local->str, local->len));
1519     else
1520         TRACE("ncname %s\n", debugstr_wn(local->str, local->len));
1521
1522     qname->str = prefix->str ? prefix->str : local->str;
1523     /* count ':' too */
1524     qname->len = (prefix->len ? prefix->len + 1 : 0) + local->len;
1525
1526     return S_OK;
1527 }
1528
1529 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
1530    [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
1531 static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *local, strval *qname, int *empty)
1532 {
1533     static const WCHAR endW[] = {'/','>',0};
1534     HRESULT hr;
1535
1536     /* skip '<' */
1537     reader_skipn(reader, 1);
1538
1539     hr = reader_parse_qname(reader, prefix, local, qname);
1540     if (FAILED(hr)) return hr;
1541
1542     reader_skipspaces(reader);
1543
1544     /* empty element */
1545     if ((*empty = !reader_cmp(reader, endW)))
1546     {
1547         /* skip '/>' */
1548         reader_skipn(reader, 2);
1549         return S_OK;
1550     }
1551
1552     /* got a start tag */
1553     if (!reader_cmp(reader, gtW))
1554     {
1555         /* skip '>' */
1556         reader_skipn(reader, 1);
1557         return reader_push_element(reader, qname);
1558     }
1559
1560     FIXME("only empty elements/start tags without attribute list supported\n");
1561     return E_NOTIMPL;
1562 }
1563
1564 /* [39] element ::= EmptyElemTag | STag content ETag */
1565 static HRESULT reader_parse_element(xmlreader *reader)
1566 {
1567     strval qname, prefix, local;
1568     HRESULT hr;
1569     int empty;
1570
1571     /* check if we are really on element */
1572     if (reader_cmp(reader, ltW)) return S_FALSE;
1573     reader_shrink(reader);
1574
1575     /* this handles empty elements too */
1576     empty = 0;
1577     hr = reader_parse_stag(reader, &prefix, &local, &qname, &empty);
1578     if (FAILED(hr)) return hr;
1579
1580     /* FIXME: need to check for defined namespace to reject invalid prefix,
1581        currently reject all prefixes */
1582     if (prefix.len) return NC_E_UNDECLAREDPREFIX;
1583
1584     /* if we got empty element and stack is empty go straight to Misc */
1585     if (empty && list_empty(&reader->elements))
1586         reader->instate = XmlReadInState_MiscEnd;
1587     else
1588         reader->instate = XmlReadInState_Content;
1589
1590     reader->nodetype = XmlNodeType_Element;
1591     reader_set_strvalue(reader, StringValue_LocalName, &local);
1592     reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
1593
1594     return hr;
1595 }
1596
1597 /* [13 NS] ETag ::= '</' QName S? '>' */
1598 static HRESULT reader_parse_endtag(xmlreader *reader)
1599 {
1600     strval prefix, local, qname;
1601     struct element *elem;
1602     HRESULT hr;
1603
1604     /* skip '</' */
1605     reader_skipn(reader, 2);
1606
1607     hr = reader_parse_qname(reader, &prefix, &local, &qname);
1608     if (FAILED(hr)) return hr;
1609
1610     reader_skipspaces(reader);
1611
1612     if (reader_cmp(reader, gtW)) return WC_E_GREATERTHAN;
1613
1614     /* skip '>' */
1615     reader_skipn(reader, 1);
1616
1617     /* Element stack should never be empty at this point, cause we shouldn't get to
1618        content parsing if it's empty. */
1619     elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
1620     if (!strval_eq(&elem->qname, &qname)) return WC_E_ELEMENTMATCH;
1621
1622     reader_pop_element(reader);
1623
1624     reader->nodetype = XmlNodeType_EndElement;
1625     reader_set_strvalue(reader, StringValue_LocalName, &local);
1626     reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
1627
1628     return S_OK;
1629 }
1630
1631 /* [18] CDSect ::= CDStart CData CDEnd
1632    [19] CDStart ::= '<![CDATA['
1633    [20] CData ::= (Char* - (Char* ']]>' Char*))
1634    [21] CDEnd ::= ']]>' */
1635 static HRESULT reader_parse_cdata(xmlreader *reader)
1636 {
1637     FIXME("CDATA sections are not supported\n");
1638     return E_NOTIMPL;
1639 }
1640
1641 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1642    [67] Reference ::= EntityRef | CharRef
1643    [68] EntityRef ::= '&' Name ';' */
1644 static HRESULT reader_parse_reference(xmlreader *reader)
1645 {
1646     FIXME("References not supported\n");
1647     return E_NOTIMPL;
1648 }
1649
1650 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1651 static HRESULT reader_parse_chardata(xmlreader *reader)
1652 {
1653     FIXME("CharData not supported\n");
1654     return E_NOTIMPL;
1655 }
1656
1657 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1658 static HRESULT reader_parse_content(xmlreader *reader)
1659 {
1660     static const WCHAR cdstartW[] = {'<','!','[','C','D','A','T','A','[',0};
1661     static const WCHAR etagW[] = {'<','/',0};
1662     static const WCHAR ampW[] = {'&',0};
1663
1664     reader_shrink(reader);
1665
1666     /* handle end tag here, it indicates end of content as well */
1667     if (!reader_cmp(reader, etagW))
1668         return reader_parse_endtag(reader);
1669
1670     if (!reader_cmp(reader, commentW))
1671         return reader_parse_comment(reader);
1672
1673     if (!reader_cmp(reader, piW))
1674         return reader_parse_pi(reader);
1675
1676     if (!reader_cmp(reader, cdstartW))
1677         return reader_parse_cdata(reader);
1678
1679     if (!reader_cmp(reader, ampW))
1680         return reader_parse_reference(reader);
1681
1682     if (!reader_cmp(reader, ltW))
1683         return reader_parse_element(reader);
1684
1685     /* what's left must be CharData */
1686     return reader_parse_chardata(reader);
1687 }
1688
1689 static HRESULT reader_parse_nextnode(xmlreader *reader)
1690 {
1691     HRESULT hr;
1692
1693     while (1)
1694     {
1695         switch (reader->instate)
1696         {
1697         /* if it's a first call for a new input we need to detect stream encoding */
1698         case XmlReadInState_Initial:
1699             {
1700                 xml_encoding enc;
1701
1702                 hr = readerinput_growraw(reader->input);
1703                 if (FAILED(hr)) return hr;
1704
1705                 /* try to detect encoding by BOM or data and set input code page */
1706                 hr = readerinput_detectencoding(reader->input, &enc);
1707                 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
1708                 if (FAILED(hr)) return hr;
1709
1710                 /* always switch first time cause we have to put something in */
1711                 readerinput_switchencoding(reader->input, enc);
1712
1713                 /* parse xml declaration */
1714                 hr = reader_parse_xmldecl(reader);
1715                 if (FAILED(hr)) return hr;
1716
1717                 readerinput_shrinkraw(reader->input, -1);
1718                 reader->instate = XmlReadInState_Misc_DTD;
1719                 if (hr == S_OK) return hr;
1720             }
1721             break;
1722         case XmlReadInState_Misc_DTD:
1723             hr = reader_parse_misc(reader);
1724             if (FAILED(hr)) return hr;
1725
1726             if (hr == S_FALSE)
1727                 reader->instate = XmlReadInState_DTD;
1728             else
1729                 return hr;
1730             break;
1731         case XmlReadInState_DTD:
1732             hr = reader_parse_dtd(reader);
1733             if (FAILED(hr)) return hr;
1734
1735             if (hr == S_OK)
1736             {
1737                 reader->instate = XmlReadInState_DTD_Misc;
1738                 return hr;
1739             }
1740             else
1741                 reader->instate = XmlReadInState_Element;
1742             break;
1743         case XmlReadInState_DTD_Misc:
1744             hr = reader_parse_misc(reader);
1745             if (FAILED(hr)) return hr;
1746
1747             if (hr == S_FALSE)
1748                 reader->instate = XmlReadInState_Element;
1749             else
1750                 return hr;
1751             break;
1752         case XmlReadInState_Element:
1753             return reader_parse_element(reader);
1754         case XmlReadInState_Content:
1755             return reader_parse_content(reader);
1756         default:
1757             FIXME("internal state %d not handled\n", reader->instate);
1758             return E_NOTIMPL;
1759         }
1760     }
1761
1762     return E_NOTIMPL;
1763 }
1764
1765 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
1766 {
1767     xmlreader *This = impl_from_IXmlReader(iface);
1768
1769     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1770
1771     if (IsEqualGUID(riid, &IID_IUnknown) ||
1772         IsEqualGUID(riid, &IID_IXmlReader))
1773     {
1774         *ppvObject = iface;
1775     }
1776     else
1777     {
1778         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1779         *ppvObject = NULL;
1780         return E_NOINTERFACE;
1781     }
1782
1783     IXmlReader_AddRef(iface);
1784
1785     return S_OK;
1786 }
1787
1788 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
1789 {
1790     xmlreader *This = impl_from_IXmlReader(iface);
1791     ULONG ref = InterlockedIncrement(&This->ref);
1792     TRACE("(%p)->(%d)\n", This, ref);
1793     return ref;
1794 }
1795
1796 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
1797 {
1798     xmlreader *This = impl_from_IXmlReader(iface);
1799     LONG ref = InterlockedDecrement(&This->ref);
1800
1801     TRACE("(%p)->(%d)\n", This, ref);
1802
1803     if (ref == 0)
1804     {
1805         IMalloc *imalloc = This->imalloc;
1806         if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
1807         reader_clear_attrs(This);
1808         reader_clear_elements(This);
1809         reader_free_strvalues(This);
1810         reader_free(This, This);
1811         if (imalloc) IMalloc_Release(imalloc);
1812     }
1813
1814     return ref;
1815 }
1816
1817 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
1818 {
1819     xmlreader *This = impl_from_IXmlReader(iface);
1820     IXmlReaderInput *readerinput;
1821     HRESULT hr;
1822
1823     TRACE("(%p)->(%p)\n", This, input);
1824
1825     if (This->input)
1826     {
1827         readerinput_release_stream(This->input);
1828         IUnknown_Release(&This->input->IXmlReaderInput_iface);
1829         This->input = NULL;
1830     }
1831
1832     This->line = This->pos = 0;
1833     reader_clear_elements(This);
1834     This->depth = 0;
1835     This->save = NULL;
1836
1837     /* just reset current input */
1838     if (!input)
1839     {
1840         This->state = XmlReadState_Initial;
1841         return S_OK;
1842     }
1843
1844     /* now try IXmlReaderInput, ISequentialStream, IStream */
1845     hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&readerinput);
1846     if (hr == S_OK)
1847     {
1848         if (readerinput->lpVtbl == &xmlreaderinputvtbl)
1849             This->input = impl_from_IXmlReaderInput(readerinput);
1850         else
1851         {
1852             ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
1853                 readerinput, readerinput->lpVtbl);
1854             IUnknown_Release(readerinput);
1855             return E_FAIL;
1856
1857         }
1858     }
1859
1860     if (hr != S_OK || !readerinput)
1861     {
1862         /* create IXmlReaderInput basing on supplied interface */
1863         hr = CreateXmlReaderInputWithEncodingName(input,
1864                                          NULL, NULL, FALSE, NULL, &readerinput);
1865         if (hr != S_OK) return hr;
1866         This->input = impl_from_IXmlReaderInput(readerinput);
1867     }
1868
1869     /* set stream for supplied IXmlReaderInput */
1870     hr = readerinput_query_for_stream(This->input);
1871     if (hr == S_OK)
1872     {
1873         This->state = XmlReadState_Initial;
1874         This->instate = XmlReadInState_Initial;
1875     }
1876
1877     return hr;
1878 }
1879
1880 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
1881 {
1882     xmlreader *This = impl_from_IXmlReader(iface);
1883
1884     TRACE("(%p %u %p)\n", This, property, value);
1885
1886     if (!value) return E_INVALIDARG;
1887
1888     switch (property)
1889     {
1890         case XmlReaderProperty_DtdProcessing:
1891             *value = This->dtdmode;
1892             break;
1893         case XmlReaderProperty_ReadState:
1894             *value = This->state;
1895             break;
1896         default:
1897             FIXME("Unimplemented property (%u)\n", property);
1898             return E_NOTIMPL;
1899     }
1900
1901     return S_OK;
1902 }
1903
1904 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
1905 {
1906     xmlreader *This = impl_from_IXmlReader(iface);
1907
1908     TRACE("(%p %u %lu)\n", iface, property, value);
1909
1910     switch (property)
1911     {
1912         case XmlReaderProperty_DtdProcessing:
1913             if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
1914             This->dtdmode = value;
1915             break;
1916         default:
1917             FIXME("Unimplemented property (%u)\n", property);
1918             return E_NOTIMPL;
1919     }
1920
1921     return S_OK;
1922 }
1923
1924 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
1925 {
1926     xmlreader *This = impl_from_IXmlReader(iface);
1927     XmlNodeType oldtype = This->nodetype;
1928     HRESULT hr;
1929
1930     TRACE("(%p)->(%p)\n", This, nodetype);
1931
1932     if (This->state == XmlReadState_Closed) return S_FALSE;
1933
1934     hr = reader_parse_nextnode(This);
1935     if (oldtype == XmlNodeType_None && This->nodetype != oldtype)
1936         This->state = XmlReadState_Interactive;
1937     if (hr == S_OK) *nodetype = This->nodetype;
1938
1939     return hr;
1940 }
1941
1942 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
1943 {
1944     xmlreader *This = impl_from_IXmlReader(iface);
1945     TRACE("(%p)->(%p)\n", This, node_type);
1946
1947     /* When we're on attribute always return attribute type, container node type is kept.
1948        Note that container is not necessarily an element, and attribute doesn't mean it's
1949        an attribute in XML spec terms. */
1950     *node_type = This->attr ? XmlNodeType_Attribute : This->nodetype;
1951     return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
1952 }
1953
1954 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
1955 {
1956     xmlreader *This = impl_from_IXmlReader(iface);
1957
1958     TRACE("(%p)\n", This);
1959
1960     if (!This->attr_count) return S_FALSE;
1961     This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
1962     return S_OK;
1963 }
1964
1965 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
1966 {
1967     xmlreader *This = impl_from_IXmlReader(iface);
1968     const struct list *next;
1969
1970     TRACE("(%p)\n", This);
1971
1972     if (!This->attr_count) return S_FALSE;
1973
1974     if (!This->attr)
1975         return IXmlReader_MoveToFirstAttribute(iface);
1976
1977     next = list_next(&This->attrs, &This->attr->entry);
1978     if (next)
1979         This->attr = LIST_ENTRY(next, struct attribute, entry);
1980
1981     return next ? S_OK : S_FALSE;
1982 }
1983
1984 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
1985                                                       LPCWSTR local_name,
1986                                                       LPCWSTR namespaceUri)
1987 {
1988     FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
1989     return E_NOTIMPL;
1990 }
1991
1992 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
1993 {
1994     xmlreader *This = impl_from_IXmlReader(iface);
1995
1996     TRACE("(%p)\n", This);
1997
1998     if (!This->attr_count) return S_FALSE;
1999     This->attr = NULL;
2000     return S_OK;
2001 }
2002
2003 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2004 {
2005     xmlreader *This = impl_from_IXmlReader(iface);
2006
2007     TRACE("(%p)->(%p %p)\n", This, name, len);
2008     *name = This->strvalues[StringValue_QualifiedName].str;
2009     *len  = This->strvalues[StringValue_QualifiedName].len;
2010     return S_OK;
2011 }
2012
2013 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
2014                                                 LPCWSTR *namespaceUri,
2015                                                 UINT *namespaceUri_length)
2016 {
2017     FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
2018     return E_NOTIMPL;
2019 }
2020
2021 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2022 {
2023     xmlreader *This = impl_from_IXmlReader(iface);
2024
2025     TRACE("(%p)->(%p %p)\n", This, name, len);
2026     *name = This->strvalues[StringValue_LocalName].str;
2027     *len  = This->strvalues[StringValue_LocalName].len;
2028     return S_OK;
2029 }
2030
2031 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
2032                                           LPCWSTR *prefix,
2033                                           UINT *prefix_length)
2034 {
2035     FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
2036     return E_NOTIMPL;
2037 }
2038
2039 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, LPCWSTR *value, UINT *len)
2040 {
2041     xmlreader *This = impl_from_IXmlReader(iface);
2042
2043     TRACE("(%p)->(%p %p)\n", This, value, len);
2044
2045     if ((This->nodetype == XmlNodeType_Comment && !This->strvalues[StringValue_Value].str) ||
2046         is_reader_pending(This))
2047     {
2048         XmlNodeType type;
2049         HRESULT hr;
2050
2051         hr = IXmlReader_Read(iface, &type);
2052         if (FAILED(hr)) return hr;
2053
2054         /* return if still pending, partially read values are not reported */
2055         if (is_reader_pending(This)) return E_PENDING;
2056     }
2057
2058     *value = This->strvalues[StringValue_Value].str;
2059     if (len) *len = This->strvalues[StringValue_Value].len;
2060     return S_OK;
2061 }
2062
2063 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
2064                                                WCHAR *buffer,
2065                                                UINT   chunk_size,
2066                                                UINT  *read)
2067 {
2068     FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
2069     return E_NOTIMPL;
2070 }
2071
2072 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
2073                                            LPCWSTR *baseUri,
2074                                            UINT *baseUri_length)
2075 {
2076     FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
2077     return E_NOTIMPL;
2078 }
2079
2080 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
2081 {
2082     FIXME("(%p): stub\n", iface);
2083     return E_NOTIMPL;
2084 }
2085
2086 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
2087 {
2088     FIXME("(%p): stub\n", iface);
2089     return E_NOTIMPL;
2090 }
2091
2092 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
2093 {
2094     xmlreader *This = impl_from_IXmlReader(iface);
2095
2096     TRACE("(%p %p)\n", This, lineNumber);
2097
2098     if (!lineNumber) return E_INVALIDARG;
2099
2100     *lineNumber = This->line;
2101
2102     return S_OK;
2103 }
2104
2105 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
2106 {
2107     xmlreader *This = impl_from_IXmlReader(iface);
2108
2109     TRACE("(%p %p)\n", This, linePosition);
2110
2111     if (!linePosition) return E_INVALIDARG;
2112
2113     *linePosition = This->pos;
2114
2115     return S_OK;
2116 }
2117
2118 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
2119 {
2120     xmlreader *This = impl_from_IXmlReader(iface);
2121
2122     TRACE("(%p)->(%p)\n", This, count);
2123
2124     if (!count) return E_INVALIDARG;
2125
2126     *count = This->attr_count;
2127     return S_OK;
2128 }
2129
2130 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
2131 {
2132     xmlreader *This = impl_from_IXmlReader(iface);
2133     TRACE("(%p)->(%p)\n", This, depth);
2134     *depth = This->depth;
2135     return S_OK;
2136 }
2137
2138 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
2139 {
2140     FIXME("(%p): stub\n", iface);
2141     return E_NOTIMPL;
2142 }
2143
2144 static const struct IXmlReaderVtbl xmlreader_vtbl =
2145 {
2146     xmlreader_QueryInterface,
2147     xmlreader_AddRef,
2148     xmlreader_Release,
2149     xmlreader_SetInput,
2150     xmlreader_GetProperty,
2151     xmlreader_SetProperty,
2152     xmlreader_Read,
2153     xmlreader_GetNodeType,
2154     xmlreader_MoveToFirstAttribute,
2155     xmlreader_MoveToNextAttribute,
2156     xmlreader_MoveToAttributeByName,
2157     xmlreader_MoveToElement,
2158     xmlreader_GetQualifiedName,
2159     xmlreader_GetNamespaceUri,
2160     xmlreader_GetLocalName,
2161     xmlreader_GetPrefix,
2162     xmlreader_GetValue,
2163     xmlreader_ReadValueChunk,
2164     xmlreader_GetBaseUri,
2165     xmlreader_IsDefault,
2166     xmlreader_IsEmptyElement,
2167     xmlreader_GetLineNumber,
2168     xmlreader_GetLinePosition,
2169     xmlreader_GetAttributeCount,
2170     xmlreader_GetDepth,
2171     xmlreader_IsEOF
2172 };
2173
2174 /** IXmlReaderInput **/
2175 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
2176 {
2177     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2178
2179     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
2180
2181     if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
2182         IsEqualGUID(riid, &IID_IUnknown))
2183     {
2184         *ppvObject = iface;
2185     }
2186     else
2187     {
2188         WARN("interface %s not implemented\n", debugstr_guid(riid));
2189         *ppvObject = NULL;
2190         return E_NOINTERFACE;
2191     }
2192
2193     IUnknown_AddRef(iface);
2194
2195     return S_OK;
2196 }
2197
2198 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
2199 {
2200     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2201     ULONG ref = InterlockedIncrement(&This->ref);
2202     TRACE("(%p)->(%d)\n", This, ref);
2203     return ref;
2204 }
2205
2206 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
2207 {
2208     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2209     LONG ref = InterlockedDecrement(&This->ref);
2210
2211     TRACE("(%p)->(%d)\n", This, ref);
2212
2213     if (ref == 0)
2214     {
2215         IMalloc *imalloc = This->imalloc;
2216         if (This->input) IUnknown_Release(This->input);
2217         if (This->stream) ISequentialStream_Release(This->stream);
2218         if (This->buffer) free_input_buffer(This->buffer);
2219         readerinput_free(This, This->baseuri);
2220         readerinput_free(This, This);
2221         if (imalloc) IMalloc_Release(imalloc);
2222     }
2223
2224     return ref;
2225 }
2226
2227 static const struct IUnknownVtbl xmlreaderinputvtbl =
2228 {
2229     xmlreaderinput_QueryInterface,
2230     xmlreaderinput_AddRef,
2231     xmlreaderinput_Release
2232 };
2233
2234 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
2235 {
2236     xmlreader *reader;
2237     int i;
2238
2239     TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
2240
2241     if (!IsEqualGUID(riid, &IID_IXmlReader))
2242     {
2243         ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
2244         return E_FAIL;
2245     }
2246
2247     if (imalloc)
2248         reader = IMalloc_Alloc(imalloc, sizeof(*reader));
2249     else
2250         reader = heap_alloc(sizeof(*reader));
2251     if(!reader) return E_OUTOFMEMORY;
2252
2253     reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
2254     reader->ref = 1;
2255     reader->input = NULL;
2256     reader->state = XmlReadState_Closed;
2257     reader->instate = XmlReadInState_Initial;
2258     reader->dtdmode = DtdProcessing_Prohibit;
2259     reader->line  = reader->pos = 0;
2260     reader->imalloc = imalloc;
2261     if (imalloc) IMalloc_AddRef(imalloc);
2262     reader->nodetype = XmlNodeType_None;
2263     list_init(&reader->attrs);
2264     reader->attr_count = 0;
2265     reader->attr = NULL;
2266     list_init(&reader->elements);
2267     reader->depth = 0;
2268     reader->save = NULL;
2269
2270     for (i = 0; i < StringValue_Last; i++)
2271         reader->strvalues[i] = strval_empty;
2272
2273     *obj = &reader->IXmlReader_iface;
2274
2275     TRACE("returning iface %p\n", *obj);
2276
2277     return S_OK;
2278 }
2279
2280 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
2281                                                     IMalloc *imalloc,
2282                                                     LPCWSTR encoding,
2283                                                     BOOL hint,
2284                                                     LPCWSTR base_uri,
2285                                                     IXmlReaderInput **ppInput)
2286 {
2287     xmlreaderinput *readerinput;
2288     HRESULT hr;
2289
2290     TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
2291                                        hint, wine_dbgstr_w(base_uri), ppInput);
2292
2293     if (!stream || !ppInput) return E_INVALIDARG;
2294
2295     if (imalloc)
2296         readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
2297     else
2298         readerinput = heap_alloc(sizeof(*readerinput));
2299     if(!readerinput) return E_OUTOFMEMORY;
2300
2301     readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinputvtbl;
2302     readerinput->ref = 1;
2303     readerinput->imalloc = imalloc;
2304     readerinput->stream = NULL;
2305     if (imalloc) IMalloc_AddRef(imalloc);
2306     readerinput->encoding = parse_encoding_name(encoding, -1);
2307     readerinput->hint = hint;
2308     readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
2309     readerinput->pending = 0;
2310
2311     hr = alloc_input_buffer(readerinput);
2312     if (hr != S_OK)
2313     {
2314         readerinput_free(readerinput, readerinput->baseuri);
2315         readerinput_free(readerinput, readerinput);
2316         if (imalloc) IMalloc_Release(imalloc);
2317         return hr;
2318     }
2319     IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
2320
2321     *ppInput = &readerinput->IXmlReaderInput_iface;
2322
2323     TRACE("returning iface %p\n", *ppInput);
2324
2325     return S_OK;
2326 }