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