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 reader_skipn(reader, 1);
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)
1851 FIXME("References not supported\n");
1855 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1856 static HRESULT reader_parse_chardata(xmlreader *reader)
1858 FIXME("CharData not supported\n");
1862 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1863 static HRESULT reader_parse_content(xmlreader *reader)
1865 static const WCHAR cdstartW[] = {'<','!','[','C','D','A','T','A','[',0};
1866 static const WCHAR etagW[] = {'<','/',0};
1867 static const WCHAR ampW[] = {'&',0};
1869 if (reader->resumestate != XmlReadResumeState_Initial)
1871 switch (reader->resumestate)
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);
1881 ERR("unknown resume state %d\n", reader->resumestate);
1885 reader_shrink(reader);
1887 /* handle end tag here, it indicates end of content as well */
1888 if (!reader_cmp(reader, etagW))
1889 return reader_parse_endtag(reader);
1891 if (!reader_cmp(reader, commentW))
1892 return reader_parse_comment(reader);
1894 if (!reader_cmp(reader, piW))
1895 return reader_parse_pi(reader);
1897 if (!reader_cmp(reader, cdstartW))
1898 return reader_parse_cdata(reader);
1900 if (!reader_cmp(reader, ampW))
1901 return reader_parse_reference(reader);
1903 if (!reader_cmp(reader, ltW))
1904 return reader_parse_element(reader);
1906 /* what's left must be CharData */
1907 return reader_parse_chardata(reader);
1910 static HRESULT reader_parse_nextnode(xmlreader *reader)
1916 switch (reader->instate)
1918 /* if it's a first call for a new input we need to detect stream encoding */
1919 case XmlReadInState_Initial:
1923 hr = readerinput_growraw(reader->input);
1924 if (FAILED(hr)) return hr;
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;
1931 /* always switch first time cause we have to put something in */
1932 readerinput_switchencoding(reader->input, enc);
1934 /* parse xml declaration */
1935 hr = reader_parse_xmldecl(reader);
1936 if (FAILED(hr)) return hr;
1938 readerinput_shrinkraw(reader->input, -1);
1939 reader->instate = XmlReadInState_Misc_DTD;
1940 if (hr == S_OK) return hr;
1943 case XmlReadInState_Misc_DTD:
1944 hr = reader_parse_misc(reader);
1945 if (FAILED(hr)) return hr;
1948 reader->instate = XmlReadInState_DTD;
1952 case XmlReadInState_DTD:
1953 hr = reader_parse_dtd(reader);
1954 if (FAILED(hr)) return hr;
1958 reader->instate = XmlReadInState_DTD_Misc;
1962 reader->instate = XmlReadInState_Element;
1964 case XmlReadInState_DTD_Misc:
1965 hr = reader_parse_misc(reader);
1966 if (FAILED(hr)) return hr;
1969 reader->instate = XmlReadInState_Element;
1973 case XmlReadInState_Element:
1974 return reader_parse_element(reader);
1975 case XmlReadInState_Content:
1976 return reader_parse_content(reader);
1978 FIXME("internal state %d not handled\n", reader->instate);
1986 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
1988 xmlreader *This = impl_from_IXmlReader(iface);
1990 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1992 if (IsEqualGUID(riid, &IID_IUnknown) ||
1993 IsEqualGUID(riid, &IID_IXmlReader))
1999 FIXME("interface %s not implemented\n", debugstr_guid(riid));
2001 return E_NOINTERFACE;
2004 IXmlReader_AddRef(iface);
2009 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
2011 xmlreader *This = impl_from_IXmlReader(iface);
2012 ULONG ref = InterlockedIncrement(&This->ref);
2013 TRACE("(%p)->(%d)\n", This, ref);
2017 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
2019 xmlreader *This = impl_from_IXmlReader(iface);
2020 LONG ref = InterlockedDecrement(&This->ref);
2022 TRACE("(%p)->(%d)\n", This, ref);
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);
2038 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
2040 xmlreader *This = impl_from_IXmlReader(iface);
2041 IXmlReaderInput *readerinput;
2044 TRACE("(%p)->(%p)\n", This, input);
2048 readerinput_release_stream(This->input);
2049 IUnknown_Release(&This->input->IXmlReaderInput_iface);
2053 This->line = This->pos = 0;
2054 reader_clear_elements(This);
2056 This->resumestate = XmlReadResumeState_Initial;
2057 memset(This->resume, 0, sizeof(This->resume));
2059 /* just reset current input */
2062 This->state = XmlReadState_Initial;
2066 /* now try IXmlReaderInput, ISequentialStream, IStream */
2067 hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&readerinput);
2070 if (readerinput->lpVtbl == &xmlreaderinputvtbl)
2071 This->input = impl_from_IXmlReaderInput(readerinput);
2074 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2075 readerinput, readerinput->lpVtbl);
2076 IUnknown_Release(readerinput);
2082 if (hr != S_OK || !readerinput)
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);
2091 /* set stream for supplied IXmlReaderInput */
2092 hr = readerinput_query_for_stream(This->input);
2095 This->state = XmlReadState_Initial;
2096 This->instate = XmlReadInState_Initial;
2102 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
2104 xmlreader *This = impl_from_IXmlReader(iface);
2106 TRACE("(%p %u %p)\n", This, property, value);
2108 if (!value) return E_INVALIDARG;
2112 case XmlReaderProperty_DtdProcessing:
2113 *value = This->dtdmode;
2115 case XmlReaderProperty_ReadState:
2116 *value = This->state;
2119 FIXME("Unimplemented property (%u)\n", property);
2126 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
2128 xmlreader *This = impl_from_IXmlReader(iface);
2130 TRACE("(%p %u %lu)\n", iface, property, value);
2134 case XmlReaderProperty_DtdProcessing:
2135 if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
2136 This->dtdmode = value;
2139 FIXME("Unimplemented property (%u)\n", property);
2146 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
2148 xmlreader *This = impl_from_IXmlReader(iface);
2149 XmlNodeType oldtype = This->nodetype;
2152 TRACE("(%p)->(%p)\n", This, nodetype);
2154 if (This->state == XmlReadState_Closed) return S_FALSE;
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;
2164 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
2166 xmlreader *This = impl_from_IXmlReader(iface);
2167 TRACE("(%p)->(%p)\n", This, node_type);
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;
2176 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
2178 xmlreader *This = impl_from_IXmlReader(iface);
2180 TRACE("(%p)\n", This);
2182 if (!This->attr_count) return S_FALSE;
2183 This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
2187 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
2189 xmlreader *This = impl_from_IXmlReader(iface);
2190 const struct list *next;
2192 TRACE("(%p)\n", This);
2194 if (!This->attr_count) return S_FALSE;
2197 return IXmlReader_MoveToFirstAttribute(iface);
2199 next = list_next(&This->attrs, &This->attr->entry);
2201 This->attr = LIST_ENTRY(next, struct attribute, entry);
2203 return next ? S_OK : S_FALSE;
2206 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
2208 LPCWSTR namespaceUri)
2210 FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
2214 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
2216 xmlreader *This = impl_from_IXmlReader(iface);
2218 TRACE("(%p)\n", This);
2220 if (!This->attr_count) return S_FALSE;
2225 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2227 xmlreader *This = impl_from_IXmlReader(iface);
2229 TRACE("(%p)->(%p %p)\n", This, name, len);
2230 *name = This->strvalues[StringValue_QualifiedName].str;
2231 *len = This->strvalues[StringValue_QualifiedName].len;
2235 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
2236 LPCWSTR *namespaceUri,
2237 UINT *namespaceUri_length)
2239 FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
2243 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2245 xmlreader *This = impl_from_IXmlReader(iface);
2247 TRACE("(%p)->(%p %p)\n", This, name, len);
2248 *name = This->strvalues[StringValue_LocalName].str;
2249 *len = This->strvalues[StringValue_LocalName].len;
2253 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
2255 UINT *prefix_length)
2257 FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
2261 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, const WCHAR **value, UINT *len)
2263 xmlreader *reader = impl_from_IXmlReader(iface);
2264 strval *val = &reader->strvalues[StringValue_Value];
2266 TRACE("(%p)->(%p %p)\n", reader, value, len);
2270 if ((reader->nodetype == XmlNodeType_Comment && !val->str) || is_reader_pending(reader))
2275 hr = IXmlReader_Read(iface, &type);
2276 if (FAILED(hr)) return hr;
2278 /* return if still pending, partially read values are not reported */
2279 if (is_reader_pending(reader)) return E_PENDING;
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;
2291 if (len) *len = val->len;
2295 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface, WCHAR *buffer, UINT chunk_size, UINT *read)
2297 xmlreader *reader = impl_from_IXmlReader(iface);
2298 strval *val = &reader->strvalues[StringValue_Value];
2301 TRACE("(%p)->(%p %u %p)\n", reader, buffer, chunk_size, read);
2303 /* Value is already allocated, chunked reads are not possible. */
2304 if (val->str) return S_FALSE;
2308 len = min(chunk_size, val->len);
2309 memcpy(buffer, val->start, len);
2312 if (read) *read = len;
2318 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
2320 UINT *baseUri_length)
2322 FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
2326 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
2328 FIXME("(%p): stub\n", iface);
2332 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
2334 FIXME("(%p): stub\n", iface);
2338 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
2340 xmlreader *This = impl_from_IXmlReader(iface);
2342 TRACE("(%p %p)\n", This, lineNumber);
2344 if (!lineNumber) return E_INVALIDARG;
2346 *lineNumber = This->line;
2351 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
2353 xmlreader *This = impl_from_IXmlReader(iface);
2355 TRACE("(%p %p)\n", This, linePosition);
2357 if (!linePosition) return E_INVALIDARG;
2359 *linePosition = This->pos;
2364 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
2366 xmlreader *This = impl_from_IXmlReader(iface);
2368 TRACE("(%p)->(%p)\n", This, count);
2370 if (!count) return E_INVALIDARG;
2372 *count = This->attr_count;
2376 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
2378 xmlreader *This = impl_from_IXmlReader(iface);
2379 TRACE("(%p)->(%p)\n", This, depth);
2380 *depth = This->depth;
2384 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
2386 FIXME("(%p): stub\n", iface);
2390 static const struct IXmlReaderVtbl xmlreader_vtbl =
2392 xmlreader_QueryInterface,
2396 xmlreader_GetProperty,
2397 xmlreader_SetProperty,
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,
2409 xmlreader_ReadValueChunk,
2410 xmlreader_GetBaseUri,
2411 xmlreader_IsDefault,
2412 xmlreader_IsEmptyElement,
2413 xmlreader_GetLineNumber,
2414 xmlreader_GetLinePosition,
2415 xmlreader_GetAttributeCount,
2420 /** IXmlReaderInput **/
2421 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
2423 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2425 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
2427 if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
2428 IsEqualGUID(riid, &IID_IUnknown))
2434 WARN("interface %s not implemented\n", debugstr_guid(riid));
2436 return E_NOINTERFACE;
2439 IUnknown_AddRef(iface);
2444 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
2446 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2447 ULONG ref = InterlockedIncrement(&This->ref);
2448 TRACE("(%p)->(%d)\n", This, ref);
2452 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
2454 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2455 LONG ref = InterlockedDecrement(&This->ref);
2457 TRACE("(%p)->(%d)\n", This, ref);
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);
2473 static const struct IUnknownVtbl xmlreaderinputvtbl =
2475 xmlreaderinput_QueryInterface,
2476 xmlreaderinput_AddRef,
2477 xmlreaderinput_Release
2480 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
2485 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
2487 if (!IsEqualGUID(riid, &IID_IXmlReader))
2489 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
2494 reader = IMalloc_Alloc(imalloc, sizeof(*reader));
2496 reader = heap_alloc(sizeof(*reader));
2497 if(!reader) return E_OUTOFMEMORY;
2499 reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
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);
2515 memset(reader->resume, 0, sizeof(reader->resume));
2517 for (i = 0; i < StringValue_Last; i++)
2518 reader->strvalues[i] = strval_empty;
2520 *obj = &reader->IXmlReader_iface;
2522 TRACE("returning iface %p\n", *obj);
2527 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
2532 IXmlReaderInput **ppInput)
2534 xmlreaderinput *readerinput;
2537 TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
2538 hint, wine_dbgstr_w(base_uri), ppInput);
2540 if (!stream || !ppInput) return E_INVALIDARG;
2543 readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
2545 readerinput = heap_alloc(sizeof(*readerinput));
2546 if(!readerinput) return E_OUTOFMEMORY;
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;
2558 hr = alloc_input_buffer(readerinput);
2561 readerinput_free(readerinput, readerinput->baseuri);
2562 readerinput_free(readerinput, readerinput);
2563 if (imalloc) IMalloc_Release(imalloc);
2566 IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
2568 *ppInput = &readerinput->IXmlReaderInput_iface;
2570 TRACE("returning iface %p\n", *ppInput);