winemac: Implement SetCursor() and DestroyCursorIcon().
[wine.git] / dlls / xmllite / reader.c
blob7bec2b13cb5d53c273a8aba443f86033d6b398df
1 /*
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
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "initguid.h"
27 #include "objbase.h"
28 #include "xmllite.h"
29 #include "xmllite_private.h"
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);
40 typedef enum
42 XmlEncoding_UTF16,
43 XmlEncoding_UTF8,
44 XmlEncoding_Unknown
45 } xml_encoding;
47 typedef enum
49 XmlReadInState_Initial,
50 XmlReadInState_XmlDecl,
51 XmlReadInState_Misc_DTD,
52 XmlReadInState_DTD,
53 XmlReadInState_DTD_Misc,
54 XmlReadInState_Element,
55 XmlReadInState_Content,
56 XmlReadInState_MiscEnd
57 } XmlReaderInternalState;
59 typedef enum
61 StringValue_LocalName,
62 StringValue_QualifiedName,
63 StringValue_Value,
64 StringValue_Last
65 } XmlReaderStringValue;
67 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
68 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
70 static const WCHAR dblquoteW[] = {'\"',0};
71 static const WCHAR quoteW[] = {'\'',0};
72 static const WCHAR ltW[] = {'<',0};
73 static const WCHAR gtW[] = {'>',0};
74 static const WCHAR commentW[] = {'<','!','-','-',0};
75 static const WCHAR piW[] = {'<','?',0};
77 struct xml_encoding_data
79 const WCHAR *name;
80 xml_encoding enc;
81 UINT cp;
84 static const struct xml_encoding_data xml_encoding_map[] = {
85 { utf16W, XmlEncoding_UTF16, ~0 },
86 { utf8W, XmlEncoding_UTF8, CP_UTF8 }
89 typedef struct
91 char *data;
92 char *cur;
93 unsigned int allocated;
94 unsigned int written;
95 } encoded_buffer;
97 typedef struct input_buffer input_buffer;
99 typedef struct
101 IXmlReaderInput IXmlReaderInput_iface;
102 LONG ref;
103 /* reference passed on IXmlReaderInput creation, is kept when input is created */
104 IUnknown *input;
105 IMalloc *imalloc;
106 xml_encoding encoding;
107 BOOL hint;
108 WCHAR *baseuri;
109 /* stream reference set after SetInput() call from reader,
110 stored as sequential stream, cause currently
111 optimizations possible with IStream aren't implemented */
112 ISequentialStream *stream;
113 input_buffer *buffer;
114 unsigned int pending : 1;
115 } xmlreaderinput;
117 static const struct IUnknownVtbl xmlreaderinputvtbl;
119 typedef struct
121 WCHAR *str;
122 UINT len;
123 } strval;
125 static WCHAR emptyW[] = {0};
126 static const strval strval_empty = {emptyW, 0};
128 struct attribute
130 struct list entry;
131 strval localname;
132 strval value;
135 struct element
137 struct list entry;
138 strval qname;
141 typedef struct
143 IXmlReader IXmlReader_iface;
144 LONG ref;
145 xmlreaderinput *input;
146 IMalloc *imalloc;
147 XmlReadState state;
148 XmlReaderInternalState instate;
149 XmlNodeType nodetype;
150 DtdProcessing dtdmode;
151 UINT line, pos; /* reader position in XML stream */
152 struct list attrs; /* attributes list for current node */
153 struct attribute *attr; /* current attribute */
154 UINT attr_count;
155 struct list elements;
156 strval strvalues[StringValue_Last];
157 UINT depth;
158 WCHAR *save;
159 } xmlreader;
161 struct input_buffer
163 encoded_buffer utf16;
164 encoded_buffer encoded;
165 UINT code_page;
166 xmlreaderinput *input;
169 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
171 return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
174 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
176 return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
179 static inline void *m_alloc(IMalloc *imalloc, size_t len)
181 if (imalloc)
182 return IMalloc_Alloc(imalloc, len);
183 else
184 return heap_alloc(len);
187 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
189 if (imalloc)
190 return IMalloc_Realloc(imalloc, mem, len);
191 else
192 return heap_realloc(mem, len);
195 static inline void m_free(IMalloc *imalloc, void *mem)
197 if (imalloc)
198 IMalloc_Free(imalloc, mem);
199 else
200 heap_free(mem);
203 /* reader memory allocation functions */
204 static inline void *reader_alloc(xmlreader *reader, size_t len)
206 return m_alloc(reader->imalloc, len);
209 static inline void reader_free(xmlreader *reader, void *mem)
211 m_free(reader->imalloc, mem);
214 static HRESULT reader_strvaldup(xmlreader *reader, const strval *src, strval *dest)
216 *dest = *src;
218 if (src->str != strval_empty.str)
220 dest->str = reader_alloc(reader, (dest->len+1)*sizeof(WCHAR));
221 if (!dest->str) return E_OUTOFMEMORY;
222 memcpy(dest->str, src->str, dest->len*sizeof(WCHAR));
223 dest->str[dest->len] = 0;
226 return S_OK;
229 /* reader input memory allocation functions */
230 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
232 return m_alloc(input->imalloc, len);
235 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
237 return m_realloc(input->imalloc, mem, len);
240 static inline void readerinput_free(xmlreaderinput *input, void *mem)
242 m_free(input->imalloc, mem);
245 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
247 LPWSTR ret = NULL;
249 if(str) {
250 DWORD size;
252 size = (strlenW(str)+1)*sizeof(WCHAR);
253 ret = readerinput_alloc(input, size);
254 if (ret) memcpy(ret, str, size);
257 return ret;
260 static void reader_clear_attrs(xmlreader *reader)
262 struct attribute *attr, *attr2;
263 LIST_FOR_EACH_ENTRY_SAFE(attr, attr2, &reader->attrs, struct attribute, entry)
265 reader_free(reader, attr);
267 list_init(&reader->attrs);
268 reader->attr_count = 0;
271 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
272 while we are on a node with attributes */
273 static HRESULT reader_add_attr(xmlreader *reader, strval *localname, strval *value)
275 struct attribute *attr;
277 attr = reader_alloc(reader, sizeof(*attr));
278 if (!attr) return E_OUTOFMEMORY;
280 attr->localname = *localname;
281 attr->value = *value;
282 list_add_tail(&reader->attrs, &attr->entry);
283 reader->attr_count++;
285 return S_OK;
288 /* This one frees stored string value if needed */
289 static void reader_free_strvalued(xmlreader *reader, strval *v)
291 if (v->str != strval_empty.str)
293 reader_free(reader, v->str);
294 *v = strval_empty;
298 static void reader_free_strvalue(xmlreader *reader, XmlReaderStringValue type)
300 reader_free_strvalued(reader, &reader->strvalues[type]);
303 static void reader_free_strvalues(xmlreader *reader)
305 int type;
306 for (type = 0; type < StringValue_Last; type++)
307 reader_free_strvalue(reader, type);
310 /* This helper should only be used to test if strings are the same,
311 it doesn't try to sort. */
312 static inline int strval_eq(const strval *str1, const strval *str2)
314 if (str1->len != str2->len) return 0;
315 return !memcmp(str1->str, str2->str, str1->len*sizeof(WCHAR));
318 static void reader_clear_elements(xmlreader *reader)
320 struct element *elem, *elem2;
321 LIST_FOR_EACH_ENTRY_SAFE(elem, elem2, &reader->elements, struct element, entry)
323 reader_free_strvalued(reader, &elem->qname);
324 reader_free(reader, elem);
326 list_init(&reader->elements);
329 static HRESULT reader_inc_depth(xmlreader *reader)
331 /* FIXME: handle XmlReaderProperty_MaxElementDepth property */
332 reader->depth++;
333 return S_OK;
336 static HRESULT reader_push_element(xmlreader *reader, strval *qname)
338 struct element *elem;
339 HRESULT hr;
341 elem = reader_alloc(reader, sizeof(*elem));
342 if (!elem) return E_OUTOFMEMORY;
344 hr = reader_strvaldup(reader, qname, &elem->qname);
345 if (FAILED(hr)) return hr;
347 if (!list_empty(&reader->elements))
349 hr = reader_inc_depth(reader);
350 if (FAILED(hr)) return hr;
353 list_add_head(&reader->elements, &elem->entry);
354 return hr;
357 static void reader_pop_element(xmlreader *reader)
359 struct element *elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
361 if (elem)
363 list_remove(&elem->entry);
364 reader_free_strvalued(reader, &elem->qname);
365 reader_free(reader, elem);
369 /* Always make a copy, cause strings are supposed to be null terminated. Null pointer for 'value'
370 means node value is to be determined. */
371 static void reader_set_strvalue(xmlreader *reader, XmlReaderStringValue type, const strval *value)
373 strval *v = &reader->strvalues[type];
375 reader_free_strvalue(reader, type);
376 if (!value)
378 v->str = NULL;
379 v->len = 0;
380 return;
383 if (value->str == strval_empty.str)
384 *v = *value;
385 else
387 v->str = reader_alloc(reader, (value->len + 1)*sizeof(WCHAR));
388 memcpy(v->str, value->str, value->len*sizeof(WCHAR));
389 v->str[value->len] = 0;
390 v->len = value->len;
394 static inline int is_reader_pending(xmlreader *reader)
396 return reader->input->pending;
399 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
401 const int initial_len = 0x2000;
402 buffer->data = readerinput_alloc(input, initial_len);
403 if (!buffer->data) return E_OUTOFMEMORY;
405 memset(buffer->data, 0, 4);
406 buffer->cur = buffer->data;
407 buffer->allocated = initial_len;
408 buffer->written = 0;
410 return S_OK;
413 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
415 readerinput_free(input, buffer->data);
418 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
420 if (encoding == XmlEncoding_Unknown)
422 FIXME("unsupported encoding %d\n", encoding);
423 return E_NOTIMPL;
426 *cp = xml_encoding_map[encoding].cp;
428 return S_OK;
431 static xml_encoding parse_encoding_name(const WCHAR *name, int len)
433 int min, max, n, c;
435 if (!name) return XmlEncoding_Unknown;
437 min = 0;
438 max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
440 while (min <= max)
442 n = (min+max)/2;
444 if (len != -1)
445 c = strncmpiW(xml_encoding_map[n].name, name, len);
446 else
447 c = strcmpiW(xml_encoding_map[n].name, name);
448 if (!c)
449 return xml_encoding_map[n].enc;
451 if (c > 0)
452 max = n-1;
453 else
454 min = n+1;
457 return XmlEncoding_Unknown;
460 static HRESULT alloc_input_buffer(xmlreaderinput *input)
462 input_buffer *buffer;
463 HRESULT hr;
465 input->buffer = NULL;
467 buffer = readerinput_alloc(input, sizeof(*buffer));
468 if (!buffer) return E_OUTOFMEMORY;
470 buffer->input = input;
471 buffer->code_page = ~0; /* code page is unknown at this point */
472 hr = init_encoded_buffer(input, &buffer->utf16);
473 if (hr != S_OK) {
474 readerinput_free(input, buffer);
475 return hr;
478 hr = init_encoded_buffer(input, &buffer->encoded);
479 if (hr != S_OK) {
480 free_encoded_buffer(input, &buffer->utf16);
481 readerinput_free(input, buffer);
482 return hr;
485 input->buffer = buffer;
486 return S_OK;
489 static void free_input_buffer(input_buffer *buffer)
491 free_encoded_buffer(buffer->input, &buffer->encoded);
492 free_encoded_buffer(buffer->input, &buffer->utf16);
493 readerinput_free(buffer->input, buffer);
496 static void readerinput_release_stream(xmlreaderinput *readerinput)
498 if (readerinput->stream) {
499 ISequentialStream_Release(readerinput->stream);
500 readerinput->stream = NULL;
504 /* Queries already stored interface for IStream/ISequentialStream.
505 Interface supplied on creation will be overwritten */
506 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
508 HRESULT hr;
510 readerinput_release_stream(readerinput);
511 hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
512 if (hr != S_OK)
513 hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
515 return hr;
518 /* reads a chunk to raw buffer */
519 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
521 encoded_buffer *buffer = &readerinput->buffer->encoded;
522 /* to make sure aligned length won't exceed allocated length */
523 ULONG len = buffer->allocated - buffer->written - 4;
524 ULONG read;
525 HRESULT hr;
527 /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
528 variable width encodings like UTF-8 */
529 len = (len + 3) & ~3;
530 /* try to use allocated space or grow */
531 if (buffer->allocated - buffer->written < len)
533 buffer->allocated *= 2;
534 buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
535 len = buffer->allocated - buffer->written;
538 read = 0;
539 hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
540 TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
541 readerinput->pending = hr == E_PENDING;
542 if (FAILED(hr)) return hr;
543 buffer->written += read;
545 return hr;
548 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
549 static void readerinput_grow(xmlreaderinput *readerinput, int length)
551 encoded_buffer *buffer = &readerinput->buffer->utf16;
553 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
554 if (buffer->allocated < buffer->written + length + 4)
556 int grown_size = max(2*buffer->allocated, buffer->allocated + length);
557 buffer->data = readerinput_realloc(readerinput, buffer->data, grown_size);
558 buffer->allocated = grown_size;
562 static inline int readerinput_is_utf8(xmlreaderinput *readerinput)
564 static char startA[] = {'<','?'};
565 static char commentA[] = {'<','!'};
566 encoded_buffer *buffer = &readerinput->buffer->encoded;
567 unsigned char *ptr = (unsigned char*)buffer->data;
569 return !memcmp(buffer->data, startA, sizeof(startA)) ||
570 !memcmp(buffer->data, commentA, sizeof(commentA)) ||
571 /* test start byte */
572 (ptr[0] == '<' &&
574 (ptr[1] && (ptr[1] <= 0x7f)) ||
575 (buffer->data[1] >> 5) == 0x6 || /* 2 bytes */
576 (buffer->data[1] >> 4) == 0xe || /* 3 bytes */
577 (buffer->data[1] >> 3) == 0x1e) /* 4 bytes */
581 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
583 encoded_buffer *buffer = &readerinput->buffer->encoded;
584 static WCHAR startW[] = {'<','?'};
585 static WCHAR commentW[] = {'<','!'};
586 static char utf8bom[] = {0xef,0xbb,0xbf};
587 static char utf16lebom[] = {0xff,0xfe};
589 *enc = XmlEncoding_Unknown;
591 if (buffer->written <= 3) return MX_E_INPUTEND;
593 /* try start symbols if we have enough data to do that, input buffer should contain
594 first chunk already */
595 if (readerinput_is_utf8(readerinput))
596 *enc = XmlEncoding_UTF8;
597 else if (!memcmp(buffer->data, startW, sizeof(startW)) ||
598 !memcmp(buffer->data, commentW, sizeof(commentW)))
599 *enc = XmlEncoding_UTF16;
600 /* try with BOM now */
601 else if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom)))
603 buffer->cur += sizeof(utf8bom);
604 *enc = XmlEncoding_UTF8;
606 else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
608 buffer->cur += sizeof(utf16lebom);
609 *enc = XmlEncoding_UTF16;
612 return S_OK;
615 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
617 encoded_buffer *buffer = &readerinput->buffer->encoded;
618 int len = buffer->written;
620 /* complete single byte char */
621 if (!(buffer->data[len-1] & 0x80)) return len;
623 /* find start byte of multibyte char */
624 while (--len && !(buffer->data[len] & 0xc0))
627 return len;
630 /* Returns byte length of complete char sequence for buffer code page,
631 it's relative to current buffer position which is currently used for BOM handling
632 only. */
633 static int readerinput_get_convlen(xmlreaderinput *readerinput)
635 encoded_buffer *buffer = &readerinput->buffer->encoded;
636 int len;
638 if (readerinput->buffer->code_page == CP_UTF8)
639 len = readerinput_get_utf8_convlen(readerinput);
640 else
641 len = buffer->written;
643 TRACE("%d\n", len - (int)(buffer->cur - buffer->data));
644 return len - (buffer->cur - buffer->data);
647 /* It's possible that raw buffer has some leftovers from last conversion - some char
648 sequence that doesn't represent a full code point. Length argument should be calculated with
649 readerinput_get_convlen(), if it's -1 it will be calculated here. */
650 static void readerinput_shrinkraw(xmlreaderinput *readerinput, int len)
652 encoded_buffer *buffer = &readerinput->buffer->encoded;
654 if (len == -1)
655 len = readerinput_get_convlen(readerinput);
657 memmove(buffer->data, buffer->cur + (buffer->written - len), len);
658 /* everything below cur is lost too */
659 buffer->written -= len + (buffer->cur - buffer->data);
660 /* after this point we don't need cur pointer really,
661 it's used only to mark where actual data begins when first chunk is read */
662 buffer->cur = buffer->data;
665 /* note that raw buffer content is kept */
666 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
668 encoded_buffer *src = &readerinput->buffer->encoded;
669 encoded_buffer *dest = &readerinput->buffer->utf16;
670 int len, dest_len;
671 HRESULT hr;
672 WCHAR *ptr;
673 UINT cp;
675 hr = get_code_page(enc, &cp);
676 if (FAILED(hr)) return;
678 readerinput->buffer->code_page = cp;
679 len = readerinput_get_convlen(readerinput);
681 TRACE("switching to cp %d\n", cp);
683 /* just copy in this case */
684 if (enc == XmlEncoding_UTF16)
686 readerinput_grow(readerinput, len);
687 memcpy(dest->data, src->cur, len);
688 dest->written += len*sizeof(WCHAR);
689 return;
692 dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
693 readerinput_grow(readerinput, dest_len);
694 ptr = (WCHAR*)dest->data;
695 MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
696 ptr[dest_len] = 0;
697 dest->written += dest_len*sizeof(WCHAR);
700 /* shrinks parsed data a buffer begins with */
701 static void reader_shrink(xmlreader *reader)
703 encoded_buffer *buffer = &reader->input->buffer->utf16;
705 /* avoid to move too often using threshold shrink length */
706 if (buffer->cur - buffer->data > buffer->written / 2)
708 buffer->written -= buffer->cur - buffer->data;
709 memmove(buffer->data, buffer->cur, buffer->written);
710 buffer->cur = buffer->data;
711 *(WCHAR*)&buffer->cur[buffer->written] = 0;
715 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
716 It won't attempt to shrink but will grow destination buffer if needed */
717 static HRESULT reader_more(xmlreader *reader)
719 xmlreaderinput *readerinput = reader->input;
720 encoded_buffer *src = &readerinput->buffer->encoded;
721 encoded_buffer *dest = &readerinput->buffer->utf16;
722 UINT cp = readerinput->buffer->code_page;
723 int len, dest_len;
724 HRESULT hr;
725 WCHAR *ptr;
727 /* get some raw data from stream first */
728 hr = readerinput_growraw(readerinput);
729 len = readerinput_get_convlen(readerinput);
731 /* just copy for UTF-16 case */
732 if (cp == ~0)
734 readerinput_grow(readerinput, len);
735 memcpy(dest->data, src->cur, len);
736 dest->written += len*sizeof(WCHAR);
737 return hr;
740 dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
741 readerinput_grow(readerinput, dest_len);
742 ptr = (WCHAR*)dest->data;
743 MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
744 ptr[dest_len] = 0;
745 dest->written += dest_len*sizeof(WCHAR);
746 /* get rid of processed data */
747 readerinput_shrinkraw(readerinput, len);
749 return hr;
752 static inline WCHAR *reader_get_cur(xmlreader *reader)
754 WCHAR *ptr = (WCHAR*)reader->input->buffer->utf16.cur;
755 if (!*ptr) reader_more(reader);
756 return ptr;
759 static int reader_cmp(xmlreader *reader, const WCHAR *str)
761 const WCHAR *ptr = reader_get_cur(reader);
762 return strncmpW(str, ptr, strlenW(str));
765 /* moves cursor n WCHARs forward */
766 static void reader_skipn(xmlreader *reader, int n)
768 encoded_buffer *buffer = &reader->input->buffer->utf16;
769 const WCHAR *ptr = reader_get_cur(reader);
771 while (*ptr++ && n--)
773 buffer->cur += sizeof(WCHAR);
774 reader->pos++;
778 static inline int is_wchar_space(WCHAR ch)
780 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
783 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
784 static int reader_skipspaces(xmlreader *reader)
786 encoded_buffer *buffer = &reader->input->buffer->utf16;
787 const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
789 while (is_wchar_space(*ptr))
791 buffer->cur += sizeof(WCHAR);
792 if (*ptr == '\r')
793 reader->pos = 0;
794 else if (*ptr == '\n')
796 reader->line++;
797 reader->pos = 0;
799 else
800 reader->pos++;
801 ptr++;
804 return ptr - start;
807 /* [26] VersionNum ::= '1.' [0-9]+ */
808 static HRESULT reader_parse_versionnum(xmlreader *reader, strval *val)
810 WCHAR *ptr, *ptr2, *start = reader_get_cur(reader);
811 static const WCHAR onedotW[] = {'1','.',0};
813 if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
814 /* skip "1." */
815 reader_skipn(reader, 2);
817 ptr2 = ptr = reader_get_cur(reader);
818 while (*ptr >= '0' && *ptr <= '9')
819 ptr++;
821 if (ptr2 == ptr) return WC_E_DIGIT;
822 TRACE("version=%s\n", debugstr_wn(start, ptr-start));
823 val->str = start;
824 val->len = ptr-start;
825 reader_skipn(reader, ptr-ptr2);
826 return S_OK;
829 /* [25] Eq ::= S? '=' S? */
830 static HRESULT reader_parse_eq(xmlreader *reader)
832 static const WCHAR eqW[] = {'=',0};
833 reader_skipspaces(reader);
834 if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
835 /* skip '=' */
836 reader_skipn(reader, 1);
837 reader_skipspaces(reader);
838 return S_OK;
841 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
842 static HRESULT reader_parse_versioninfo(xmlreader *reader)
844 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
845 strval val, name;
846 HRESULT hr;
848 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
850 if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
851 name.str = reader_get_cur(reader);
852 name.len = 7;
853 /* skip 'version' */
854 reader_skipn(reader, 7);
856 hr = reader_parse_eq(reader);
857 if (FAILED(hr)) return hr;
859 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
860 return WC_E_QUOTE;
861 /* skip "'"|'"' */
862 reader_skipn(reader, 1);
864 hr = reader_parse_versionnum(reader, &val);
865 if (FAILED(hr)) return hr;
867 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
868 return WC_E_QUOTE;
870 /* skip "'"|'"' */
871 reader_skipn(reader, 1);
873 return reader_add_attr(reader, &name, &val);
876 /* ([A-Za-z0-9._] | '-') */
877 static inline int is_wchar_encname(WCHAR ch)
879 return ((ch >= 'A' && ch <= 'Z') ||
880 (ch >= 'a' && ch <= 'z') ||
881 (ch >= '0' && ch <= '9') ||
882 (ch == '.') || (ch == '_') ||
883 (ch == '-'));
886 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
887 static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
889 WCHAR *start = reader_get_cur(reader), *ptr;
890 xml_encoding enc;
891 int len;
893 if ((*start < 'A' || *start > 'Z') && (*start < 'a' || *start > 'z'))
894 return WC_E_ENCNAME;
896 ptr = start;
897 while (is_wchar_encname(*++ptr))
900 len = ptr - start;
901 enc = parse_encoding_name(start, len);
902 TRACE("encoding name %s\n", debugstr_wn(start, len));
903 val->str = start;
904 val->len = len;
906 if (enc == XmlEncoding_Unknown)
907 return WC_E_ENCNAME;
909 /* skip encoding name */
910 reader_skipn(reader, len);
911 return S_OK;
914 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
915 static HRESULT reader_parse_encdecl(xmlreader *reader)
917 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
918 strval name, val;
919 HRESULT hr;
921 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
923 if (reader_cmp(reader, encodingW)) return S_FALSE;
924 name.str = reader_get_cur(reader);
925 name.len = 8;
926 /* skip 'encoding' */
927 reader_skipn(reader, 8);
929 hr = reader_parse_eq(reader);
930 if (FAILED(hr)) return hr;
932 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
933 return WC_E_QUOTE;
934 /* skip "'"|'"' */
935 reader_skipn(reader, 1);
937 hr = reader_parse_encname(reader, &val);
938 if (FAILED(hr)) return hr;
940 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
941 return WC_E_QUOTE;
943 /* skip "'"|'"' */
944 reader_skipn(reader, 1);
946 return reader_add_attr(reader, &name, &val);
949 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
950 static HRESULT reader_parse_sddecl(xmlreader *reader)
952 static const WCHAR standaloneW[] = {'s','t','a','n','d','a','l','o','n','e',0};
953 static const WCHAR yesW[] = {'y','e','s',0};
954 static const WCHAR noW[] = {'n','o',0};
955 WCHAR *start, *ptr;
956 strval name, val;
957 HRESULT hr;
959 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
961 if (reader_cmp(reader, standaloneW)) return S_FALSE;
962 name.str = reader_get_cur(reader);
963 name.len = 10;
964 /* skip 'standalone' */
965 reader_skipn(reader, 10);
967 hr = reader_parse_eq(reader);
968 if (FAILED(hr)) return hr;
970 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
971 return WC_E_QUOTE;
972 /* skip "'"|'"' */
973 reader_skipn(reader, 1);
975 if (reader_cmp(reader, yesW) && reader_cmp(reader, noW))
976 return WC_E_XMLDECL;
978 start = reader_get_cur(reader);
979 /* skip 'yes'|'no' */
980 reader_skipn(reader, reader_cmp(reader, yesW) ? 2 : 3);
981 ptr = reader_get_cur(reader);
982 TRACE("standalone=%s\n", debugstr_wn(start, ptr-start));
983 val.str = start;
984 val.len = ptr-start;
986 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
987 return WC_E_QUOTE;
988 /* skip "'"|'"' */
989 reader_skipn(reader, 1);
991 return reader_add_attr(reader, &name, &val);
994 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
995 static HRESULT reader_parse_xmldecl(xmlreader *reader)
997 static const WCHAR xmldeclW[] = {'<','?','x','m','l',' ',0};
998 static const WCHAR declcloseW[] = {'?','>',0};
999 HRESULT hr;
1001 /* check if we have "<?xml " */
1002 if (reader_cmp(reader, xmldeclW)) return S_FALSE;
1004 reader_skipn(reader, 5);
1005 hr = reader_parse_versioninfo(reader);
1006 if (FAILED(hr))
1007 return hr;
1009 hr = reader_parse_encdecl(reader);
1010 if (FAILED(hr))
1011 return hr;
1013 hr = reader_parse_sddecl(reader);
1014 if (FAILED(hr))
1015 return hr;
1017 reader_skipspaces(reader);
1018 if (reader_cmp(reader, declcloseW)) return WC_E_XMLDECL;
1019 reader_skipn(reader, 2);
1021 reader->nodetype = XmlNodeType_XmlDeclaration;
1022 reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1023 reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1024 reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1026 return S_OK;
1029 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1030 static HRESULT reader_parse_comment(xmlreader *reader)
1032 WCHAR *start, *ptr;
1034 if (reader->save)
1036 start = reader->save;
1037 ptr = reader_get_cur(reader);
1039 else
1041 /* skip '<!--' */
1042 reader_skipn(reader, 4);
1043 reader_shrink(reader);
1044 ptr = start = reader_get_cur(reader);
1045 reader->nodetype = XmlNodeType_Comment;
1046 reader->save = start;
1047 reader_set_strvalue(reader, StringValue_LocalName, NULL);
1048 reader_set_strvalue(reader, StringValue_QualifiedName, NULL);
1049 reader_set_strvalue(reader, StringValue_Value, NULL);
1052 /* will exit when there's no more data, it won't attempt to
1053 read more from stream */
1054 while (*ptr)
1056 if (ptr[0] == '-')
1058 if (ptr[1] == '-')
1060 if (ptr[2] == '>')
1062 strval value = { start, ptr-start };
1064 TRACE("%s\n", debugstr_wn(start, ptr-start));
1065 /* skip '-->' */
1066 reader_skipn(reader, 3);
1067 reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1068 reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1069 reader_set_strvalue(reader, StringValue_Value, &value);
1070 reader->save = NULL;
1071 return S_OK;
1073 else
1074 return WC_E_COMMENT;
1076 else
1077 ptr++;
1079 else
1081 reader_skipn(reader, 1);
1082 ptr++;
1086 return S_OK;
1089 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1090 static inline int is_char(WCHAR ch)
1092 return (ch == '\t') || (ch == '\r') || (ch == '\n') ||
1093 (ch >= 0x20 && ch <= 0xd7ff) ||
1094 (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1095 (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1096 (ch >= 0xe000 && ch <= 0xfffd);
1099 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1100 static inline int is_pubchar(WCHAR ch)
1102 return (ch == ' ') ||
1103 (ch >= 'a' && ch <= 'z') ||
1104 (ch >= 'A' && ch <= 'Z') ||
1105 (ch >= '0' && ch <= '9') ||
1106 (ch >= '-' && ch <= ';') || /* '()*+,-./:; */
1107 (ch == '=') || (ch == '?') ||
1108 (ch == '@') || (ch == '!') ||
1109 (ch >= '#' && ch <= '%') || /* #$% */
1110 (ch == '_') || (ch == '\r') || (ch == '\n');
1113 static inline int is_namestartchar(WCHAR ch)
1115 return (ch == ':') || (ch >= 'A' && ch <= 'Z') ||
1116 (ch == '_') || (ch >= 'a' && ch <= 'z') ||
1117 (ch >= 0xc0 && ch <= 0xd6) ||
1118 (ch >= 0xd8 && ch <= 0xf6) ||
1119 (ch >= 0xf8 && ch <= 0x2ff) ||
1120 (ch >= 0x370 && ch <= 0x37d) ||
1121 (ch >= 0x37f && ch <= 0x1fff) ||
1122 (ch >= 0x200c && ch <= 0x200d) ||
1123 (ch >= 0x2070 && ch <= 0x218f) ||
1124 (ch >= 0x2c00 && ch <= 0x2fef) ||
1125 (ch >= 0x3001 && ch <= 0xd7ff) ||
1126 (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1127 (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1128 (ch >= 0xf900 && ch <= 0xfdcf) ||
1129 (ch >= 0xfdf0 && ch <= 0xfffd);
1132 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1133 static inline int is_ncnamechar(WCHAR ch)
1135 return (ch >= 'A' && ch <= 'Z') ||
1136 (ch == '_') || (ch >= 'a' && ch <= 'z') ||
1137 (ch == '-') || (ch == '.') ||
1138 (ch >= '0' && ch <= '9') ||
1139 (ch == 0xb7) ||
1140 (ch >= 0xc0 && ch <= 0xd6) ||
1141 (ch >= 0xd8 && ch <= 0xf6) ||
1142 (ch >= 0xf8 && ch <= 0x2ff) ||
1143 (ch >= 0x300 && ch <= 0x36f) ||
1144 (ch >= 0x370 && ch <= 0x37d) ||
1145 (ch >= 0x37f && ch <= 0x1fff) ||
1146 (ch >= 0x200c && ch <= 0x200d) ||
1147 (ch >= 0x203f && ch <= 0x2040) ||
1148 (ch >= 0x2070 && ch <= 0x218f) ||
1149 (ch >= 0x2c00 && ch <= 0x2fef) ||
1150 (ch >= 0x3001 && ch <= 0xd7ff) ||
1151 (ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
1152 (ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
1153 (ch >= 0xf900 && ch <= 0xfdcf) ||
1154 (ch >= 0xfdf0 && ch <= 0xfffd);
1157 static inline int is_namechar(WCHAR ch)
1159 return (ch == ':') || is_ncnamechar(ch);
1162 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
1163 [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
1164 [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
1165 [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
1166 [5] Name ::= NameStartChar (NameChar)* */
1167 static HRESULT reader_parse_name(xmlreader *reader, strval *name)
1169 WCHAR *ptr, *start = reader_get_cur(reader);
1171 ptr = start;
1172 if (!is_namestartchar(*ptr)) return WC_E_NAMECHARACTER;
1174 while (is_namechar(*ptr))
1176 reader_skipn(reader, 1);
1177 ptr = reader_get_cur(reader);
1180 TRACE("name %s:%d\n", debugstr_wn(start, ptr-start), (int)(ptr-start));
1181 name->str = start;
1182 name->len = ptr-start;
1184 return S_OK;
1187 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1188 static HRESULT reader_parse_pitarget(xmlreader *reader, strval *target)
1190 static const WCHAR xmlW[] = {'x','m','l'};
1191 strval name;
1192 HRESULT hr;
1193 int i;
1195 hr = reader_parse_name(reader, &name);
1196 if (FAILED(hr)) return WC_E_PI;
1198 /* now that we got name check for illegal content */
1199 if (name.len == 3 && !strncmpiW(name.str, xmlW, 3))
1200 return WC_E_LEADINGXML;
1202 /* PITarget can't be a qualified name */
1203 for (i = 0; i < name.len; i++)
1204 if (name.str[i] == ':')
1205 return i ? NC_E_NAMECOLON : WC_E_PI;
1207 TRACE("pitarget %s:%d\n", debugstr_wn(name.str, name.len), name.len);
1208 *target = name;
1209 return S_OK;
1212 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1213 static HRESULT reader_parse_pi(xmlreader *reader)
1215 WCHAR *ptr, *start;
1216 strval target;
1217 HRESULT hr;
1219 /* skip '<?' */
1220 reader_skipn(reader, 2);
1221 reader_shrink(reader);
1223 hr = reader_parse_pitarget(reader, &target);
1224 if (FAILED(hr)) return hr;
1226 ptr = reader_get_cur(reader);
1227 /* exit earlier if there's no content */
1228 if (ptr[0] == '?' && ptr[1] == '>')
1230 /* skip '?>' */
1231 reader_skipn(reader, 2);
1232 reader->nodetype = XmlNodeType_ProcessingInstruction;
1233 reader_set_strvalue(reader, StringValue_LocalName, &target);
1234 reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1235 reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1236 return S_OK;
1239 /* now at least a single space char should be there */
1240 if (!is_wchar_space(*ptr)) return WC_E_WHITESPACE;
1241 reader_skipspaces(reader);
1243 ptr = start = reader_get_cur(reader);
1245 while (*ptr)
1247 if (ptr[0] == '?')
1249 if (ptr[1] == '>')
1251 strval value = { start, ptr-start };
1253 TRACE("%s\n", debugstr_wn(start, ptr-start));
1254 /* skip '?>' */
1255 reader_skipn(reader, 2);
1256 reader->nodetype = XmlNodeType_ProcessingInstruction;
1257 reader_set_strvalue(reader, StringValue_LocalName, &target);
1258 reader_set_strvalue(reader, StringValue_QualifiedName, &target);
1259 reader_set_strvalue(reader, StringValue_Value, &value);
1260 return S_OK;
1262 else
1264 ptr++;
1265 reader_more(reader);
1268 else
1270 reader_skipn(reader, 1);
1271 ptr = reader_get_cur(reader);
1275 return S_OK;
1278 /* This one is used to parse significant whitespace nodes, like in Misc production */
1279 static HRESULT reader_parse_whitespace(xmlreader *reader)
1281 WCHAR *start, *ptr;
1283 reader_shrink(reader);
1284 start = reader_get_cur(reader);
1286 reader_skipspaces(reader);
1287 ptr = reader_get_cur(reader);
1288 TRACE("%s\n", debugstr_wn(start, ptr-start));
1290 reader->nodetype = XmlNodeType_Whitespace;
1291 reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
1292 reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
1293 reader_set_strvalue(reader, StringValue_Value, &strval_empty);
1294 return S_OK;
1297 /* [27] Misc ::= Comment | PI | S */
1298 static HRESULT reader_parse_misc(xmlreader *reader)
1300 HRESULT hr = S_FALSE;
1302 if (is_reader_pending(reader))
1304 hr = reader_more(reader);
1305 if (FAILED(hr)) return hr;
1307 /* finish current node */
1308 if (reader->nodetype == XmlNodeType_Comment)
1309 return reader_parse_comment(reader);
1312 while (1)
1314 const WCHAR *cur = reader_get_cur(reader);
1316 if (is_wchar_space(*cur))
1317 hr = reader_parse_whitespace(reader);
1318 else if (!reader_cmp(reader, commentW))
1319 hr = reader_parse_comment(reader);
1320 else if (!reader_cmp(reader, piW))
1321 hr = reader_parse_pi(reader);
1322 else
1323 break;
1325 if (hr != S_FALSE) return hr;
1328 return hr;
1331 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1332 static HRESULT reader_parse_sys_literal(xmlreader *reader, strval *literal)
1334 WCHAR *start = reader_get_cur(reader), *cur, quote;
1336 if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1338 quote = *start;
1339 reader_skipn(reader, 1);
1341 cur = start = reader_get_cur(reader);
1342 while (is_char(*cur) && *cur != quote)
1344 reader_skipn(reader, 1);
1345 cur = reader_get_cur(reader);
1347 if (*cur == quote) reader_skipn(reader, 1);
1349 literal->str = start;
1350 literal->len = cur-start;
1351 TRACE("%s\n", debugstr_wn(start, cur-start));
1352 return S_OK;
1355 /* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1356 [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1357 static HRESULT reader_parse_pub_literal(xmlreader *reader, strval *literal)
1359 WCHAR *start = reader_get_cur(reader), *cur, quote;
1361 if (*start != '"' && *start != '\'') return WC_E_QUOTE;
1363 quote = *start;
1364 reader_skipn(reader, 1);
1366 cur = start;
1367 while (is_pubchar(*cur) && *cur != quote)
1369 reader_skipn(reader, 1);
1370 cur = reader_get_cur(reader);
1373 literal->str = start;
1374 literal->len = cur-start;
1375 TRACE("%s\n", debugstr_wn(start, cur-start));
1376 return S_OK;
1379 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1380 static HRESULT reader_parse_externalid(xmlreader *reader)
1382 static WCHAR systemW[] = {'S','Y','S','T','E','M',0};
1383 static WCHAR publicW[] = {'P','U','B','L','I','C',0};
1384 strval name;
1385 HRESULT hr;
1386 int cnt;
1388 if (reader_cmp(reader, systemW))
1390 if (reader_cmp(reader, publicW))
1391 return S_FALSE;
1392 else
1394 strval pub;
1396 /* public id */
1397 reader_skipn(reader, 6);
1398 cnt = reader_skipspaces(reader);
1399 if (!cnt) return WC_E_WHITESPACE;
1401 hr = reader_parse_pub_literal(reader, &pub);
1402 if (FAILED(hr)) return hr;
1404 name.str = publicW;
1405 name.len = strlenW(publicW);
1406 return reader_add_attr(reader, &name, &pub);
1409 else
1411 strval sys;
1413 /* system id */
1414 reader_skipn(reader, 6);
1415 cnt = reader_skipspaces(reader);
1416 if (!cnt) return WC_E_WHITESPACE;
1418 hr = reader_parse_sys_literal(reader, &sys);
1419 if (FAILED(hr)) return hr;
1421 name.str = systemW;
1422 name.len = strlenW(systemW);
1423 return reader_add_attr(reader, &name, &sys);
1426 return hr;
1429 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1430 static HRESULT reader_parse_dtd(xmlreader *reader)
1432 static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',0};
1433 strval name;
1434 WCHAR *cur;
1435 HRESULT hr;
1437 /* check if we have "<!DOCTYPE" */
1438 if (reader_cmp(reader, doctypeW)) return S_FALSE;
1439 reader_shrink(reader);
1441 /* DTD processing is not allowed by default */
1442 if (reader->dtdmode == DtdProcessing_Prohibit) return WC_E_DTDPROHIBITED;
1444 reader_skipn(reader, 9);
1445 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
1447 /* name */
1448 hr = reader_parse_name(reader, &name);
1449 if (FAILED(hr)) return WC_E_DECLDOCTYPE;
1451 reader_skipspaces(reader);
1453 hr = reader_parse_externalid(reader);
1454 if (FAILED(hr)) return hr;
1456 reader_skipspaces(reader);
1458 cur = reader_get_cur(reader);
1459 if (*cur != '>')
1461 FIXME("internal subset parsing not implemented\n");
1462 return E_NOTIMPL;
1465 /* skip '>' */
1466 reader_skipn(reader, 1);
1468 reader->nodetype = XmlNodeType_DocumentType;
1469 reader_set_strvalue(reader, StringValue_LocalName, &name);
1470 reader_set_strvalue(reader, StringValue_QualifiedName, &name);
1472 return S_OK;
1475 /* [7 NS] QName ::= PrefixedName | UnprefixedName
1476 [8 NS] PrefixedName ::= Prefix ':' LocalPart
1477 [9 NS] UnprefixedName ::= LocalPart
1478 [10 NS] Prefix ::= NCName
1479 [11 NS] LocalPart ::= NCName */
1480 static HRESULT reader_parse_qname(xmlreader *reader, strval *prefix, strval *local, strval *qname)
1482 WCHAR *ptr, *start = reader_get_cur(reader);
1484 ptr = start;
1485 if (!is_ncnamechar(*ptr)) return NC_E_QNAMECHARACTER;
1487 while (is_ncnamechar(*ptr))
1489 reader_skipn(reader, 1);
1490 ptr = reader_get_cur(reader);
1493 /* got a qualified name */
1494 if (*ptr == ':')
1496 prefix->str = start;
1497 prefix->len = ptr-start;
1499 reader_skipn(reader, 1);
1500 start = ptr = reader_get_cur(reader);
1502 while (is_ncnamechar(*ptr))
1504 reader_skipn(reader, 1);
1505 ptr = reader_get_cur(reader);
1508 else
1510 prefix->str = NULL;
1511 prefix->len = 0;
1514 local->str = start;
1515 local->len = ptr-start;
1517 if (prefix->len)
1518 TRACE("qname %s:%s\n", debugstr_wn(prefix->str, prefix->len), debugstr_wn(local->str, local->len));
1519 else
1520 TRACE("ncname %s\n", debugstr_wn(local->str, local->len));
1522 qname->str = prefix->str ? prefix->str : local->str;
1523 /* count ':' too */
1524 qname->len = (prefix->len ? prefix->len + 1 : 0) + local->len;
1526 return S_OK;
1529 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
1530 [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
1531 static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *local, strval *qname, int *empty)
1533 static const WCHAR endW[] = {'/','>',0};
1534 HRESULT hr;
1536 /* skip '<' */
1537 reader_skipn(reader, 1);
1539 hr = reader_parse_qname(reader, prefix, local, qname);
1540 if (FAILED(hr)) return hr;
1542 reader_skipspaces(reader);
1544 /* empty element */
1545 if ((*empty = !reader_cmp(reader, endW)))
1547 /* skip '/>' */
1548 reader_skipn(reader, 2);
1549 return S_OK;
1552 /* got a start tag */
1553 if (!reader_cmp(reader, gtW))
1555 /* skip '>' */
1556 reader_skipn(reader, 1);
1557 return reader_push_element(reader, qname);
1560 FIXME("only empty elements/start tags without attribute list supported\n");
1561 return E_NOTIMPL;
1564 /* [39] element ::= EmptyElemTag | STag content ETag */
1565 static HRESULT reader_parse_element(xmlreader *reader)
1567 strval qname, prefix, local;
1568 HRESULT hr;
1569 int empty;
1571 /* check if we are really on element */
1572 if (reader_cmp(reader, ltW)) return S_FALSE;
1573 reader_shrink(reader);
1575 /* this handles empty elements too */
1576 empty = 0;
1577 hr = reader_parse_stag(reader, &prefix, &local, &qname, &empty);
1578 if (FAILED(hr)) return hr;
1580 /* FIXME: need to check for defined namespace to reject invalid prefix,
1581 currently reject all prefixes */
1582 if (prefix.len) return NC_E_UNDECLAREDPREFIX;
1584 /* if we got empty element and stack is empty go straight to Misc */
1585 if (empty && list_empty(&reader->elements))
1586 reader->instate = XmlReadInState_MiscEnd;
1587 else
1588 reader->instate = XmlReadInState_Content;
1590 reader->nodetype = XmlNodeType_Element;
1591 reader_set_strvalue(reader, StringValue_LocalName, &local);
1592 reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
1594 return hr;
1597 /* [13 NS] ETag ::= '</' QName S? '>' */
1598 static HRESULT reader_parse_endtag(xmlreader *reader)
1600 strval prefix, local, qname;
1601 struct element *elem;
1602 HRESULT hr;
1604 /* skip '</' */
1605 reader_skipn(reader, 2);
1607 hr = reader_parse_qname(reader, &prefix, &local, &qname);
1608 if (FAILED(hr)) return hr;
1610 reader_skipspaces(reader);
1612 if (reader_cmp(reader, gtW)) return WC_E_GREATERTHAN;
1614 /* skip '>' */
1615 reader_skipn(reader, 1);
1617 /* Element stack should never be empty at this point, cause we shouldn't get to
1618 content parsing if it's empty. */
1619 elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
1620 if (!strval_eq(&elem->qname, &qname)) return WC_E_ELEMENTMATCH;
1622 reader_pop_element(reader);
1624 reader->nodetype = XmlNodeType_EndElement;
1625 reader_set_strvalue(reader, StringValue_LocalName, &local);
1626 reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
1628 return S_OK;
1631 /* [18] CDSect ::= CDStart CData CDEnd
1632 [19] CDStart ::= '<![CDATA['
1633 [20] CData ::= (Char* - (Char* ']]>' Char*))
1634 [21] CDEnd ::= ']]>' */
1635 static HRESULT reader_parse_cdata(xmlreader *reader)
1637 FIXME("CDATA sections are not supported\n");
1638 return E_NOTIMPL;
1641 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1642 [67] Reference ::= EntityRef | CharRef
1643 [68] EntityRef ::= '&' Name ';' */
1644 static HRESULT reader_parse_reference(xmlreader *reader)
1646 FIXME("References not supported\n");
1647 return E_NOTIMPL;
1650 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1651 static HRESULT reader_parse_chardata(xmlreader *reader)
1653 FIXME("CharData not supported\n");
1654 return E_NOTIMPL;
1657 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1658 static HRESULT reader_parse_content(xmlreader *reader)
1660 static const WCHAR cdstartW[] = {'<','!','[','C','D','A','T','A','[',0};
1661 static const WCHAR etagW[] = {'<','/',0};
1662 static const WCHAR ampW[] = {'&',0};
1664 reader_shrink(reader);
1666 /* handle end tag here, it indicates end of content as well */
1667 if (!reader_cmp(reader, etagW))
1668 return reader_parse_endtag(reader);
1670 if (!reader_cmp(reader, commentW))
1671 return reader_parse_comment(reader);
1673 if (!reader_cmp(reader, piW))
1674 return reader_parse_pi(reader);
1676 if (!reader_cmp(reader, cdstartW))
1677 return reader_parse_cdata(reader);
1679 if (!reader_cmp(reader, ampW))
1680 return reader_parse_reference(reader);
1682 if (!reader_cmp(reader, ltW))
1683 return reader_parse_element(reader);
1685 /* what's left must be CharData */
1686 return reader_parse_chardata(reader);
1689 static HRESULT reader_parse_nextnode(xmlreader *reader)
1691 HRESULT hr;
1693 while (1)
1695 switch (reader->instate)
1697 /* if it's a first call for a new input we need to detect stream encoding */
1698 case XmlReadInState_Initial:
1700 xml_encoding enc;
1702 hr = readerinput_growraw(reader->input);
1703 if (FAILED(hr)) return hr;
1705 /* try to detect encoding by BOM or data and set input code page */
1706 hr = readerinput_detectencoding(reader->input, &enc);
1707 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
1708 if (FAILED(hr)) return hr;
1710 /* always switch first time cause we have to put something in */
1711 readerinput_switchencoding(reader->input, enc);
1713 /* parse xml declaration */
1714 hr = reader_parse_xmldecl(reader);
1715 if (FAILED(hr)) return hr;
1717 readerinput_shrinkraw(reader->input, -1);
1718 reader->instate = XmlReadInState_Misc_DTD;
1719 if (hr == S_OK) return hr;
1721 break;
1722 case XmlReadInState_Misc_DTD:
1723 hr = reader_parse_misc(reader);
1724 if (FAILED(hr)) return hr;
1726 if (hr == S_FALSE)
1727 reader->instate = XmlReadInState_DTD;
1728 else
1729 return hr;
1730 break;
1731 case XmlReadInState_DTD:
1732 hr = reader_parse_dtd(reader);
1733 if (FAILED(hr)) return hr;
1735 if (hr == S_OK)
1737 reader->instate = XmlReadInState_DTD_Misc;
1738 return hr;
1740 else
1741 reader->instate = XmlReadInState_Element;
1742 break;
1743 case XmlReadInState_DTD_Misc:
1744 hr = reader_parse_misc(reader);
1745 if (FAILED(hr)) return hr;
1747 if (hr == S_FALSE)
1748 reader->instate = XmlReadInState_Element;
1749 else
1750 return hr;
1751 break;
1752 case XmlReadInState_Element:
1753 return reader_parse_element(reader);
1754 case XmlReadInState_Content:
1755 return reader_parse_content(reader);
1756 default:
1757 FIXME("internal state %d not handled\n", reader->instate);
1758 return E_NOTIMPL;
1762 return E_NOTIMPL;
1765 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
1767 xmlreader *This = impl_from_IXmlReader(iface);
1769 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1771 if (IsEqualGUID(riid, &IID_IUnknown) ||
1772 IsEqualGUID(riid, &IID_IXmlReader))
1774 *ppvObject = iface;
1776 else
1778 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1779 *ppvObject = NULL;
1780 return E_NOINTERFACE;
1783 IXmlReader_AddRef(iface);
1785 return S_OK;
1788 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
1790 xmlreader *This = impl_from_IXmlReader(iface);
1791 ULONG ref = InterlockedIncrement(&This->ref);
1792 TRACE("(%p)->(%d)\n", This, ref);
1793 return ref;
1796 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
1798 xmlreader *This = impl_from_IXmlReader(iface);
1799 LONG ref = InterlockedDecrement(&This->ref);
1801 TRACE("(%p)->(%d)\n", This, ref);
1803 if (ref == 0)
1805 IMalloc *imalloc = This->imalloc;
1806 if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
1807 reader_clear_attrs(This);
1808 reader_clear_elements(This);
1809 reader_free_strvalues(This);
1810 reader_free(This, This);
1811 if (imalloc) IMalloc_Release(imalloc);
1814 return ref;
1817 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
1819 xmlreader *This = impl_from_IXmlReader(iface);
1820 IXmlReaderInput *readerinput;
1821 HRESULT hr;
1823 TRACE("(%p)->(%p)\n", This, input);
1825 if (This->input)
1827 readerinput_release_stream(This->input);
1828 IUnknown_Release(&This->input->IXmlReaderInput_iface);
1829 This->input = NULL;
1832 This->line = This->pos = 0;
1833 reader_clear_elements(This);
1834 This->depth = 0;
1835 This->save = NULL;
1837 /* just reset current input */
1838 if (!input)
1840 This->state = XmlReadState_Initial;
1841 return S_OK;
1844 /* now try IXmlReaderInput, ISequentialStream, IStream */
1845 hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&readerinput);
1846 if (hr == S_OK)
1848 if (readerinput->lpVtbl == &xmlreaderinputvtbl)
1849 This->input = impl_from_IXmlReaderInput(readerinput);
1850 else
1852 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
1853 readerinput, readerinput->lpVtbl);
1854 IUnknown_Release(readerinput);
1855 return E_FAIL;
1860 if (hr != S_OK || !readerinput)
1862 /* create IXmlReaderInput basing on supplied interface */
1863 hr = CreateXmlReaderInputWithEncodingName(input,
1864 NULL, NULL, FALSE, NULL, &readerinput);
1865 if (hr != S_OK) return hr;
1866 This->input = impl_from_IXmlReaderInput(readerinput);
1869 /* set stream for supplied IXmlReaderInput */
1870 hr = readerinput_query_for_stream(This->input);
1871 if (hr == S_OK)
1873 This->state = XmlReadState_Initial;
1874 This->instate = XmlReadInState_Initial;
1877 return hr;
1880 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
1882 xmlreader *This = impl_from_IXmlReader(iface);
1884 TRACE("(%p %u %p)\n", This, property, value);
1886 if (!value) return E_INVALIDARG;
1888 switch (property)
1890 case XmlReaderProperty_DtdProcessing:
1891 *value = This->dtdmode;
1892 break;
1893 case XmlReaderProperty_ReadState:
1894 *value = This->state;
1895 break;
1896 default:
1897 FIXME("Unimplemented property (%u)\n", property);
1898 return E_NOTIMPL;
1901 return S_OK;
1904 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
1906 xmlreader *This = impl_from_IXmlReader(iface);
1908 TRACE("(%p %u %lu)\n", iface, property, value);
1910 switch (property)
1912 case XmlReaderProperty_DtdProcessing:
1913 if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
1914 This->dtdmode = value;
1915 break;
1916 default:
1917 FIXME("Unimplemented property (%u)\n", property);
1918 return E_NOTIMPL;
1921 return S_OK;
1924 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
1926 xmlreader *This = impl_from_IXmlReader(iface);
1927 XmlNodeType oldtype = This->nodetype;
1928 HRESULT hr;
1930 TRACE("(%p)->(%p)\n", This, nodetype);
1932 if (This->state == XmlReadState_Closed) return S_FALSE;
1934 hr = reader_parse_nextnode(This);
1935 if (oldtype == XmlNodeType_None && This->nodetype != oldtype)
1936 This->state = XmlReadState_Interactive;
1937 if (hr == S_OK) *nodetype = This->nodetype;
1939 return hr;
1942 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
1944 xmlreader *This = impl_from_IXmlReader(iface);
1945 TRACE("(%p)->(%p)\n", This, node_type);
1947 /* When we're on attribute always return attribute type, container node type is kept.
1948 Note that container is not necessarily an element, and attribute doesn't mean it's
1949 an attribute in XML spec terms. */
1950 *node_type = This->attr ? XmlNodeType_Attribute : This->nodetype;
1951 return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
1954 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
1956 xmlreader *This = impl_from_IXmlReader(iface);
1958 TRACE("(%p)\n", This);
1960 if (!This->attr_count) return S_FALSE;
1961 This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
1962 return S_OK;
1965 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
1967 xmlreader *This = impl_from_IXmlReader(iface);
1968 const struct list *next;
1970 TRACE("(%p)\n", This);
1972 if (!This->attr_count) return S_FALSE;
1974 if (!This->attr)
1975 return IXmlReader_MoveToFirstAttribute(iface);
1977 next = list_next(&This->attrs, &This->attr->entry);
1978 if (next)
1979 This->attr = LIST_ENTRY(next, struct attribute, entry);
1981 return next ? S_OK : S_FALSE;
1984 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
1985 LPCWSTR local_name,
1986 LPCWSTR namespaceUri)
1988 FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
1989 return E_NOTIMPL;
1992 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
1994 xmlreader *This = impl_from_IXmlReader(iface);
1996 TRACE("(%p)\n", This);
1998 if (!This->attr_count) return S_FALSE;
1999 This->attr = NULL;
2000 return S_OK;
2003 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2005 xmlreader *This = impl_from_IXmlReader(iface);
2007 TRACE("(%p)->(%p %p)\n", This, name, len);
2008 *name = This->strvalues[StringValue_QualifiedName].str;
2009 *len = This->strvalues[StringValue_QualifiedName].len;
2010 return S_OK;
2013 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
2014 LPCWSTR *namespaceUri,
2015 UINT *namespaceUri_length)
2017 FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
2018 return E_NOTIMPL;
2021 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, UINT *len)
2023 xmlreader *This = impl_from_IXmlReader(iface);
2025 TRACE("(%p)->(%p %p)\n", This, name, len);
2026 *name = This->strvalues[StringValue_LocalName].str;
2027 *len = This->strvalues[StringValue_LocalName].len;
2028 return S_OK;
2031 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
2032 LPCWSTR *prefix,
2033 UINT *prefix_length)
2035 FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
2036 return E_NOTIMPL;
2039 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, LPCWSTR *value, UINT *len)
2041 xmlreader *This = impl_from_IXmlReader(iface);
2043 TRACE("(%p)->(%p %p)\n", This, value, len);
2045 if ((This->nodetype == XmlNodeType_Comment && !This->strvalues[StringValue_Value].str) ||
2046 is_reader_pending(This))
2048 XmlNodeType type;
2049 HRESULT hr;
2051 hr = IXmlReader_Read(iface, &type);
2052 if (FAILED(hr)) return hr;
2054 /* return if still pending, partially read values are not reported */
2055 if (is_reader_pending(This)) return E_PENDING;
2058 *value = This->strvalues[StringValue_Value].str;
2059 if (len) *len = This->strvalues[StringValue_Value].len;
2060 return S_OK;
2063 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
2064 WCHAR *buffer,
2065 UINT chunk_size,
2066 UINT *read)
2068 FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
2069 return E_NOTIMPL;
2072 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
2073 LPCWSTR *baseUri,
2074 UINT *baseUri_length)
2076 FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
2077 return E_NOTIMPL;
2080 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
2082 FIXME("(%p): stub\n", iface);
2083 return E_NOTIMPL;
2086 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
2088 FIXME("(%p): stub\n", iface);
2089 return E_NOTIMPL;
2092 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
2094 xmlreader *This = impl_from_IXmlReader(iface);
2096 TRACE("(%p %p)\n", This, lineNumber);
2098 if (!lineNumber) return E_INVALIDARG;
2100 *lineNumber = This->line;
2102 return S_OK;
2105 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
2107 xmlreader *This = impl_from_IXmlReader(iface);
2109 TRACE("(%p %p)\n", This, linePosition);
2111 if (!linePosition) return E_INVALIDARG;
2113 *linePosition = This->pos;
2115 return S_OK;
2118 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
2120 xmlreader *This = impl_from_IXmlReader(iface);
2122 TRACE("(%p)->(%p)\n", This, count);
2124 if (!count) return E_INVALIDARG;
2126 *count = This->attr_count;
2127 return S_OK;
2130 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
2132 xmlreader *This = impl_from_IXmlReader(iface);
2133 TRACE("(%p)->(%p)\n", This, depth);
2134 *depth = This->depth;
2135 return S_OK;
2138 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
2140 FIXME("(%p): stub\n", iface);
2141 return E_NOTIMPL;
2144 static const struct IXmlReaderVtbl xmlreader_vtbl =
2146 xmlreader_QueryInterface,
2147 xmlreader_AddRef,
2148 xmlreader_Release,
2149 xmlreader_SetInput,
2150 xmlreader_GetProperty,
2151 xmlreader_SetProperty,
2152 xmlreader_Read,
2153 xmlreader_GetNodeType,
2154 xmlreader_MoveToFirstAttribute,
2155 xmlreader_MoveToNextAttribute,
2156 xmlreader_MoveToAttributeByName,
2157 xmlreader_MoveToElement,
2158 xmlreader_GetQualifiedName,
2159 xmlreader_GetNamespaceUri,
2160 xmlreader_GetLocalName,
2161 xmlreader_GetPrefix,
2162 xmlreader_GetValue,
2163 xmlreader_ReadValueChunk,
2164 xmlreader_GetBaseUri,
2165 xmlreader_IsDefault,
2166 xmlreader_IsEmptyElement,
2167 xmlreader_GetLineNumber,
2168 xmlreader_GetLinePosition,
2169 xmlreader_GetAttributeCount,
2170 xmlreader_GetDepth,
2171 xmlreader_IsEOF
2174 /** IXmlReaderInput **/
2175 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
2177 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2179 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
2181 if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
2182 IsEqualGUID(riid, &IID_IUnknown))
2184 *ppvObject = iface;
2186 else
2188 WARN("interface %s not implemented\n", debugstr_guid(riid));
2189 *ppvObject = NULL;
2190 return E_NOINTERFACE;
2193 IUnknown_AddRef(iface);
2195 return S_OK;
2198 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
2200 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2201 ULONG ref = InterlockedIncrement(&This->ref);
2202 TRACE("(%p)->(%d)\n", This, ref);
2203 return ref;
2206 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
2208 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
2209 LONG ref = InterlockedDecrement(&This->ref);
2211 TRACE("(%p)->(%d)\n", This, ref);
2213 if (ref == 0)
2215 IMalloc *imalloc = This->imalloc;
2216 if (This->input) IUnknown_Release(This->input);
2217 if (This->stream) ISequentialStream_Release(This->stream);
2218 if (This->buffer) free_input_buffer(This->buffer);
2219 readerinput_free(This, This->baseuri);
2220 readerinput_free(This, This);
2221 if (imalloc) IMalloc_Release(imalloc);
2224 return ref;
2227 static const struct IUnknownVtbl xmlreaderinputvtbl =
2229 xmlreaderinput_QueryInterface,
2230 xmlreaderinput_AddRef,
2231 xmlreaderinput_Release
2234 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
2236 xmlreader *reader;
2237 int i;
2239 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
2241 if (!IsEqualGUID(riid, &IID_IXmlReader))
2243 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
2244 return E_FAIL;
2247 if (imalloc)
2248 reader = IMalloc_Alloc(imalloc, sizeof(*reader));
2249 else
2250 reader = heap_alloc(sizeof(*reader));
2251 if(!reader) return E_OUTOFMEMORY;
2253 reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
2254 reader->ref = 1;
2255 reader->input = NULL;
2256 reader->state = XmlReadState_Closed;
2257 reader->instate = XmlReadInState_Initial;
2258 reader->dtdmode = DtdProcessing_Prohibit;
2259 reader->line = reader->pos = 0;
2260 reader->imalloc = imalloc;
2261 if (imalloc) IMalloc_AddRef(imalloc);
2262 reader->nodetype = XmlNodeType_None;
2263 list_init(&reader->attrs);
2264 reader->attr_count = 0;
2265 reader->attr = NULL;
2266 list_init(&reader->elements);
2267 reader->depth = 0;
2268 reader->save = NULL;
2270 for (i = 0; i < StringValue_Last; i++)
2271 reader->strvalues[i] = strval_empty;
2273 *obj = &reader->IXmlReader_iface;
2275 TRACE("returning iface %p\n", *obj);
2277 return S_OK;
2280 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
2281 IMalloc *imalloc,
2282 LPCWSTR encoding,
2283 BOOL hint,
2284 LPCWSTR base_uri,
2285 IXmlReaderInput **ppInput)
2287 xmlreaderinput *readerinput;
2288 HRESULT hr;
2290 TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
2291 hint, wine_dbgstr_w(base_uri), ppInput);
2293 if (!stream || !ppInput) return E_INVALIDARG;
2295 if (imalloc)
2296 readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
2297 else
2298 readerinput = heap_alloc(sizeof(*readerinput));
2299 if(!readerinput) return E_OUTOFMEMORY;
2301 readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinputvtbl;
2302 readerinput->ref = 1;
2303 readerinput->imalloc = imalloc;
2304 readerinput->stream = NULL;
2305 if (imalloc) IMalloc_AddRef(imalloc);
2306 readerinput->encoding = parse_encoding_name(encoding, -1);
2307 readerinput->hint = hint;
2308 readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
2309 readerinput->pending = 0;
2311 hr = alloc_input_buffer(readerinput);
2312 if (hr != S_OK)
2314 readerinput_free(readerinput, readerinput->baseuri);
2315 readerinput_free(readerinput, readerinput);
2316 if (imalloc) IMalloc_Release(imalloc);
2317 return hr;
2319 IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
2321 *ppInput = &readerinput->IXmlReaderInput_iface;
2323 TRACE("returning iface %p\n", *ppInput);
2325 return S_OK;