2 * IXmlReader implementation
4 * Copyright 2010, 2012 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 } XmlReaderInternalState;
55 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
56 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
58 static const WCHAR dblquoteW[] = {'\"',0};
59 static const WCHAR quoteW[] = {'\'',0};
61 struct xml_encoding_data
68 static const struct xml_encoding_data xml_encoding_map[] = {
69 { utf16W, XmlEncoding_UTF16, ~0 },
70 { utf8W, XmlEncoding_UTF8, CP_UTF8 }
77 unsigned int allocated;
81 typedef struct input_buffer input_buffer;
83 typedef struct _xmlreaderinput
85 IXmlReaderInput IXmlReaderInput_iface;
87 /* reference passed on IXmlReaderInput creation, is kept when input is created */
90 xml_encoding encoding;
93 /* stream reference set after SetInput() call from reader,
94 stored as sequential stream, cause currently
95 optimizations possible with IStream aren't implemented */
96 ISequentialStream *stream;
113 typedef struct _xmlreader
115 IXmlReader IXmlReader_iface;
117 xmlreaderinput *input;
120 XmlReaderInternalState instate;
121 XmlNodeType nodetype;
122 DtdProcessing dtdmode;
123 UINT line, pos; /* reader position in XML stream */
124 struct list attrs; /* attributes list for current node */
125 struct attribute *attr; /* current attribute */
131 encoded_buffer utf16;
132 encoded_buffer encoded;
134 xmlreaderinput *input;
137 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
139 return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
142 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
144 return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
147 static inline void *m_alloc(IMalloc *imalloc, size_t len)
150 return IMalloc_Alloc(imalloc, len);
152 return heap_alloc(len);
155 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
158 return IMalloc_Realloc(imalloc, mem, len);
160 return heap_realloc(mem, len);
163 static inline void m_free(IMalloc *imalloc, void *mem)
166 IMalloc_Free(imalloc, mem);
171 /* reader memory allocation functions */
172 static inline void *reader_alloc(xmlreader *reader, size_t len)
174 return m_alloc(reader->imalloc, len);
177 static inline void reader_free(xmlreader *reader, void *mem)
179 m_free(reader->imalloc, mem);
182 /* reader input memory allocation functions */
183 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
185 return m_alloc(input->imalloc, len);
188 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
190 return m_realloc(input->imalloc, mem, len);
193 static inline void readerinput_free(xmlreaderinput *input, void *mem)
195 m_free(input->imalloc, mem);
198 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
205 size = (strlenW(str)+1)*sizeof(WCHAR);
206 ret = readerinput_alloc(input, size);
207 if (ret) memcpy(ret, str, size);
213 static void reader_clear_attrs(xmlreader *reader)
215 struct attribute *attr, *attr2;
216 LIST_FOR_EACH_ENTRY_SAFE(attr, attr2, &reader->attrs, struct attribute, entry)
218 reader_free(reader, attr);
220 list_init(&reader->attrs);
221 reader->attr_count = 0;
224 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
225 while we are on a node with attributes */
226 static HRESULT reader_add_attr(xmlreader *reader, strval *localname, strval *value)
228 struct attribute *attr;
230 attr = reader_alloc(reader, sizeof(*attr));
231 if (!attr) return E_OUTOFMEMORY;
233 attr->localname = *localname;
234 attr->value = *value;
235 list_add_tail(&reader->attrs, &attr->entry);
236 reader->attr_count++;
241 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
243 const int initial_len = 0x2000;
244 buffer->data = readerinput_alloc(input, initial_len);
245 if (!buffer->data) return E_OUTOFMEMORY;
247 memset(buffer->data, 0, 4);
248 buffer->cur = buffer->data;
249 buffer->allocated = initial_len;
255 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
257 readerinput_free(input, buffer->data);
260 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
262 if (encoding == XmlEncoding_Unknown)
264 FIXME("unsupported encoding %d\n", encoding);
268 *cp = xml_encoding_map[encoding].cp;
273 static xml_encoding parse_encoding_name(const WCHAR *name, int len)
277 if (!name) return XmlEncoding_Unknown;
280 max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
287 c = strncmpiW(xml_encoding_map[n].name, name, len);
289 c = strcmpiW(xml_encoding_map[n].name, name);
291 return xml_encoding_map[n].enc;
299 return XmlEncoding_Unknown;
302 static HRESULT alloc_input_buffer(xmlreaderinput *input)
304 input_buffer *buffer;
307 input->buffer = NULL;
309 buffer = readerinput_alloc(input, sizeof(*buffer));
310 if (!buffer) return E_OUTOFMEMORY;
312 buffer->input = input;
313 buffer->code_page = ~0; /* code page is unknown at this point */
314 hr = init_encoded_buffer(input, &buffer->utf16);
316 readerinput_free(input, buffer);
320 hr = init_encoded_buffer(input, &buffer->encoded);
322 free_encoded_buffer(input, &buffer->utf16);
323 readerinput_free(input, buffer);
327 input->buffer = buffer;
331 static void free_input_buffer(input_buffer *buffer)
333 free_encoded_buffer(buffer->input, &buffer->encoded);
334 free_encoded_buffer(buffer->input, &buffer->utf16);
335 readerinput_free(buffer->input, buffer);
338 static void readerinput_release_stream(xmlreaderinput *readerinput)
340 if (readerinput->stream) {
341 ISequentialStream_Release(readerinput->stream);
342 readerinput->stream = NULL;
346 /* Queries already stored interface for IStream/ISequentialStream.
347 Interface supplied on creation will be overwritten */
348 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
352 readerinput_release_stream(readerinput);
353 hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
355 hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
360 /* reads a chunk to raw buffer */
361 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
363 encoded_buffer *buffer = &readerinput->buffer->encoded;
364 ULONG len = buffer->allocated - buffer->written, read;
367 /* always try to get aligned to 4 bytes, so the only case we can get partialy read characters is
368 variable width encodings like UTF-8 */
369 len = (len + 3) & ~3;
370 /* try to use allocated space or grow */
371 if (buffer->allocated - buffer->written < len)
373 buffer->allocated *= 2;
374 buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
375 len = buffer->allocated - buffer->written;
378 hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
379 if (FAILED(hr)) return hr;
380 TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
381 buffer->written += read;
386 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
387 static void readerinput_grow(xmlreaderinput *readerinput, int length)
389 encoded_buffer *buffer = &readerinput->buffer->utf16;
391 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
392 if (buffer->allocated < buffer->written + length + 4)
394 int grown_size = max(2*buffer->allocated, buffer->allocated + length);
395 buffer->data = readerinput_realloc(readerinput, buffer->data, grown_size);
396 buffer->allocated = grown_size;
400 static HRESULT readerinput_detectencoding(xmlreaderinput *readerinput, xml_encoding *enc)
402 encoded_buffer *buffer = &readerinput->buffer->encoded;
403 static char startA[] = {'<','?','x','m'};
404 static WCHAR startW[] = {'<','?'};
405 static char utf8bom[] = {0xef,0xbb,0xbf};
406 static char utf16lebom[] = {0xff,0xfe};
408 *enc = XmlEncoding_Unknown;
410 if (buffer->written <= 3) return MX_E_INPUTEND;
412 /* try start symbols if we have enough data to do that, input buffer should contain
413 first chunk already */
414 if (!memcmp(buffer->data, startA, sizeof(startA)))
415 *enc = XmlEncoding_UTF8;
416 else if (!memcmp(buffer->data, startW, sizeof(startW)))
417 *enc = XmlEncoding_UTF16;
418 /* try with BOM now */
419 else if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom)))
421 buffer->cur += sizeof(utf8bom);
422 *enc = XmlEncoding_UTF8;
424 else if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom)))
426 buffer->cur += sizeof(utf16lebom);
427 *enc = XmlEncoding_UTF16;
433 static int readerinput_get_utf8_convlen(xmlreaderinput *readerinput)
435 encoded_buffer *buffer = &readerinput->buffer->encoded;
436 int len = buffer->written;
438 /* complete single byte char */
439 if (!(buffer->data[len-1] & 0x80)) return len;
441 /* find start byte of multibyte char */
442 while (--len && !(buffer->data[len] & 0xc0))
448 /* returns byte length of complete char sequence for specified code page, */
449 static int readerinput_get_convlen(xmlreaderinput *readerinput, UINT cp)
451 encoded_buffer *buffer = &readerinput->buffer->encoded;
455 len = readerinput_get_utf8_convlen(readerinput);
457 len = buffer->written;
459 return len - (buffer->cur - buffer->data);
462 /* note that raw buffer content is kept */
463 static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding enc)
465 encoded_buffer *src = &readerinput->buffer->encoded;
466 encoded_buffer *dest = &readerinput->buffer->utf16;
472 hr = get_code_page(enc, &cp);
473 if (FAILED(hr)) return;
475 len = readerinput_get_convlen(readerinput, cp);
477 TRACE("switching to cp %d\n", cp);
479 /* just copy in this case */
480 if (enc == XmlEncoding_UTF16)
482 readerinput_grow(readerinput, len);
483 memcpy(dest->data, src->cur, len);
484 readerinput->buffer->code_page = cp;
488 dest_len = MultiByteToWideChar(cp, 0, src->cur, len, NULL, 0);
489 readerinput_grow(readerinput, dest_len);
490 ptr = (WCHAR*)dest->data;
491 MultiByteToWideChar(cp, 0, src->cur, len, ptr, dest_len);
493 readerinput->buffer->code_page = cp;
496 static inline const WCHAR *reader_get_cur(xmlreader *reader)
498 return (WCHAR*)reader->input->buffer->utf16.cur;
501 static int reader_cmp(xmlreader *reader, const WCHAR *str)
503 const WCHAR *ptr = reader_get_cur(reader);
504 return strncmpW(str, ptr, strlenW(str));
507 /* moves cursor n WCHARs forward */
508 static void reader_skipn(xmlreader *reader, int n)
510 encoded_buffer *buffer = &reader->input->buffer->utf16;
511 const WCHAR *ptr = reader_get_cur(reader);
513 while (*ptr++ && n--)
515 buffer->cur += sizeof(WCHAR);
520 static inline int is_wchar_space(WCHAR ch)
522 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
525 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
526 static int reader_skipspaces(xmlreader *reader)
528 encoded_buffer *buffer = &reader->input->buffer->utf16;
529 const WCHAR *ptr = reader_get_cur(reader), *start = ptr;
531 while (is_wchar_space(*ptr))
533 buffer->cur += sizeof(WCHAR);
536 else if (*ptr == '\n')
549 /* [26] VersionNum ::= '1.' [0-9]+ */
550 static HRESULT reader_parse_versionnum(xmlreader *reader, strval *val)
552 const WCHAR *ptr, *ptr2, *start = reader_get_cur(reader);
553 static const WCHAR onedotW[] = {'1','.',0};
555 if (reader_cmp(reader, onedotW)) return WC_E_XMLDECL;
557 reader_skipn(reader, 2);
559 ptr2 = ptr = reader_get_cur(reader);
560 while (*ptr >= '0' && *ptr <= '9')
563 if (ptr2 == ptr) return WC_E_DIGIT;
564 TRACE("version=%s\n", debugstr_wn(start, ptr-start));
566 val->len = ptr-start;
567 reader_skipn(reader, ptr-ptr2);
571 /* [25] Eq ::= S? '=' S? */
572 static HRESULT reader_parse_eq(xmlreader *reader)
574 static const WCHAR eqW[] = {'=',0};
575 reader_skipspaces(reader);
576 if (reader_cmp(reader, eqW)) return WC_E_EQUAL;
578 reader_skipn(reader, 1);
579 reader_skipspaces(reader);
583 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
584 static HRESULT reader_parse_versioninfo(xmlreader *reader)
586 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
590 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
592 if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
593 name.str = reader_get_cur(reader);
596 reader_skipn(reader, 7);
598 hr = reader_parse_eq(reader);
599 if (FAILED(hr)) return hr;
601 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
604 reader_skipn(reader, 1);
606 hr = reader_parse_versionnum(reader, &val);
607 if (FAILED(hr)) return hr;
609 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
613 reader_skipn(reader, 1);
615 return reader_add_attr(reader, &name, &val);
618 /* ([A-Za-z0-9._] | '-') */
619 static inline int is_wchar_encname(WCHAR ch)
621 return ((ch >= 'A' && ch <= 'Z') ||
622 (ch >= 'a' && ch <= 'z') ||
623 (ch >= '0' && ch <= '9') ||
624 (ch == '.') || (ch == '_') ||
628 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
629 static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
631 const WCHAR *start = reader_get_cur(reader), *ptr;
635 if ((*start < 'A' || *start > 'Z') && (*start < 'a' || *start > 'z'))
639 while (is_wchar_encname(*++ptr))
643 enc = parse_encoding_name(start, len);
644 TRACE("encoding name %s\n", debugstr_wn(start, len));
648 if (enc == XmlEncoding_Unknown)
651 /* skip encoding name */
652 reader_skipn(reader, len);
656 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
657 static HRESULT reader_parse_encdecl(xmlreader *reader)
659 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
663 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
665 if (reader_cmp(reader, encodingW)) return S_FALSE;
666 name.str = reader_get_cur(reader);
668 /* skip 'encoding' */
669 reader_skipn(reader, 8);
671 hr = reader_parse_eq(reader);
672 if (FAILED(hr)) return hr;
674 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
677 reader_skipn(reader, 1);
679 hr = reader_parse_encname(reader, &val);
680 if (FAILED(hr)) return hr;
682 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
686 reader_skipn(reader, 1);
688 return reader_add_attr(reader, &name, &val);
691 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
692 static HRESULT reader_parse_sddecl(xmlreader *reader)
694 static const WCHAR standaloneW[] = {'s','t','a','n','d','a','l','o','n','e',0};
695 static const WCHAR yesW[] = {'y','e','s',0};
696 static const WCHAR noW[] = {'n','o',0};
697 const WCHAR *start, *ptr;
701 if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
703 if (reader_cmp(reader, standaloneW)) return S_FALSE;
704 name.str = reader_get_cur(reader);
706 /* skip 'standalone' */
707 reader_skipn(reader, 10);
709 hr = reader_parse_eq(reader);
710 if (FAILED(hr)) return hr;
712 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
715 reader_skipn(reader, 1);
717 if (reader_cmp(reader, yesW) && reader_cmp(reader, noW))
720 start = reader_get_cur(reader);
721 /* skip 'yes'|'no' */
722 reader_skipn(reader, reader_cmp(reader, yesW) ? 2 : 3);
723 ptr = reader_get_cur(reader);
724 TRACE("standalone=%s\n", debugstr_wn(start, ptr-start));
728 if (reader_cmp(reader, quoteW) && reader_cmp(reader, dblquoteW))
731 reader_skipn(reader, 1);
733 return reader_add_attr(reader, &name, &val);
736 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
737 static HRESULT reader_parse_xmldecl(xmlreader *reader)
739 static const WCHAR xmldeclW[] = {'<','?','x','m','l',0};
740 static const WCHAR declcloseW[] = {'?','>',0};
743 /* check if we have "<?xml" */
744 if (reader_cmp(reader, xmldeclW)) return S_FALSE;
746 reader_skipn(reader, 5);
747 hr = reader_parse_versioninfo(reader);
751 hr = reader_parse_encdecl(reader);
755 hr = reader_parse_sddecl(reader);
759 reader_skipspaces(reader);
760 if (reader_cmp(reader, declcloseW)) return WC_E_XMLDECL;
761 reader_skipn(reader, 2);
763 reader->nodetype = XmlNodeType_XmlDeclaration;
768 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
769 static HRESULT reader_parse_comment(xmlreader *reader)
771 const WCHAR *start, *ptr;
774 reader_skipn(reader, 4);
775 ptr = start = reader_get_cur(reader);
779 if (ptr[0] == '-' && ptr[1] == '-')
783 TRACE("%s\n", debugstr_wn(start, ptr-start));
785 reader_skipn(reader, 3);
786 reader->nodetype = XmlNodeType_Comment;
794 reader_skipn(reader, 1);
795 ptr = reader_get_cur(reader);
799 return MX_E_INPUTEND;
802 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
803 static HRESULT reader_parse_pi(xmlreader *reader)
805 FIXME("PI not supported\n");
809 /* [27] Misc ::= Comment | PI | S */
810 static HRESULT reader_parse_misc(xmlreader *reader)
812 HRESULT hr = S_FALSE;
816 static const WCHAR commentW[] = {'<','!','-','-',0};
817 static const WCHAR piW[] = {'<','?',0};
818 const WCHAR *cur = reader_get_cur(reader);
820 if (is_wchar_space(*cur))
821 reader_skipspaces(reader);
822 else if (!reader_cmp(reader, commentW))
823 hr = reader_parse_comment(reader);
824 else if (!reader_cmp(reader, piW))
825 hr = reader_parse_pi(reader);
829 if (FAILED(hr)) return hr;
830 cur = reader_get_cur(reader);
836 static HRESULT reader_parse_nextnode(xmlreader *reader)
842 switch (reader->instate)
844 /* if it's a first call for a new input we need to detect stream encoding */
845 case XmlReadInState_Initial:
849 hr = readerinput_growraw(reader->input);
850 if (FAILED(hr)) return hr;
852 /* try to detect encoding by BOM or data and set input code page */
853 hr = readerinput_detectencoding(reader->input, &enc);
854 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map[enc].name), hr);
855 if (FAILED(hr)) return hr;
857 /* always switch first time cause we have to put something in */
858 readerinput_switchencoding(reader->input, enc);
860 /* parse xml declaration */
861 hr = reader_parse_xmldecl(reader);
862 if (FAILED(hr)) return hr;
864 reader->instate = XmlReadInState_Misc_DTD;
865 if (hr == S_OK) return hr;
868 case XmlReadInState_Misc_DTD:
869 hr = reader_parse_misc(reader);
870 if (FAILED(hr)) return hr;
873 reader->instate = XmlReadInState_DTD;
877 case XmlReadInState_DTD:
878 FIXME("DTD parsing not supported\n");
881 FIXME("internal state %d not handled\n", reader->instate);
889 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
891 xmlreader *This = impl_from_IXmlReader(iface);
893 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
895 if (IsEqualGUID(riid, &IID_IUnknown) ||
896 IsEqualGUID(riid, &IID_IXmlReader))
902 FIXME("interface %s not implemented\n", debugstr_guid(riid));
903 return E_NOINTERFACE;
906 IXmlReader_AddRef(iface);
911 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
913 xmlreader *This = impl_from_IXmlReader(iface);
914 ULONG ref = InterlockedIncrement(&This->ref);
915 TRACE("(%p)->(%d)\n", This, ref);
919 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
921 xmlreader *This = impl_from_IXmlReader(iface);
922 LONG ref = InterlockedDecrement(&This->ref);
924 TRACE("(%p)->(%d)\n", This, ref);
928 IMalloc *imalloc = This->imalloc;
929 if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
930 reader_clear_attrs(This);
931 reader_free(This, This);
932 if (imalloc) IMalloc_Release(imalloc);
938 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
940 xmlreader *This = impl_from_IXmlReader(iface);
943 TRACE("(%p %p)\n", This, input);
947 readerinput_release_stream(This->input);
948 IUnknown_Release(&This->input->IXmlReaderInput_iface);
952 This->line = This->pos = 0;
954 /* just reset current input */
957 This->state = XmlReadState_Initial;
961 /* now try IXmlReaderInput, ISequentialStream, IStream */
962 hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input);
965 IXmlReaderInput *readerinput;
967 /* create IXmlReaderInput basing on supplied interface */
968 hr = CreateXmlReaderInputWithEncodingName(input,
969 NULL, NULL, FALSE, NULL, &readerinput);
970 if (hr != S_OK) return hr;
971 This->input = impl_from_IXmlReaderInput(readerinput);
974 /* set stream for supplied IXmlReaderInput */
975 hr = readerinput_query_for_stream(This->input);
978 This->state = XmlReadState_Initial;
979 This->instate = XmlReadInState_Initial;
985 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
987 xmlreader *This = impl_from_IXmlReader(iface);
989 TRACE("(%p %u %p)\n", This, property, value);
991 if (!value) return E_INVALIDARG;
995 case XmlReaderProperty_DtdProcessing:
996 *value = This->dtdmode;
998 case XmlReaderProperty_ReadState:
999 *value = This->state;
1002 FIXME("Unimplemented property (%u)\n", property);
1009 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
1011 xmlreader *This = impl_from_IXmlReader(iface);
1013 TRACE("(%p %u %lu)\n", iface, property, value);
1017 case XmlReaderProperty_DtdProcessing:
1018 if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
1019 This->dtdmode = value;
1022 FIXME("Unimplemented property (%u)\n", property);
1029 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *nodetype)
1031 xmlreader *This = impl_from_IXmlReader(iface);
1032 XmlNodeType oldtype = This->nodetype;
1035 TRACE("(%p)->(%p)\n", This, nodetype);
1037 if (This->state == XmlReadState_Closed) return S_FALSE;
1039 hr = reader_parse_nextnode(This);
1040 if (oldtype == XmlNodeType_None && This->nodetype != oldtype)
1041 This->state = XmlReadState_Interactive;
1042 if (hr == S_OK) *nodetype = This->nodetype;
1047 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
1049 xmlreader *This = impl_from_IXmlReader(iface);
1050 TRACE("(%p)->(%p)\n", This, node_type);
1052 /* When we're on attribute always return attribute type, container node type is kept.
1053 Note that container is not necessarily an element, and attribute doesn't mean it's
1054 an attribute in XML spec terms. */
1055 *node_type = This->attr ? XmlNodeType_Attribute : This->nodetype;
1056 return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
1059 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
1061 xmlreader *This = impl_from_IXmlReader(iface);
1063 TRACE("(%p)\n", This);
1065 if (!This->attr_count) return S_FALSE;
1066 This->attr = LIST_ENTRY(list_head(&This->attrs), struct attribute, entry);
1070 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
1072 xmlreader *This = impl_from_IXmlReader(iface);
1073 const struct list *next;
1075 TRACE("(%p)\n", This);
1077 if (!This->attr_count) return S_FALSE;
1080 return IXmlReader_MoveToFirstAttribute(iface);
1082 next = list_next(&This->attrs, &This->attr->entry);
1084 This->attr = LIST_ENTRY(next, struct attribute, entry);
1086 return next ? S_OK : S_FALSE;
1089 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
1091 LPCWSTR namespaceUri)
1093 FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
1097 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
1099 xmlreader *This = impl_from_IXmlReader(iface);
1101 TRACE("(%p)\n", This);
1103 if (!This->attr_count) return S_FALSE;
1108 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *qualifiedName,
1109 UINT *qualifiedName_length)
1111 FIXME("(%p %p %p): stub\n", iface, qualifiedName, qualifiedName_length);
1115 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
1116 LPCWSTR *namespaceUri,
1117 UINT *namespaceUri_length)
1119 FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
1123 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface,
1124 LPCWSTR *local_name,
1125 UINT *local_name_length)
1127 FIXME("(%p %p %p): stub\n", iface, local_name, local_name_length);
1131 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
1133 UINT *prefix_length)
1135 FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
1139 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface,
1143 FIXME("(%p %p %p): stub\n", iface, value, value_length);
1147 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
1152 FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
1156 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
1158 UINT *baseUri_length)
1160 FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
1164 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
1166 FIXME("(%p): stub\n", iface);
1170 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
1172 FIXME("(%p): stub\n", iface);
1176 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
1178 xmlreader *This = impl_from_IXmlReader(iface);
1180 TRACE("(%p %p)\n", This, lineNumber);
1182 if (!lineNumber) return E_INVALIDARG;
1184 *lineNumber = This->line;
1189 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
1191 xmlreader *This = impl_from_IXmlReader(iface);
1193 TRACE("(%p %p)\n", This, linePosition);
1195 if (!linePosition) return E_INVALIDARG;
1197 *linePosition = This->pos;
1202 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *count)
1204 xmlreader *This = impl_from_IXmlReader(iface);
1206 TRACE("(%p)->(%p)\n", This, count);
1208 if (!count) return E_INVALIDARG;
1210 *count = This->attr_count;
1214 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
1216 FIXME("(%p %p): stub\n", iface, depth);
1220 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
1222 FIXME("(%p): stub\n", iface);
1226 static const struct IXmlReaderVtbl xmlreader_vtbl =
1228 xmlreader_QueryInterface,
1232 xmlreader_GetProperty,
1233 xmlreader_SetProperty,
1235 xmlreader_GetNodeType,
1236 xmlreader_MoveToFirstAttribute,
1237 xmlreader_MoveToNextAttribute,
1238 xmlreader_MoveToAttributeByName,
1239 xmlreader_MoveToElement,
1240 xmlreader_GetQualifiedName,
1241 xmlreader_GetNamespaceUri,
1242 xmlreader_GetLocalName,
1243 xmlreader_GetPrefix,
1245 xmlreader_ReadValueChunk,
1246 xmlreader_GetBaseUri,
1247 xmlreader_IsDefault,
1248 xmlreader_IsEmptyElement,
1249 xmlreader_GetLineNumber,
1250 xmlreader_GetLinePosition,
1251 xmlreader_GetAttributeCount,
1256 /** IXmlReaderInput **/
1257 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
1259 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1261 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
1263 if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
1264 IsEqualGUID(riid, &IID_IUnknown))
1270 WARN("interface %s not implemented\n", debugstr_guid(riid));
1271 return E_NOINTERFACE;
1274 IUnknown_AddRef(iface);
1279 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
1281 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1282 ULONG ref = InterlockedIncrement(&This->ref);
1283 TRACE("(%p)->(%d)\n", This, ref);
1287 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
1289 xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
1290 LONG ref = InterlockedDecrement(&This->ref);
1292 TRACE("(%p)->(%d)\n", This, ref);
1296 IMalloc *imalloc = This->imalloc;
1297 if (This->input) IUnknown_Release(This->input);
1298 if (This->stream) ISequentialStream_Release(This->stream);
1299 if (This->buffer) free_input_buffer(This->buffer);
1300 readerinput_free(This, This->baseuri);
1301 readerinput_free(This, This);
1302 if (imalloc) IMalloc_Release(imalloc);
1308 static const struct IUnknownVtbl xmlreaderinput_vtbl =
1310 xmlreaderinput_QueryInterface,
1311 xmlreaderinput_AddRef,
1312 xmlreaderinput_Release
1315 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
1319 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
1321 if (!IsEqualGUID(riid, &IID_IXmlReader))
1323 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
1328 reader = IMalloc_Alloc(imalloc, sizeof(*reader));
1330 reader = heap_alloc(sizeof(*reader));
1331 if(!reader) return E_OUTOFMEMORY;
1333 reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
1335 reader->input = NULL;
1336 reader->state = XmlReadState_Closed;
1337 reader->instate = XmlReadInState_Initial;
1338 reader->dtdmode = DtdProcessing_Prohibit;
1339 reader->line = reader->pos = 0;
1340 reader->imalloc = imalloc;
1341 if (imalloc) IMalloc_AddRef(imalloc);
1342 reader->nodetype = XmlNodeType_None;
1343 list_init(&reader->attrs);
1344 reader->attr_count = 0;
1345 reader->attr = NULL;
1347 *obj = &reader->IXmlReader_iface;
1349 TRACE("returning iface %p\n", *obj);
1354 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
1359 IXmlReaderInput **ppInput)
1361 xmlreaderinput *readerinput;
1364 TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
1365 hint, wine_dbgstr_w(base_uri), ppInput);
1367 if (!stream || !ppInput) return E_INVALIDARG;
1370 readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
1372 readerinput = heap_alloc(sizeof(*readerinput));
1373 if(!readerinput) return E_OUTOFMEMORY;
1375 readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinput_vtbl;
1376 readerinput->ref = 1;
1377 readerinput->imalloc = imalloc;
1378 readerinput->stream = NULL;
1379 if (imalloc) IMalloc_AddRef(imalloc);
1380 readerinput->encoding = parse_encoding_name(encoding, -1);
1381 readerinput->hint = hint;
1382 readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
1384 hr = alloc_input_buffer(readerinput);
1387 readerinput_free(readerinput, readerinput);
1390 IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
1392 *ppInput = &readerinput->IXmlReaderInput_iface;
1394 TRACE("returning iface %p\n", *ppInput);