2 * IXmlReader implementation
4 * Copyright 2010, 2012-2013 Nikolay Sivov
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.
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.
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
29 #include "xmllite_private.h"
31 #include "wine/debug.h"
32 #include "wine/list.h"
33 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
37 /* not defined in public headers */
38 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
49 XmlReadInState_Initial,
50 XmlReadInState_XmlDecl,
51 XmlReadInState_Misc_DTD,
53 XmlReadInState_DTD_Misc,
54 XmlReadInState_Element,
55 XmlReadInState_Content,
56 XmlReadInState_MiscEnd
57 } XmlReaderInternalState;
59 /* This state denotes where parsing was interrupted by input problem.
60 Reader resumes parsing using this information. */
63 XmlReadResumeState_Initial,
64 XmlReadResumeState_PITarget,
65 XmlReadResumeState_PIBody,
66 XmlReadResumeState_CDATA,
67 XmlReadResumeState_Comment,
68 XmlReadResumeState_STag
69 } XmlReaderResumeState;
71 /* saved pointer index to resume from particular input position */
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 */
82 StringValue_LocalName,
83 StringValue_QualifiedName,
86 } XmlReaderStringValue;
88 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
89 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
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};
98 struct xml_encoding_data
105 static const struct xml_encoding_data xml_encoding_map[] = {
106 { utf16W, XmlEncoding_UTF16, ~0 },
107 { utf8W, XmlEncoding_UTF8, CP_UTF8 }
114 unsigned int allocated;
115 unsigned int written;
118 typedef struct input_buffer input_buffer;
122 IXmlReaderInput IXmlReaderInput_iface;
124 /* reference passed on IXmlReaderInput creation, is kept when input is created */
127 xml_encoding encoding;
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;
138 static const struct IUnknownVtbl xmlreaderinputvtbl;
140 /* Structure to hold parsed string of specific length.
142 Reader stores node value as 'start' pointer, on request
143 a null-terminated version of it is allocated.
145 To init a strval variable use reader_init_strval(),
146 to set strval as a reader value use reader_set_strval().
150 WCHAR *start; /* input position where value starts */
151 UINT len; /* length in WCHARs, altered after ReadValueChunk */
152 WCHAR *str; /* allocated null-terminated string */
155 static WCHAR emptyW[] = {0};
156 static const strval strval_empty = {emptyW, 0, emptyW};
173 IXmlReader IXmlReader_iface;
175 xmlreaderinput *input;
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 */
186 struct list elements;
187 strval strvalues[StringValue_Last];
189 WCHAR *resume[XmlReadResume_Last]; /* pointers used to resume reader */
194 encoded_buffer utf16;
195 encoded_buffer encoded;
197 xmlreaderinput *input;
200 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
202 return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
205 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
207 return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
210 static inline void *m_alloc(IMalloc *imalloc, size_t len)
213 return IMalloc_Alloc(imalloc, len);
215 return heap_alloc(len);
218 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
221 return IMalloc_Realloc(imalloc, mem, len);
223 return heap_realloc(mem, len);
226 static inline void m_free(IMalloc *imalloc, void *mem)
229 IMalloc_Free(imalloc, mem);
234 /* reader memory allocation functions */
235 static inline void *reader_alloc(xmlreader *reader, size_t len)
237 return m_alloc(reader->imalloc, len);
240 static inline void reader_free(xmlreader *reader, void *mem)
242 m_free(reader->imalloc, mem);
245 static HRESULT reader_strvaldup(xmlreader *reader, const strval *src, strval *dest)
249 if (src->str != strval_empty.str)
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;
260 /* reader input memory allocation functions */
261 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
263 return m_alloc(input->imalloc, len);
266 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
268 return m_realloc(input->imalloc, mem, len);
271 static inline void readerinput_free(xmlreaderinput *input, void *mem)
273 m_free(input->imalloc, mem);
276 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
283 size = (strlenW(str)+1)*sizeof(WCHAR);
284 ret = readerinput_alloc(input, size);
285 if (ret) memcpy(ret, str, size);
291 static void reader_clear_attrs(xmlreader *reader)
293 struct attribute *attr, *attr2;
294 LIST_FOR_EACH_ENTRY_SAFE(attr, attr2, &reader->attrs, struct attribute, entry)
296 reader_free(reader, attr);
298 list_init(&reader->attrs);
299 reader->attr_count = 0;
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)
306 struct attribute *attr;
308 attr = reader_alloc(reader, sizeof(*attr));
309 if (!attr) return E_OUTOFMEMORY;
311 attr->localname = *localname;
312 attr->value = *value;
313 list_add_tail(&reader->attrs, &attr->entry);
314 reader->attr_count++;
319 /* This one frees stored string value if needed */
320 static void reader_free_strvalued(xmlreader *reader, strval *v)
322 if (v->str != strval_empty.str)
324 reader_free(reader, v->str);
329 static inline void reader_init_strvalue(WCHAR *str, UINT len, strval *v)
331 v->start = v->str = str;
335 static void reader_free_strvalue(xmlreader *reader, XmlReaderStringValue type)
337 reader_free_strvalued(reader, &reader->strvalues[type]);
340 static void reader_free_strvalues(xmlreader *reader)
343 for (type = 0; type < StringValue_Last; type++)
344 reader_free_strvalue(reader, type);
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)
351 if (str1->len != str2->len) return 0;
352 return !memcmp(str1->str, str2->str, str1->len*sizeof(WCHAR));
355 static void reader_clear_elements(xmlreader *reader)
357 struct element *elem, *elem2;
358 LIST_FOR_EACH_ENTRY_SAFE(elem, elem2, &reader->elements, struct element, entry)
360 reader_free_strvalued(reader, &elem->qname);
361 reader_free(reader, elem);
363 list_init(&reader->elements);
366 static HRESULT reader_inc_depth(xmlreader *reader)
368 /* FIXME: handle XmlReaderProperty_MaxElementDepth property */
373 static HRESULT reader_push_element(xmlreader *reader, strval *qname)
375 struct element *elem;
378 elem = reader_alloc(reader, sizeof(*elem));
379 if (!elem) return E_OUTOFMEMORY;
381 hr = reader_strvaldup(reader, qname, &elem->qname);
382 if (FAILED(hr)) return hr;
384 if (!list_empty(&reader->elements))
386 hr = reader_inc_depth(reader);
387 if (FAILED(hr)) return hr;
390 list_add_head(&reader->elements, &elem->entry);
394 static void reader_pop_element(xmlreader *reader)
396 struct element *elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
400 list_remove(&elem->entry);
401 reader_free_strvalued(reader, &elem->qname);
402 reader_free(reader, elem);
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)
410 strval *v = &reader->strvalues[type];
412 reader_free_strvalue(reader, type);
421 if (value->str == strval_empty.str)
425 if (type == StringValue_Value)
427 /* defer allocation for value string */
429 v->start = value->start;
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;
442 static inline int is_reader_pending(xmlreader *reader)
444 return reader->input->pending;
447 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
449 const int initial_len = 0x2000;
450 buffer->data = readerinput_alloc(input, initial_len);
451 if (!buffer->data) return E_OUTOFMEMORY;
453 memset(buffer->data, 0, 4);
454 buffer->cur = buffer->data;
455 buffer->allocated = initial_len;
461 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
463 readerinput_free(input, buffer->data);
466 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
468 if (encoding == XmlEncoding_Unknown)
470 FIXME("unsupported encoding %d\n", encoding);
474 *cp = xml_encoding_map[encoding].cp;
479 static xml_encoding parse_encoding_name(const WCHAR *name, int len)
483 if (!name) return XmlEncoding_Unknown;
486 max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
493 c = strncmpiW(xml_encoding_map[n].name, name, len);
495 c = strcmpiW(xml_encoding_map[n].name, name);
497 return xml_encoding_map[n].enc;
505 return XmlEncoding_Unknown;
508 static HRESULT alloc_input_buffer(xmlreaderinput *input)
510 input_buffer *buffer;
513 input->buffer = NULL;
515 buffer = readerinput_alloc(input, sizeof(*buffer));
516 if (!buffer) return E_OUTOFMEMORY;
518 buffer->input = input;
519 buffer->code_page = ~0; /* code page is unknown at this point */
520 hr = init_encoded_buffer(input, &buffer->utf16);
522 readerinput_free(input, buffer);
526 hr = init_encoded_buffer(input, &buffer->encoded);
528 free_encoded_buffer(input, &buffer->utf16);
529 readerinput_free(input, buffer);
533 input->buffer = buffer;
537 static void free_input_buffer(input_buffer *buffer)
539 free_encoded_buffer(buffer->input, &buffer->encoded);
540 free_encoded_buffer(buffer->input, &buffer->utf16);
541 readerinput_free(buffer->input, buffer);
544 static void readerinput_release_stream(xmlreaderinput *readerinput)
546 if (readerinput->stream) {
547 ISequentialStream_Release(readerinput->stream);
548 readerinput->stream = NULL;
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)
558 readerinput_release_stream(readerinput);
559 hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
561 hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
566 /* reads a chunk to raw buffer */
567 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
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;
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)
581 buffer->allocated *= 2;
582 buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
583 len = buffer->allocated - buffer->written;
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;
596 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
597 static void readerinput_grow(xmlreaderinput *readerinput, int length)
599 encoded_buffer *buffer = &readerinput->buffer->utf16;
601 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
602 if (buffer->allocated < buffer->written + length + 4)
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;
610 static inline int readerinput_is_utf8(xmlreaderinput *readerinput)
612 static char startA[] = {'<','?'};
613 static char commentA[] = {'<','!'};
614 encoded_buffer *buffer = &readerinput->buffer->encoded;
615 unsigned char *ptr = (unsigned char*)buffer->data;
617 return !memcmp(buffer->data, startA, sizeof(startA)) ||
618 !memcmp(buffer->data, commentA, sizeof(commentA)) ||
619 /* test start byte */
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 */
629 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
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};
637 *enc = XmlEncoding_Unknown;
639 if (buffer->written <= 3)
641 HRESULT hr = readerinput_growraw(readerinput);
642 if (FAILED(hr)) return hr;
643 if (buffer->written <= 3) return MX_E_INPUTEND;
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)))
656 buffer->cur += sizeof(utf8bom);
657 *enc = XmlEncoding_UTF8;
659 else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
661 buffer->cur += sizeof(utf16lebom);
662 *enc = XmlEncoding_UTF16;
668 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
670 encoded_buffer *buffer = &readerinput->buffer->encoded;
671 int len = buffer->written;
673 /* complete single byte char */
674 if (!(buffer->data[len-1] & 0x80)) return len;
676 /* find start byte of multibyte char */
677 while (--len && !(buffer->data[len] & 0xc0))
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
686 static int readerinput_get_convlen(xmlreaderinput *readerinput)
688 encoded_buffer *buffer = &readerinput->buffer->encoded;
691 if (readerinput->buffer->code_page == CP_UTF8)
692 len = readerinput_get_utf8_convlen(readerinput);
694 len = buffer->written;
696 TRACE("%d\n", len - (int)(buffer->cur - buffer->data));
697 return len - (buffer->cur - buffer->data);
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)
705 encoded_buffer *buffer = &readerinput->buffer->encoded;
708 len = readerinput_get_convlen(readerinput);
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;
718 /* note that raw buffer content is kept */
719 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
721 encoded_buffer *src = &readerinput->buffer->encoded;
722 encoded_buffer *dest = &readerinput->buffer->utf16;
728 hr = get_code_page(enc, &cp);
729 if (FAILED(hr)) return;
731 readerinput->buffer->code_page = cp;
732 len = readerinput_get_convlen(readerinput);
734 TRACE("switching to cp %d\n", cp);
736 /* just copy in this case */
737 if (enc == XmlEncoding_UTF16)
739 readerinput_grow(readerinput, len);
740 memcpy(dest->data, src->cur, len);
741 dest->written += len*sizeof(WCHAR);
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);
750 dest->written += dest_len*sizeof(WCHAR);
753 /* shrinks parsed data a buffer begins with */
754 static void reader_shrink(xmlreader *reader)
756 encoded_buffer *buffer = &reader->input->buffer->utf16;
758 /* avoid to move too often using threshold shrink length */
759 if (buffer->cur - buffer->data > buffer->written / 2)
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;
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)
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;
780 /* get some raw data from stream first */
781 hr = readerinput_growraw(readerinput);
782 len = readerinput_get_convlen(readerinput);
784 /* just copy for UTF-16 case */
787 readerinput_grow(readerinput, len);
788 memcpy(dest->data, src->cur, len);
789 dest->written += len*sizeof(WCHAR);
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);
798 dest->written += dest_len*sizeof(WCHAR);
799 /* get rid of processed data */
800 readerinput_shrinkraw(readerinput, len);
805 static inline WCHAR *reader_get_cur(xmlreader *reader)
807 WCHAR *ptr = (WCHAR*)reader->input->buffer->utf16.cur;
808 if (!*ptr) reader_more(reader);
812 static int reader_cmp(xmlreader *reader, const WCHAR *str)
814 const WCHAR *ptr = reader_get_cur(reader);
815 return strncmpW(str, ptr, strlenW(str));
818 /* moves cursor n WCHARs forward */
819 static void reader_skipn(xmlreader *reader, int n)
821 encoded_buffer *buffer = &reader->input->buffer->utf16;
822 const WCHAR *ptr = reader_get_cur(reader);
824 while (*ptr++ && n--)
826 buffer->cur += sizeof(WCHAR);
831 static inline int is_wchar_space(WCHAR ch)
833 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
836 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
837 static int reader_skipspaces(xmlreader *reader)
839 encoded_buffer *buffer = &reader->input->buffer->utf16;
840 const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
842 while (is_wchar_space(*ptr))
844 buffer->cur += sizeof(WCHAR);
847 else if (*ptr == '\n')
860 /* [26] VersionNum ::= '1.' [0-9]+ */
861 static HRESULT reader_parse_versionnum(xmlreader *reader, strval *val)
863 WCHAR *ptr, *ptr2, *start = reader_get_cur(reader);
864 static const WCHAR onedotW[] = {'1','.',0};
866 if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
868 reader_skipn(reader, 2);
870 ptr2 = ptr = reader_get_cur(reader);
871 while (*ptr >= '0' && *ptr <= '9')
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);
881 /* [25] Eq ::= S? '=' S? */
882 static HRESULT reader_parse_eq(xmlreader *reader)
884 static const WCHAR eqW[] = {'=',0};
885 reader_skipspaces(reader);
886 if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
888 reader_skipn(reader, 1);
889 reader_skipspaces(reader);
893 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
894 static HRESULT reader_parse_versioninfo(xmlreader *reader)
896 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
900 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
902 if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
903 reader_init_strvalue(reader_get_cur(reader), 7, &name);
905 reader_skipn(reader, 7);
907 hr = reader_parse_eq(reader);
908 if (FAILED(hr)) return hr;
910 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
913 reader_skipn(reader, 1);
915 hr = reader_parse_versionnum(reader, &val);
916 if (FAILED(hr)) return hr;
918 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
922 reader_skipn(reader, 1);
924 return reader_add_attr(reader, &name, &val);
927 /* ([A-Za-z0-9._] | '-') */
928 static inline int is_wchar_encname(WCHAR ch)
930 return ((ch >= 'A' && ch <= 'Z') ||
931 (ch >= 'a' && ch <= 'z') ||
932 (ch >= '0' && ch <= '9') ||
933 (ch == '.') || (ch == '_') ||
937 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
938 static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
940 WCHAR *start = reader_get_cur(reader), *ptr;
944 if ((*start < 'A' || *start > 'Z') && (*start < 'a' || *start > 'z'))
948 while (is_wchar_encname(*++ptr))
952 enc = parse_encoding_name(start, len);
953 TRACE("encoding name %s\n", debugstr_wn(start, len));
957 if (enc == XmlEncoding_Unknown)
960 /* skip encoding name */
961 reader_skipn(reader, len);
965 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
966 static HRESULT reader_parse_encdecl(xmlreader *reader)
968 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
972 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
974 if (reader_cmp(reader, encodingW)) return S_FALSE;
975 name.str = reader_get_cur(reader);
977 /* skip 'encoding' */
978 reader_skipn(reader, 8);
980 hr = reader_parse_eq(reader);
981 if (FAILED(hr)) return hr;
983 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
986 reader_skipn(reader, 1);
988 hr = reader_parse_encname(reader, &val);
989 if (FAILED(hr)) return hr;
991 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
995 reader_skipn(reader, 1);
997 return reader_add_attr(reader, &name, &val);
1000 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
1001 static HRESULT reader_parse_sddecl(xmlreader *reader)
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};
1010 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
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);
1017 hr = reader_parse_eq(reader);
1018 if (FAILED(hr)) return hr;
1020 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
1023 reader_skipn(reader, 1);
1025 if (reader_cmp(reader, yesW) && reader_cmp(reader, noW))
1026 return WC_E_XMLDECL;
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));
1034 val.len = ptr-start;
1036 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
1039 reader_skipn(reader, 1);
1041 return reader_add_attr(reader, &name, &val);
1044 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
1045 static HRESULT reader_parse_xmldecl(xmlreader *reader)
1047 static const WCHAR xmldeclW[] = {'<','?','x','m','l',' ',0};
1048 static const WCHAR declcloseW[] = {'?','>',0};
1051 /* check if we have "<?xml " */
1052 if (reader_cmp(reader, xmldeclW)) return S_FALSE;
1054 reader_skipn(reader, 5);
1055 hr = reader_parse_versioninfo(reader);
1059 hr = reader_parse_encdecl(reader);
1063 hr = reader_parse_sddecl(reader);
1067 reader_skipspaces(reader);
1068 if (reader_cmp(reader, declcloseW)) return WC_E_XMLDECL;
1069 reader_skipn(reader, 2);
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);
1079 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1080 static HRESULT reader_parse_comment(xmlreader *reader)
1084 if (reader->resume[XmlReadResume_Body])
1086 start = reader->resume[XmlReadResume_Body];
1087 ptr = reader_get_cur(reader);
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);
1103 /* will exit when there's no more data, it won't attempt to
1104 read more from stream */
1115 TRACE("%s\n", debugstr_wn(start, ptr-start));
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;
1127 return WC_E_COMMENT;
1134 reader_skipn(reader, 1);
1142 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1143 static inline int is_char(WCHAR ch)
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);
1152 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1153 static inline int is_pubchar(WCHAR ch)
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');
1166 static inline int is_namestartchar(WCHAR ch)
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);
1185 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1186 static inline int is_ncnamechar(WCHAR ch)
1188 return (ch >= 'A' && ch <= 'Z') ||
1189 (ch == '_') || (ch >= 'a' && ch <= 'z') ||
1190 (ch == '-') || (ch == '.') ||
1191 (ch >= '0' && ch <= '9') ||
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);
1210 static inline int is_namechar(WCHAR ch)
1212 return (ch == ':') || is_ncnamechar(ch);
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)
1224 if (reader->resume[XmlReadResume_Name])
1226 start = reader->resume[XmlReadResume_Name];
1227 ptr = reader_get_cur(reader);
1231 ptr = start = reader_get_cur(reader);
1232 if (!is_namestartchar(*ptr)) return WC_E_NAMECHARACTER;
1235 while (is_namechar(*ptr))
1237 reader_skipn(reader, 1);
1238 ptr = reader_get_cur(reader);
1241 if (is_reader_pending(reader))
1243 reader->resume[XmlReadResume_Name] = start;
1247 reader->resume[XmlReadResume_Name] = NULL;
1249 TRACE("name %s:%d\n", debugstr_wn(start, ptr-start), (int)(ptr-start));
1250 reader_init_strvalue(start, ptr-start, name);
1255 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1256 static HRESULT reader_parse_pitarget(xmlreader *reader, strval *target)
1258 static const WCHAR xmlW[] = {'x','m','l'};
1263 hr = reader_parse_name(reader, &name);
1264 if (FAILED(hr)) return is_reader_pending(reader) ? E_PENDING : WC_E_PI;
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;
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;
1275 TRACE("pitarget %s:%d\n", debugstr_wn(name.str, name.len), name.len);
1280 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1281 static HRESULT reader_parse_pi(xmlreader *reader)
1287 switch (reader->resumestate)
1289 case XmlReadResumeState_Initial:
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;
1302 ptr = reader_get_cur(reader);
1303 /* exit earlier if there's no content */
1304 if (ptr[0] == '?' && ptr[1] == '>')
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);
1316 if (!reader->resume[XmlReadResume_Body])
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;
1326 start = reader->resume[XmlReadResume_Body];
1327 ptr = reader_get_cur(reader);
1338 TRACE("%s\n", debugstr_wn(start, ptr-start));
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);
1353 reader_more(reader);
1358 reader_skipn(reader, 1);
1359 ptr = reader_get_cur(reader);
1366 /* This one is used to parse significant whitespace nodes, like in Misc production */
1367 static HRESULT reader_parse_whitespace(xmlreader *reader)
1371 reader_shrink(reader);
1372 start = reader_get_cur(reader);
1374 reader_skipspaces(reader);
1375 ptr = reader_get_cur(reader);
1376 TRACE("%s\n", debugstr_wn(start, ptr-start));
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);
1385 /* [27] Misc ::= Comment | PI | S */
1386 static HRESULT reader_parse_misc(xmlreader *reader)
1388 HRESULT hr = S_FALSE;
1390 if (reader->resumestate != XmlReadResumeState_Initial)
1392 hr = reader_more(reader);
1393 if (FAILED(hr)) return hr;
1395 /* finish current node */
1396 switch (reader->resumestate)
1398 case XmlReadResumeState_PITarget:
1399 case XmlReadResumeState_PIBody:
1400 return reader_parse_pi(reader);
1401 case XmlReadResumeState_Comment:
1402 return reader_parse_comment(reader);
1404 ERR("unknown resume state %d\n", reader->resumestate);
1410 const WCHAR *cur = reader_get_cur(reader);
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);
1421 if (hr != S_FALSE) return hr;
1427 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1428 static HRESULT reader_parse_sys_literal(xmlreader *reader, strval *literal)
1430 WCHAR *start = reader_get_cur(reader), *cur, quote;
1432 if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1435 reader_skipn(reader, 1);
1437 cur = start = reader_get_cur(reader);
1438 while (is_char(*cur) && *cur != quote)
1440 reader_skipn(reader, 1);
1441 cur = reader_get_cur(reader);
1443 if (*cur == quote) reader_skipn(reader, 1);
1445 literal->str = start;
1446 literal->len = cur-start;
1447 TRACE("%s\n", debugstr_wn(start, cur-start));
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)
1455 WCHAR *start = reader_get_cur(reader), *cur, quote;
1457 if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1460 reader_skipn(reader, 1);
1463 while (is_pubchar(*cur) && *cur != quote)
1465 reader_skipn(reader, 1);
1466 cur = reader_get_cur(reader);
1469 reader_init_strvalue(start, cur-start, literal);
1470 TRACE("%s\n", debugstr_wn(start, cur-start));
1474 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1475 static HRESULT reader_parse_externalid(xmlreader *reader)
1477 static WCHAR systemW[] = {'S','Y','S','T','E','M',0};
1478 static WCHAR publicW[] = {'P','U','B','L','I','C',0};
1483 if (reader_cmp(reader, systemW))
1485 if (reader_cmp(reader, publicW))
1492 reader_skipn(reader, 6);
1493 cnt = reader_skipspaces(reader);
1494 if (!cnt) return WC_E_WHITESPACE;
1496 hr = reader_parse_pub_literal(reader, &pub);
1497 if (FAILED(hr)) return hr;
1499 reader_init_strvalue(publicW, strlenW(publicW), &name);
1500 return reader_add_attr(reader, &name, &pub);
1508 reader_skipn(reader, 6);
1509 cnt = reader_skipspaces(reader);
1510 if (!cnt) return WC_E_WHITESPACE;
1512 hr = reader_parse_sys_literal(reader, &sys);
1513 if (FAILED(hr)) return hr;
1515 reader_init_strvalue(systemW, strlenW(systemW), &name);
1516 return reader_add_attr(reader, &name, &sys);
1522 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1523 static HRESULT reader_parse_dtd(xmlreader *reader)
1525 static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',0};
1530 /* check if we have "<!DOCTYPE" */
1531 if (reader_cmp(reader, doctypeW)) return S_FALSE;
1532 reader_shrink(reader);
1534 /* DTD processing is not allowed by default */
1535 if (reader->dtdmode == DtdProcessing_Prohibit) return WC_E_DTDPROHIBITED;
1537 reader_skipn(reader, 9);
1538 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
1541 hr = reader_parse_name(reader, &name);
1542 if (FAILED(hr)) return WC_E_DECLDOCTYPE;
1544 reader_skipspaces(reader);
1546 hr = reader_parse_externalid(reader);
1547 if (FAILED(hr)) return hr;
1549 reader_skipspaces(reader);
1551 cur = reader_get_cur(reader);
1554 FIXME("internal subset parsing not implemented\n");
1559 reader_skipn(reader, 1);
1561 reader->nodetype = XmlNodeType_DocumentType;
1562 reader_set_strvalue(reader, StringValue_LocalName, &name);
1563 reader_set_strvalue(reader, StringValue_QualifiedName, &name);
1568 /* [11 NS] LocalPart ::= NCName */
1569 static HRESULT reader_parse_local(xmlreader *reader, strval *local)
1573 if (reader->resume[XmlReadResume_Local])
1575 start = reader->resume[XmlReadResume_Local];
1576 ptr = reader_get_cur(reader);
1580 ptr = start = reader_get_cur(reader);
1583 while (is_ncnamechar(*ptr))
1585 reader_skipn(reader, 1);
1586 ptr = reader_get_cur(reader);
1589 if (is_reader_pending(reader))
1591 reader->resume[XmlReadResume_Local] = start;
1595 reader->resume[XmlReadResume_Local] = NULL;
1597 reader_init_strvalue(start, ptr-start, local);
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)
1611 if (reader->resume[XmlReadResume_Name])
1613 start = reader->resume[XmlReadResume_Name];
1614 ptr = reader_get_cur(reader);
1618 ptr = start = reader_get_cur(reader);
1619 reader->resume[XmlReadResume_Name] = start;
1620 if (!is_ncnamechar(*ptr)) return NC_E_QNAMECHARACTER;
1623 if (reader->resume[XmlReadResume_Local])
1625 hr = reader_parse_local(reader, local);
1626 if (FAILED(hr)) return hr;
1628 reader_init_strvalue(reader->resume[XmlReadResume_Name],
1629 local->start - reader->resume[XmlReadResume_Name] - 1,
1634 /* skip prefix part */
1635 while (is_ncnamechar(*ptr))
1637 reader_skipn(reader, 1);
1638 ptr = reader_get_cur(reader);
1641 if (is_reader_pending(reader)) return E_PENDING;
1643 /* got a qualified name */
1646 reader_init_strvalue(start, ptr-start, prefix);
1649 reader_skipn(reader, 1);
1650 hr = reader_parse_local(reader, local);
1651 if (FAILED(hr)) return hr;
1655 reader_init_strvalue(reader->resume[XmlReadResume_Name], ptr-reader->resume[XmlReadResume_Name], local);
1656 reader_init_strvalue(NULL, 0, prefix);
1660 reader_init_strvalue(start, ptr-start, local);
1663 TRACE("qname %s:%s\n", debugstr_wn(prefix->start, prefix->len), debugstr_wn(local->start, local->len));
1665 TRACE("ncname %s\n", debugstr_wn(local->start, local->len));
1667 reader_init_strvalue(prefix->start ? prefix->start : local->start,
1669 (prefix->len ? prefix->len + 1 : 0) + local->len,
1672 reader->resume[XmlReadResume_Name] = NULL;
1673 reader->resume[XmlReadResume_Local] = NULL;
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)
1682 static const WCHAR endW[] = {'/','>',0};
1685 hr = reader_parse_qname(reader, prefix, local, qname);
1686 if (FAILED(hr)) return hr;
1688 reader_skipspaces(reader);
1691 if ((*empty = !reader_cmp(reader, endW)))
1694 reader_skipn(reader, 2);
1698 /* got a start tag */
1699 if (!reader_cmp(reader, gtW))
1702 reader_skipn(reader, 1);
1703 return reader_push_element(reader, qname);
1706 FIXME("only empty elements/start tags without attribute list supported\n");
1710 /* [39] element ::= EmptyElemTag | STag content ETag */
1711 static HRESULT reader_parse_element(xmlreader *reader)
1715 switch (reader->resumestate)
1717 case XmlReadResumeState_Initial:
1718 /* check if we are really on element */
1719 if (reader_cmp(reader, ltW)) return S_FALSE;
1722 reader_skipn(reader, 1);
1724 reader_shrink(reader);
1725 reader->resumestate = XmlReadResumeState_STag;
1726 case XmlReadResumeState_STag:
1728 strval qname, prefix, local;
1731 /* this handles empty elements too */
1732 hr = reader_parse_stag(reader, &prefix, &local, &qname, &empty);
1733 if (FAILED(hr)) return hr;
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;
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;
1743 reader->instate = XmlReadInState_Content;
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);
1758 /* [13 NS] ETag ::= '</' QName S? '>' */
1759 static HRESULT reader_parse_endtag(xmlreader *reader)
1761 strval prefix, local, qname;
1762 struct element *elem;
1766 reader_skipn(reader, 2);
1768 hr = reader_parse_qname(reader, &prefix, &local, &qname);
1769 if (FAILED(hr)) return hr;
1771 reader_skipspaces(reader);
1773 if (reader_cmp(reader, gtW)) return WC_E_GREATERTHAN;
1776 reader_skipn(reader, 1);
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;
1783 reader_pop_element(reader);
1785 reader->nodetype = XmlNodeType_EndElement;
1786 reader_set_strvalue(reader, StringValue_LocalName, &local);
1787 reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
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)
1800 if (reader->resume[XmlReadResume_Body])
1802 start = reader->resume[XmlReadResume_Body];
1803 ptr = reader_get_cur(reader);
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);
1821 if (*ptr == ']' && *(ptr+1) == ']' && *(ptr+2) == '>')
1825 TRACE("%s\n", debugstr_wn(start, ptr-start));
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;
1838 /* Value normalization is not fully implemented, rules are:
1840 - single '\r' -> '\n';
1841 - sequence '\r\n' -> '\n', in this case value length changes;
1843 if (*ptr == '\r') *ptr = '\n';
1844 reader_skipn(reader, 1);
1852 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1853 [67] Reference ::= EntityRef | CharRef
1854 [68] EntityRef ::= '&' Name ';' */
1855 static HRESULT reader_parse_reference(xmlreader *reader)
1857 FIXME("References not supported\n");
1861 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1862 static HRESULT reader_parse_chardata(xmlreader *reader)
1864 FIXME("CharData not supported\n");
1868 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1869 static HRESULT reader_parse_content(xmlreader *reader)
1871 static const WCHAR cdstartW[] = {'<','!','[','C','D','A','T','A','[',0};
1872 static const WCHAR etagW[] = {'<','/',0};
1873 static const WCHAR ampW[] = {'&',0};
1875 if (reader->resumestate != XmlReadResumeState_Initial)
1877 switch (reader->resumestate)
1879 case XmlReadResumeState_CDATA:
1880 return reader_parse_cdata(reader);
1881 case XmlReadResumeState_Comment:
1882 return reader_parse_comment(reader);
1883 case XmlReadResumeState_PIBody:
1884 case XmlReadResumeState_PITarget:
1885 return reader_parse_pi(reader);
1887 ERR("unknown resume state %d\n", reader->resumestate);
1891 reader_shrink(reader);
1893 /* handle end tag here, it indicates end of content as well */
1894 if (!reader_cmp(reader, etagW))
1895 return reader_parse_endtag(reader);
1897 if (!reader_cmp(reader, commentW))
1898 return reader_parse_comment(reader);
1900 if (!reader_cmp(reader, piW))
1901 return reader_parse_pi(reader);
1903 if (!reader_cmp(reader, cdstartW))
1904 return reader_parse_cdata(reader);
1906 if (!reader_cmp(reader, ampW))
1907 return reader_parse_reference(reader);
1909 if (!reader_cmp(reader, ltW))
1910 return reader_parse_element(reader);
1912 /* what's left must be CharData */
1913 return reader_parse_chardata(reader);
1916 static HRESULT reader_parse_nextnode(xmlreader *reader)
1922 switch (reader->instate)
1924 /* if it's a first call for a new input we need to detect stream encoding */
1925 case XmlReadInState_Initial:
1929 hr = readerinput_growraw(reader->input);
1930 if (FAILED(hr)) return hr;
1932 /* try to detect encoding by BOM or data and set input code page */
1933 hr = readerinput_detectencoding(reader->input, &enc);
1934 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
1935 if (FAILED(hr)) return hr;
1937 /* always switch first time cause we have to put something in */
1938 readerinput_switchencoding(reader->input, enc);
1940 /* parse xml declaration */
1941 hr = reader_parse_xmldecl(reader);
1942 if (FAILED(hr)) return hr;
1944 readerinput_shrinkraw(reader->input, -1);
1945 reader->instate = XmlReadInState_Misc_DTD;
1946 if (hr == S_OK) return hr;
1949 case XmlReadInState_Misc_DTD:
1950 hr = reader_parse_misc(reader);
1951 if (FAILED(hr)) return hr;
1954 reader->instate = XmlReadInState_DTD;
1958 case XmlReadInState_DTD:
1959 hr = reader_parse_dtd(reader);
1960 if (FAILED(hr)) return hr;
1964 reader->instate = XmlReadInState_DTD_Misc;
1968 reader->instate = XmlReadInState_Element;
1970 case XmlReadInState_DTD_Misc:
1971 hr = reader_parse_misc(reader);
1972 if (FAILED(hr)) return hr;
1975 reader->instate = XmlReadInState_Element;
1979 case XmlReadInState_Element:
1980 return reader_parse_element(reader);
1981 case XmlReadInState_Content:
1982 return reader_parse_content(reader);
1984 FIXME("internal state %d not handled\n", reader->instate);
1992 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
1994 xmlreader *This = impl_from_IXmlReader(iface);
1996 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1998 if (IsEqualGUID(riid, &IID_IUnknown) ||
1999 IsEqualGUID(riid, &IID_IXmlReader))
2005 FIXME("interface %s not implemented\n", debugstr_guid(riid));
2007 return E_NOINTERFACE;
2010 IXmlReader_AddRef(iface);
2015 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
2017 xmlreader *This = impl_from_IXmlReader(iface);
2018 ULONG ref = InterlockedIncrement(&This->ref);
2019 TRACE("(%p)->(%d)\n", This, ref);
2023 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
2025 xmlreader *This = impl_from_IXmlReader(iface);
2026 LONG ref = InterlockedDecrement(&This->ref);
2028 TRACE("(%p)->(%d)\n", This, ref);
2032 IMalloc *imalloc = This->imalloc;
2033 if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
2034 reader_clear_attrs(This);
2035 reader_clear_elements(This);
2036 reader_free_strvalues(This);
2037 reader_free(This, This);
2038 if (imalloc) IMalloc_Release(imalloc);
2044 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
2046 xmlreader *This = impl_from_IXmlReader(iface);
2047 IXmlReaderInput *readerinput;
2050 TRACE("(%p)->(%p)\n", This, input);
2054 readerinput_release_stream(This->input);
2055 IUnknown_Release(&This->input->IXmlReaderInput_iface);
2059 This->line = This->pos = 0;
2060 reader_clear_elements(This);
2062 This->resumestate = XmlReadResumeState_Initial;
2063 memset(This->resume, 0, sizeof(This->resume));
2065 /* just reset current input */
2068 This->state = XmlReadState_Initial;
2072 /* now try IXmlReaderInput, ISequentialStream, IStream */
2073 hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&readerinput);
2076 if (readerinput->lpVtbl == &xmlreaderinputvtbl)
2077 This->input = impl_from_IXmlReaderInput(readerinput);
2080 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2081 readerinput, readerinput->lpVtbl);
2082 IUnknown_Release(readerinput);
2088 if (hr != S_OK || !readerinput)
2090 /* create IXmlReaderInput basing on supplied interface */
2091 hr = CreateXmlReaderInputWithEncodingName(input,
2092 NULL, NULL, FALSE, NULL, &readerinput);
2093 if (hr != S_OK) return hr;
2094 This->input = impl_from_IXmlReaderInput(readerinput);
2097 /* set stream for supplied IXmlReaderInput */
2098 hr = readerinput_query_for_stream(This->input);
2101 This->state = XmlReadState_Initial;
2102 This->instate = XmlReadInState_Initial;
2108 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
2110 xmlreader *This = impl_from_IXmlReader(iface);
2112 TRACE("(%p %u %p)\n", This, property, value);
2114 if (!value) return E_INVALIDARG;
2118 case XmlReaderProperty_DtdProcessing:
2119 *value = This->dtdmode;
2121 case XmlReaderProperty_ReadState:
2122 *value = This->state;
2125 FIXME("Unimplemented property (%u)\n", property);
2132 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
2134 xmlreader *This = impl_from_IXmlReader(iface);
2136 TRACE("(%p %u %lu)\n", iface, property, value);
2140 case XmlReaderProperty_DtdProcessing:
2141 if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
2142 This->dtdmode = value;
2145 FIXME("Unimplemented property (%u)\n", property);
2152 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
2154 xmlreader *This = impl_from_IXmlReader(iface);
2155 XmlNodeType oldtype = This->nodetype;
2158 TRACE("(%p)->(%p)\n", This, nodetype);
2160 if (This->state == XmlReadState_Closed) return S_FALSE;
2162 hr = reader_parse_nextnode(This);
2163 if (oldtype == XmlNodeType_None && This->nodetype != oldtype)
2164 This->state = XmlReadState_Interactive;
2165 if (hr == S_OK) *nodetype = This->nodetype;
2170 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
2172 xmlreader *This = impl_from_IXmlReader(iface);
2173 TRACE("(%p)->(%p)\n", This, node_type);
2175 /* When we're on attribute always return attribute type, container node type is kept.
2176 Note that container is not necessarily an element, and attribute doesn't mean it's
2177 an attribute in XML spec terms. */
2178 *node_type = This->attr ? XmlNodeType_Attribute : This->nodetype;
2179 return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
2182 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
2184 xmlreader *This = impl_from_IXmlReader(iface);
2186 TRACE("(%p)\n", This);
2188 if (!This->attr_count) return S_FALSE;
2189 This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
2193 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
2195 xmlreader *This = impl_from_IXmlReader(iface);
2196 const struct list *next;
2198 TRACE("(%p)\n", This);
2200 if (!This->attr_count) return S_FALSE;
2203 return IXmlReader_MoveToFirstAttribute(iface);
2205 next = list_next(&This->attrs, &This->attr->entry);
2207 This->attr = LIST_ENTRY(next, struct attribute, entry);
2209 return next ? S_OK : S_FALSE;
2212 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
2214 LPCWSTR namespaceUri)
2216 FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
2220 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
2222 xmlreader *This = impl_from_IXmlReader(iface);
2224 TRACE("(%p)\n", This);
2226 if (!This->attr_count) return S_FALSE;
2231 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2233 xmlreader *This = impl_from_IXmlReader(iface);
2235 TRACE("(%p)->(%p %p)\n", This, name, len);
2236 *name = This->strvalues[StringValue_QualifiedName].str;
2237 *len = This->strvalues[StringValue_QualifiedName].len;
2241 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
2242 LPCWSTR *namespaceUri,
2243 UINT *namespaceUri_length)
2245 FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
2249 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2251 xmlreader *This = impl_from_IXmlReader(iface);
2253 TRACE("(%p)->(%p %p)\n", This, name, len);
2254 *name = This->strvalues[StringValue_LocalName].str;
2255 *len = This->strvalues[StringValue_LocalName].len;
2259 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
2261 UINT *prefix_length)
2263 FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
2267 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, const WCHAR **value, UINT *len)
2269 xmlreader *reader = impl_from_IXmlReader(iface);
2270 strval *val = &reader->strvalues[StringValue_Value];
2272 TRACE("(%p)->(%p %p)\n", reader, value, len);
2276 if ((reader->nodetype == XmlNodeType_Comment && !val->str) || is_reader_pending(reader))
2281 hr = IXmlReader_Read(iface, &type);
2282 if (FAILED(hr)) return hr;
2284 /* return if still pending, partially read values are not reported */
2285 if (is_reader_pending(reader)) return E_PENDING;
2290 val->str = reader_alloc(reader, (val->len+1)*sizeof(WCHAR));
2291 if (!val->str) return E_OUTOFMEMORY;
2292 memcpy(val->str, val->start, val->len*sizeof(WCHAR));
2293 val->str[val->len] = 0;
2297 if (len) *len = val->len;
2301 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface, WCHAR *buffer, UINT chunk_size, UINT *read)
2303 xmlreader *reader = impl_from_IXmlReader(iface);
2304 strval *val = &reader->strvalues[StringValue_Value];
2307 TRACE("(%p)->(%p %u %p)\n", reader, buffer, chunk_size, read);
2309 /* Value is already allocated, chunked reads are not possible. */
2310 if (val->str) return S_FALSE;
2314 len = min(chunk_size, val->len);
2315 memcpy(buffer, val->start, len);
2318 if (read) *read = len;
2324 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
2326 UINT *baseUri_length)
2328 FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
2332 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
2334 FIXME("(%p): stub\n", iface);
2338 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
2340 FIXME("(%p): stub\n", iface);
2344 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
2346 xmlreader *This = impl_from_IXmlReader(iface);
2348 TRACE("(%p %p)\n", This, lineNumber);
2350 if (!lineNumber) return E_INVALIDARG;
2352 *lineNumber = This->line;
2357 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
2359 xmlreader *This = impl_from_IXmlReader(iface);
2361 TRACE("(%p %p)\n", This, linePosition);
2363 if (!linePosition) return E_INVALIDARG;
2365 *linePosition = This->pos;
2370 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
2372 xmlreader *This = impl_from_IXmlReader(iface);
2374 TRACE("(%p)->(%p)\n", This, count);
2376 if (!count) return E_INVALIDARG;
2378 *count = This->attr_count;
2382 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
2384 xmlreader *This = impl_from_IXmlReader(iface);
2385 TRACE("(%p)->(%p)\n", This, depth);
2386 *depth = This->depth;
2390 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
2392 FIXME("(%p): stub\n", iface);
2396 static const struct IXmlReaderVtbl xmlreader_vtbl =
2398 xmlreader_QueryInterface,
2402 xmlreader_GetProperty,
2403 xmlreader_SetProperty,
2405 xmlreader_GetNodeType,
2406 xmlreader_MoveToFirstAttribute,
2407 xmlreader_MoveToNextAttribute,
2408 xmlreader_MoveToAttributeByName,
2409 xmlreader_MoveToElement,
2410 xmlreader_GetQualifiedName,
2411 xmlreader_GetNamespaceUri,
2412 xmlreader_GetLocalName,
2413 xmlreader_GetPrefix,
2415 xmlreader_ReadValueChunk,
2416 xmlreader_GetBaseUri,
2417 xmlreader_IsDefault,
2418 xmlreader_IsEmptyElement,
2419 xmlreader_GetLineNumber,
2420 xmlreader_GetLinePosition,
2421 xmlreader_GetAttributeCount,
2426 /** IXmlReaderInput **/
2427 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
2429 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2431 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
2433 if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
2434 IsEqualGUID(riid, &IID_IUnknown))
2440 WARN("interface %s not implemented\n", debugstr_guid(riid));
2442 return E_NOINTERFACE;
2445 IUnknown_AddRef(iface);
2450 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
2452 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2453 ULONG ref = InterlockedIncrement(&This->ref);
2454 TRACE("(%p)->(%d)\n", This, ref);
2458 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
2460 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2461 LONG ref = InterlockedDecrement(&This->ref);
2463 TRACE("(%p)->(%d)\n", This, ref);
2467 IMalloc *imalloc = This->imalloc;
2468 if (This->input) IUnknown_Release(This->input);
2469 if (This->stream) ISequentialStream_Release(This->stream);
2470 if (This->buffer) free_input_buffer(This->buffer);
2471 readerinput_free(This, This->baseuri);
2472 readerinput_free(This, This);
2473 if (imalloc) IMalloc_Release(imalloc);
2479 static const struct IUnknownVtbl xmlreaderinputvtbl =
2481 xmlreaderinput_QueryInterface,
2482 xmlreaderinput_AddRef,
2483 xmlreaderinput_Release
2486 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
2491 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
2493 if (!IsEqualGUID(riid, &IID_IXmlReader))
2495 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
2500 reader = IMalloc_Alloc(imalloc, sizeof(*reader));
2502 reader = heap_alloc(sizeof(*reader));
2503 if(!reader) return E_OUTOFMEMORY;
2505 reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
2507 reader->input = NULL;
2508 reader->state = XmlReadState_Closed;
2509 reader->instate = XmlReadInState_Initial;
2510 reader->resumestate = XmlReadResumeState_Initial;
2511 reader->dtdmode = DtdProcessing_Prohibit;
2512 reader->line = reader->pos = 0;
2513 reader->imalloc = imalloc;
2514 if (imalloc) IMalloc_AddRef(imalloc);
2515 reader->nodetype = XmlNodeType_None;
2516 list_init(&reader->attrs);
2517 reader->attr_count = 0;
2518 reader->attr = NULL;
2519 list_init(&reader->elements);
2521 memset(reader->resume, 0, sizeof(reader->resume));
2523 for (i = 0; i < StringValue_Last; i++)
2524 reader->strvalues[i] = strval_empty;
2526 *obj = &reader->IXmlReader_iface;
2528 TRACE("returning iface %p\n", *obj);
2533 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
2538 IXmlReaderInput **ppInput)
2540 xmlreaderinput *readerinput;
2543 TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
2544 hint, wine_dbgstr_w(base_uri), ppInput);
2546 if (!stream || !ppInput) return E_INVALIDARG;
2549 readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
2551 readerinput = heap_alloc(sizeof(*readerinput));
2552 if(!readerinput) return E_OUTOFMEMORY;
2554 readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinputvtbl;
2555 readerinput->ref = 1;
2556 readerinput->imalloc = imalloc;
2557 readerinput->stream = NULL;
2558 if (imalloc) IMalloc_AddRef(imalloc);
2559 readerinput->encoding = parse_encoding_name(encoding, -1);
2560 readerinput->hint = hint;
2561 readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
2562 readerinput->pending = 0;
2564 hr = alloc_input_buffer(readerinput);
2567 readerinput_free(readerinput, readerinput->baseuri);
2568 readerinput_free(readerinput, readerinput);
2569 if (imalloc) IMalloc_Release(imalloc);
2572 IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
2574 *ppInput = &readerinput->IXmlReaderInput_iface;
2576 TRACE("returning iface %p\n", *ppInput);