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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
33 #include "xmllite_private.h"
35 #include <wine/debug.h>
36 #include <wine/list.h>
37 #include <wine/unicode.h>
39 WINE_DEFAULT_DEBUG_CHANNEL(xmllite
);
41 /* not defined in public headers */
42 DEFINE_GUID(IID_IXmlReaderInput
, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
51 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
52 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
54 static const WCHAR dblquoteW
[] = {'\"',0};
55 static const WCHAR quoteW
[] = {'\'',0};
57 struct xml_encoding_data
64 static const struct xml_encoding_data xml_encoding_map
[] = {
65 { utf16W
, XmlEncoding_UTF16
, ~0 },
66 { utf8W
, XmlEncoding_UTF8
, CP_UTF8
}
73 unsigned int allocated
;
77 typedef struct input_buffer input_buffer
;
79 typedef struct _xmlreaderinput
81 IXmlReaderInput IXmlReaderInput_iface
;
83 /* reference passed on IXmlReaderInput creation, is kept when input is created */
86 xml_encoding encoding
;
89 /* stream reference set after SetInput() call from reader,
90 stored as sequential stream, cause currently
91 optimizations possible with IStream aren't implemented */
92 ISequentialStream
*stream
;
109 typedef struct _xmlreader
111 IXmlReader IXmlReader_iface
;
113 xmlreaderinput
*input
;
116 XmlNodeType nodetype
;
117 DtdProcessing dtdmode
;
118 UINT line
, pos
; /* reader position in XML stream */
119 struct list attrs
; /* attributes list for current node */
120 struct attribute
*attr
; /* current attribute */
126 encoded_buffer utf16
;
127 encoded_buffer encoded
;
129 xmlreaderinput
*input
;
132 static inline xmlreader
*impl_from_IXmlReader(IXmlReader
*iface
)
134 return CONTAINING_RECORD(iface
, xmlreader
, IXmlReader_iface
);
137 static inline xmlreaderinput
*impl_from_IXmlReaderInput(IXmlReaderInput
*iface
)
139 return CONTAINING_RECORD(iface
, xmlreaderinput
, IXmlReaderInput_iface
);
142 static inline void *m_alloc(IMalloc
*imalloc
, size_t len
)
145 return IMalloc_Alloc(imalloc
, len
);
147 return heap_alloc(len
);
150 static inline void *m_realloc(IMalloc
*imalloc
, void *mem
, size_t len
)
153 return IMalloc_Realloc(imalloc
, mem
, len
);
155 return heap_realloc(mem
, len
);
158 static inline void m_free(IMalloc
*imalloc
, void *mem
)
161 IMalloc_Free(imalloc
, mem
);
166 /* reader memory allocation functions */
167 static inline void *reader_alloc(xmlreader
*reader
, size_t len
)
169 return m_alloc(reader
->imalloc
, len
);
172 static inline void reader_free(xmlreader
*reader
, void *mem
)
174 m_free(reader
->imalloc
, mem
);
177 /* reader input memory allocation functions */
178 static inline void *readerinput_alloc(xmlreaderinput
*input
, size_t len
)
180 return m_alloc(input
->imalloc
, len
);
183 static inline void *readerinput_realloc(xmlreaderinput
*input
, void *mem
, size_t len
)
185 return m_realloc(input
->imalloc
, mem
, len
);
188 static inline void readerinput_free(xmlreaderinput
*input
, void *mem
)
190 m_free(input
->imalloc
, mem
);
193 static inline WCHAR
*readerinput_strdupW(xmlreaderinput
*input
, const WCHAR
*str
)
200 size
= (strlenW(str
)+1)*sizeof(WCHAR
);
201 ret
= readerinput_alloc(input
, size
);
202 if (ret
) memcpy(ret
, str
, size
);
208 static void reader_clear_attrs(xmlreader
*reader
)
210 struct attribute
*attr
, *attr2
;
211 LIST_FOR_EACH_ENTRY_SAFE(attr
, attr2
, &reader
->attrs
, struct attribute
, entry
)
213 reader_free(reader
, attr
);
215 list_init(&reader
->attrs
);
216 reader
->attr_count
= 0;
219 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
220 while we are on a node with attributes */
221 static HRESULT
reader_add_attr(xmlreader
*reader
, strval
*localname
, strval
*value
)
223 struct attribute
*attr
;
225 attr
= reader_alloc(reader
, sizeof(*attr
));
226 if (!attr
) return E_OUTOFMEMORY
;
228 attr
->localname
= *localname
;
229 attr
->value
= *value
;
230 list_add_tail(&reader
->attrs
, &attr
->entry
);
231 reader
->attr_count
++;
236 static HRESULT
init_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
238 const int initial_len
= 0x2000;
239 buffer
->data
= readerinput_alloc(input
, initial_len
);
240 if (!buffer
->data
) return E_OUTOFMEMORY
;
242 memset(buffer
->data
, 0, 4);
243 buffer
->cur
= buffer
->data
;
244 buffer
->allocated
= initial_len
;
250 static void free_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
252 readerinput_free(input
, buffer
->data
);
255 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
257 if (encoding
== XmlEncoding_Unknown
)
259 FIXME("unsupported encoding %d\n", encoding
);
263 *cp
= xml_encoding_map
[encoding
].cp
;
268 static xml_encoding
parse_encoding_name(const WCHAR
*name
, int len
)
272 if (!name
) return XmlEncoding_Unknown
;
275 max
= sizeof(xml_encoding_map
)/sizeof(struct xml_encoding_data
) - 1;
282 c
= strncmpiW(xml_encoding_map
[n
].name
, name
, len
);
284 c
= strcmpiW(xml_encoding_map
[n
].name
, name
);
286 return xml_encoding_map
[n
].enc
;
294 return XmlEncoding_Unknown
;
297 static HRESULT
alloc_input_buffer(xmlreaderinput
*input
)
299 input_buffer
*buffer
;
302 input
->buffer
= NULL
;
304 buffer
= readerinput_alloc(input
, sizeof(*buffer
));
305 if (!buffer
) return E_OUTOFMEMORY
;
307 buffer
->input
= input
;
308 buffer
->code_page
= ~0; /* code page is unknown at this point */
309 hr
= init_encoded_buffer(input
, &buffer
->utf16
);
311 readerinput_free(input
, buffer
);
315 hr
= init_encoded_buffer(input
, &buffer
->encoded
);
317 free_encoded_buffer(input
, &buffer
->utf16
);
318 readerinput_free(input
, buffer
);
322 input
->buffer
= buffer
;
326 static void free_input_buffer(input_buffer
*buffer
)
328 free_encoded_buffer(buffer
->input
, &buffer
->encoded
);
329 free_encoded_buffer(buffer
->input
, &buffer
->utf16
);
330 readerinput_free(buffer
->input
, buffer
);
333 static void readerinput_release_stream(xmlreaderinput
*readerinput
)
335 if (readerinput
->stream
) {
336 ISequentialStream_Release(readerinput
->stream
);
337 readerinput
->stream
= NULL
;
341 /* Queries already stored interface for IStream/ISequentialStream.
342 Interface supplied on creation will be overwritten */
343 static HRESULT
readerinput_query_for_stream(xmlreaderinput
*readerinput
)
347 readerinput_release_stream(readerinput
);
348 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_IStream
, (void**)&readerinput
->stream
);
350 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_ISequentialStream
, (void**)&readerinput
->stream
);
355 /* reads a chunk to raw buffer */
356 static HRESULT
readerinput_growraw(xmlreaderinput
*readerinput
)
358 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
359 ULONG len
= buffer
->allocated
- buffer
->written
, read
;
362 /* always try to get aligned to 4 bytes, so the only case we can get partialy read characters is
363 variable width encodings like UTF-8 */
364 len
= (len
+ 3) & ~3;
365 /* try to use allocated space or grow */
366 if (buffer
->allocated
- buffer
->written
< len
)
368 buffer
->allocated
*= 2;
369 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, buffer
->allocated
);
370 len
= buffer
->allocated
- buffer
->written
;
373 hr
= ISequentialStream_Read(readerinput
->stream
, buffer
->data
+ buffer
->written
, len
, &read
);
374 if (FAILED(hr
)) return hr
;
375 TRACE("requested %d, read %d, ret 0x%08x\n", len
, read
, hr
);
376 buffer
->written
+= read
;
381 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
382 static void readerinput_grow(xmlreaderinput
*readerinput
, int length
)
384 encoded_buffer
*buffer
= &readerinput
->buffer
->utf16
;
386 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
387 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
389 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
390 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, grown_size
);
391 buffer
->allocated
= grown_size
;
395 static HRESULT
readerinput_detectencoding(xmlreaderinput
*readerinput
, xml_encoding
*enc
)
397 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
398 static char startA
[] = {'<','?','x','m'};
399 static WCHAR startW
[] = {'<','?'};
400 static char utf8bom
[] = {0xef,0xbb,0xbf};
401 static char utf16lebom
[] = {0xff,0xfe};
403 *enc
= XmlEncoding_Unknown
;
405 if (buffer
->written
<= 3) return MX_E_INPUTEND
;
407 /* try start symbols if we have enough data to do that, input buffer should contain
408 first chunk already */
409 if (!memcmp(buffer
->data
, startA
, sizeof(startA
)))
410 *enc
= XmlEncoding_UTF8
;
411 else if (!memcmp(buffer
->data
, startW
, sizeof(startW
)))
412 *enc
= XmlEncoding_UTF16
;
413 /* try with BOM now */
414 else if (!memcmp(buffer
->data
, utf8bom
, sizeof(utf8bom
)))
416 buffer
->cur
+= sizeof(utf8bom
);
417 *enc
= XmlEncoding_UTF8
;
419 else if (!memcmp(buffer
->data
, utf16lebom
, sizeof(utf16lebom
)))
421 buffer
->cur
+= sizeof(utf16lebom
);
422 *enc
= XmlEncoding_UTF16
;
428 static int readerinput_get_utf8_convlen(xmlreaderinput
*readerinput
)
430 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
431 int len
= buffer
->written
;
433 /* complete single byte char */
434 if (!(buffer
->data
[len
-1] & 0x80)) return len
;
436 /* find start byte of multibyte char */
437 while (--len
&& !(buffer
->data
[len
] & 0xc0))
443 /* returns byte length of complete char sequence for specified code page, */
444 static int readerinput_get_convlen(xmlreaderinput
*readerinput
, UINT cp
)
446 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
447 int len
= buffer
->written
;
450 len
= readerinput_get_utf8_convlen(readerinput
);
452 len
= buffer
->written
;
454 return len
- (buffer
->cur
- buffer
->data
);
457 /* note that raw buffer content is kept */
458 static void readerinput_switchencoding(xmlreaderinput
*readerinput
, xml_encoding enc
)
460 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
461 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
466 hr
= get_code_page(enc
, &cp
);
467 if (FAILED(hr
)) return;
469 len
= readerinput_get_convlen(readerinput
, cp
);
471 TRACE("switching to cp %d\n", cp
);
473 /* just copy in this case */
474 if (enc
== XmlEncoding_UTF16
)
476 readerinput_grow(readerinput
, len
);
477 memcpy(dest
->data
, src
->cur
, len
);
478 readerinput
->buffer
->code_page
= cp
;
482 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
483 readerinput_grow(readerinput
, dest_len
);
484 MultiByteToWideChar(cp
, 0, src
->cur
, len
, (WCHAR
*)dest
->data
, dest_len
);
485 dest
->data
[dest_len
] = 0;
486 readerinput
->buffer
->code_page
= cp
;
489 static inline const WCHAR
*reader_get_cur(xmlreader
*reader
)
491 return (WCHAR
*)reader
->input
->buffer
->utf16
.cur
;
494 static int reader_cmp(xmlreader
*reader
, const WCHAR
*str
)
496 const WCHAR
*ptr
= reader_get_cur(reader
);
499 return strncmpW(str
, ptr
, strlenW(str
));
502 if (ptr
[i
] != str
[i
]) return 0;
509 /* moves cursor n WCHARs forward */
510 static void reader_skipn(xmlreader
*reader
, int n
)
512 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
513 const WCHAR
*ptr
= reader_get_cur(reader
);
515 while (*ptr
++ && n
--)
517 buffer
->cur
+= sizeof(WCHAR
);
522 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
523 static int reader_skipspaces(xmlreader
*reader
)
525 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
526 const WCHAR
*ptr
= reader_get_cur(reader
), *start
= ptr
;
528 while (*ptr
== ' ' || *ptr
== '\t' || *ptr
== '\r' || *ptr
== '\n')
530 buffer
->cur
+= sizeof(WCHAR
);
533 else if (*ptr
== '\n')
546 /* [26] VersionNum ::= '1.' [0-9]+ */
547 static HRESULT
reader_parse_versionnum(xmlreader
*reader
, strval
*val
)
549 const WCHAR
*ptr
, *ptr2
, *start
= reader_get_cur(reader
);
550 static const WCHAR onedotW
[] = {'1','.',0};
552 if (reader_cmp(reader
, onedotW
)) return WC_E_XMLDECL
;
554 reader_skipn(reader
, 2);
556 ptr2
= ptr
= reader_get_cur(reader
);
557 while (*ptr
>= '0' && *ptr
<= '9')
560 if (ptr2
== ptr
) return WC_E_DIGIT
;
561 TRACE("version=%s\n", debugstr_wn(start
, ptr
-start
));
563 val
->len
= ptr
-start
;
564 reader_skipn(reader
, ptr
-ptr2
);
568 /* [25] Eq ::= S? '=' S? */
569 static HRESULT
reader_parse_eq(xmlreader
*reader
)
571 static const WCHAR eqW
[] = {'=',0};
572 reader_skipspaces(reader
);
573 if (reader_cmp(reader
, eqW
)) return WC_E_EQUAL
;
575 reader_skipn(reader
, 1);
576 reader_skipspaces(reader
);
580 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
581 static HRESULT
reader_parse_versioninfo(xmlreader
*reader
)
583 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
587 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
589 if (reader_cmp(reader
, versionW
)) return WC_E_XMLDECL
;
590 name
.str
= reader_get_cur(reader
);
593 reader_skipn(reader
, 7);
595 hr
= reader_parse_eq(reader
);
596 if (FAILED(hr
)) return hr
;
598 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
601 reader_skipn(reader
, 1);
603 hr
= reader_parse_versionnum(reader
, &val
);
604 if (FAILED(hr
)) return hr
;
606 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
610 reader_skipn(reader
, 1);
612 return reader_add_attr(reader
, &name
, &val
);
615 /* ([A-Za-z0-9._] | '-') */
616 static inline int is_wchar_encname(WCHAR ch
)
618 return ((ch
>= 'A' && ch
<= 'Z') ||
619 (ch
>= 'a' && ch
<= 'z') ||
620 (ch
>= '0' && ch
<= '9') ||
621 (ch
== '.') || (ch
== '_') ||
625 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
626 static HRESULT
reader_parse_encname(xmlreader
*reader
, strval
*val
)
628 const WCHAR
*start
= reader_get_cur(reader
), *ptr
;
632 if ((*start
< 'A' || *start
> 'Z') && (*start
< 'a' || *start
> 'z'))
636 while (is_wchar_encname(*++ptr
))
640 enc
= parse_encoding_name(start
, len
);
641 TRACE("encoding name %s\n", debugstr_wn(start
, len
));
645 if (enc
== XmlEncoding_Unknown
)
648 /* skip encoding name */
649 reader_skipn(reader
, len
);
653 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
654 static HRESULT
reader_parse_encdecl(xmlreader
*reader
)
656 static const WCHAR encodingW
[] = {'e','n','c','o','d','i','n','g',0};
660 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
662 if (reader_cmp(reader
, encodingW
)) return S_FALSE
;
663 name
.str
= reader_get_cur(reader
);
665 /* skip 'encoding' */
666 reader_skipn(reader
, 8);
668 hr
= reader_parse_eq(reader
);
669 if (FAILED(hr
)) return hr
;
671 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
674 reader_skipn(reader
, 1);
676 hr
= reader_parse_encname(reader
, &val
);
677 if (FAILED(hr
)) return hr
;
679 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
683 reader_skipn(reader
, 1);
685 return reader_add_attr(reader
, &name
, &val
);
688 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
689 static HRESULT
reader_parse_sddecl(xmlreader
*reader
)
691 static const WCHAR standaloneW
[] = {'s','t','a','n','d','a','l','o','n','e',0};
692 static const WCHAR yesW
[] = {'y','e','s',0};
693 static const WCHAR noW
[] = {'n','o',0};
694 const WCHAR
*start
, *ptr
;
698 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
700 if (reader_cmp(reader
, standaloneW
)) return S_FALSE
;
701 name
.str
= reader_get_cur(reader
);
703 /* skip 'standalone' */
704 reader_skipn(reader
, 10);
706 hr
= reader_parse_eq(reader
);
707 if (FAILED(hr
)) return hr
;
709 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
712 reader_skipn(reader
, 1);
714 if (reader_cmp(reader
, yesW
) && reader_cmp(reader
, noW
))
717 start
= reader_get_cur(reader
);
718 /* skip 'yes'|'no' */
719 reader_skipn(reader
, reader_cmp(reader
, yesW
) ? 2 : 3);
720 ptr
= reader_get_cur(reader
);
721 TRACE("standalone=%s\n", debugstr_wn(start
, ptr
-start
));
725 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
728 reader_skipn(reader
, 1);
730 return reader_add_attr(reader
, &name
, &val
);
733 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
734 static HRESULT
reader_parse_xmldecl(xmlreader
*reader
)
736 static const WCHAR xmldeclW
[] = {'<','?','x','m','l',0};
737 static const WCHAR declcloseW
[] = {'?','>',0};
740 /* check if we have "<?xml" */
741 if (reader_cmp(reader
, xmldeclW
)) return S_FALSE
;
743 reader_skipn(reader
, 5);
744 hr
= reader_parse_versioninfo(reader
);
748 hr
= reader_parse_encdecl(reader
);
752 hr
= reader_parse_sddecl(reader
);
756 reader_skipspaces(reader
);
757 if (reader_cmp(reader
, declcloseW
)) return WC_E_XMLDECL
;
758 reader_skipn(reader
, 2);
763 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
765 xmlreader
*This
= impl_from_IXmlReader(iface
);
767 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
769 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
770 IsEqualGUID(riid
, &IID_IXmlReader
))
776 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
777 return E_NOINTERFACE
;
780 IXmlReader_AddRef(iface
);
785 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
787 xmlreader
*This
= impl_from_IXmlReader(iface
);
788 ULONG ref
= InterlockedIncrement(&This
->ref
);
789 TRACE("(%p)->(%d)\n", This
, ref
);
793 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
795 xmlreader
*This
= impl_from_IXmlReader(iface
);
796 LONG ref
= InterlockedDecrement(&This
->ref
);
798 TRACE("(%p)->(%d)\n", This
, ref
);
802 IMalloc
*imalloc
= This
->imalloc
;
803 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
804 reader_clear_attrs(This
);
805 reader_free(This
, This
);
806 if (imalloc
) IMalloc_Release(imalloc
);
812 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
814 xmlreader
*This
= impl_from_IXmlReader(iface
);
817 TRACE("(%p %p)\n", This
, input
);
821 readerinput_release_stream(This
->input
);
822 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
826 This
->line
= This
->pos
= 0;
828 /* just reset current input */
831 This
->state
= XmlReadState_Initial
;
835 /* now try IXmlReaderInput, ISequentialStream, IStream */
836 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&This
->input
);
839 IXmlReaderInput
*readerinput
;
841 /* create IXmlReaderInput basing on supplied interface */
842 hr
= CreateXmlReaderInputWithEncodingName(input
,
843 NULL
, NULL
, FALSE
, NULL
, &readerinput
);
844 if (hr
!= S_OK
) return hr
;
845 This
->input
= impl_from_IXmlReaderInput(readerinput
);
848 /* set stream for supplied IXmlReaderInput */
849 hr
= readerinput_query_for_stream(This
->input
);
851 This
->state
= XmlReadState_Initial
;
856 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
858 xmlreader
*This
= impl_from_IXmlReader(iface
);
860 TRACE("(%p %u %p)\n", This
, property
, value
);
862 if (!value
) return E_INVALIDARG
;
866 case XmlReaderProperty_DtdProcessing
:
867 *value
= This
->dtdmode
;
869 case XmlReaderProperty_ReadState
:
870 *value
= This
->state
;
873 FIXME("Unimplemented property (%u)\n", property
);
880 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
882 xmlreader
*This
= impl_from_IXmlReader(iface
);
884 TRACE("(%p %u %lu)\n", iface
, property
, value
);
888 case XmlReaderProperty_DtdProcessing
:
889 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
890 This
->dtdmode
= value
;
893 FIXME("Unimplemented property (%u)\n", property
);
900 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*node_type
)
902 xmlreader
*This
= impl_from_IXmlReader(iface
);
904 FIXME("(%p)->(%p): stub\n", This
, node_type
);
906 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
908 /* if it's a first call for a new input we need to detect stream encoding */
909 if (This
->state
== XmlReadState_Initial
)
914 hr
= readerinput_growraw(This
->input
);
915 if (FAILED(hr
)) return hr
;
917 /* try to detect encoding by BOM or data and set input code page */
918 hr
= readerinput_detectencoding(This
->input
, &enc
);
919 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
920 if (FAILED(hr
)) return hr
;
922 /* always switch first time cause we have to put something in */
923 readerinput_switchencoding(This
->input
, enc
);
925 /* parse xml declaration */
926 hr
= reader_parse_xmldecl(This
);
927 if (FAILED(hr
)) return hr
;
931 This
->state
= XmlReadState_Interactive
;
932 This
->nodetype
= *node_type
= XmlNodeType_XmlDeclaration
;
940 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
942 xmlreader
*This
= impl_from_IXmlReader(iface
);
943 TRACE("(%p)->(%p)\n", This
, node_type
);
945 /* When we're on attribute always return attribute type, container node type is kept.
946 Note that container is not necessarily an element, and attribute doesn't mean it's
947 an attribute in XML spec terms. */
948 *node_type
= This
->attr
? XmlNodeType_Attribute
: This
->nodetype
;
949 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
952 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
954 xmlreader
*This
= impl_from_IXmlReader(iface
);
956 TRACE("(%p)\n", This
);
958 if (!This
->attr_count
) return S_FALSE
;
959 This
->attr
= LIST_ENTRY(list_head(&This
->attrs
), struct attribute
, entry
);
963 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
965 xmlreader
*This
= impl_from_IXmlReader(iface
);
966 const struct list
*next
;
968 TRACE("(%p)\n", This
);
970 if (!This
->attr_count
) return S_FALSE
;
973 return IXmlReader_MoveToFirstAttribute(iface
);
975 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
977 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
979 return next
? S_OK
: S_FALSE
;
982 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
984 LPCWSTR namespaceUri
)
986 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
990 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
992 xmlreader
*This
= impl_from_IXmlReader(iface
);
994 TRACE("(%p)\n", This
);
996 if (!This
->attr_count
) return S_FALSE
;
1001 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*qualifiedName
,
1002 UINT
*qualifiedName_length
)
1004 FIXME("(%p %p %p): stub\n", iface
, qualifiedName
, qualifiedName_length
);
1008 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
,
1009 LPCWSTR
*namespaceUri
,
1010 UINT
*namespaceUri_length
)
1012 FIXME("(%p %p %p): stub\n", iface
, namespaceUri
, namespaceUri_length
);
1016 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
,
1017 LPCWSTR
*local_name
,
1018 UINT
*local_name_length
)
1020 FIXME("(%p %p %p): stub\n", iface
, local_name
, local_name_length
);
1024 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
,
1026 UINT
*prefix_length
)
1028 FIXME("(%p %p %p): stub\n", iface
, prefix
, prefix_length
);
1032 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
,
1036 FIXME("(%p %p %p): stub\n", iface
, value
, value_length
);
1040 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
,
1045 FIXME("(%p %p %u %p): stub\n", iface
, buffer
, chunk_size
, read
);
1049 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
1051 UINT
*baseUri_length
)
1053 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
1057 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
1059 FIXME("(%p): stub\n", iface
);
1063 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
1065 FIXME("(%p): stub\n", iface
);
1069 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
1071 xmlreader
*This
= impl_from_IXmlReader(iface
);
1073 TRACE("(%p %p)\n", This
, lineNumber
);
1075 if (!lineNumber
) return E_INVALIDARG
;
1077 *lineNumber
= This
->line
;
1082 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
1084 xmlreader
*This
= impl_from_IXmlReader(iface
);
1086 TRACE("(%p %p)\n", This
, linePosition
);
1088 if (!linePosition
) return E_INVALIDARG
;
1090 *linePosition
= This
->pos
;
1095 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
1097 xmlreader
*This
= impl_from_IXmlReader(iface
);
1099 TRACE("(%p)->(%p)\n", This
, count
);
1101 if (!count
) return E_INVALIDARG
;
1103 *count
= This
->attr_count
;
1107 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
1109 FIXME("(%p %p): stub\n", iface
, depth
);
1113 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
1115 FIXME("(%p): stub\n", iface
);
1119 static const struct IXmlReaderVtbl xmlreader_vtbl
=
1121 xmlreader_QueryInterface
,
1125 xmlreader_GetProperty
,
1126 xmlreader_SetProperty
,
1128 xmlreader_GetNodeType
,
1129 xmlreader_MoveToFirstAttribute
,
1130 xmlreader_MoveToNextAttribute
,
1131 xmlreader_MoveToAttributeByName
,
1132 xmlreader_MoveToElement
,
1133 xmlreader_GetQualifiedName
,
1134 xmlreader_GetNamespaceUri
,
1135 xmlreader_GetLocalName
,
1136 xmlreader_GetPrefix
,
1138 xmlreader_ReadValueChunk
,
1139 xmlreader_GetBaseUri
,
1140 xmlreader_IsDefault
,
1141 xmlreader_IsEmptyElement
,
1142 xmlreader_GetLineNumber
,
1143 xmlreader_GetLinePosition
,
1144 xmlreader_GetAttributeCount
,
1149 /** IXmlReaderInput **/
1150 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
1152 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1154 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
1156 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
1157 IsEqualGUID(riid
, &IID_IUnknown
))
1163 WARN("interface %s not implemented\n", debugstr_guid(riid
));
1164 return E_NOINTERFACE
;
1167 IUnknown_AddRef(iface
);
1172 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
1174 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1175 ULONG ref
= InterlockedIncrement(&This
->ref
);
1176 TRACE("(%p)->(%d)\n", This
, ref
);
1180 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
1182 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1183 LONG ref
= InterlockedDecrement(&This
->ref
);
1185 TRACE("(%p)->(%d)\n", This
, ref
);
1189 IMalloc
*imalloc
= This
->imalloc
;
1190 if (This
->input
) IUnknown_Release(This
->input
);
1191 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1192 if (This
->buffer
) free_input_buffer(This
->buffer
);
1193 readerinput_free(This
, This
->baseuri
);
1194 readerinput_free(This
, This
);
1195 if (imalloc
) IMalloc_Release(imalloc
);
1201 static const struct IUnknownVtbl xmlreaderinput_vtbl
=
1203 xmlreaderinput_QueryInterface
,
1204 xmlreaderinput_AddRef
,
1205 xmlreaderinput_Release
1208 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1212 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1214 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
1216 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
1221 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
1223 reader
= heap_alloc(sizeof(*reader
));
1224 if(!reader
) return E_OUTOFMEMORY
;
1226 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
1228 reader
->input
= NULL
;
1229 reader
->state
= XmlReadState_Closed
;
1230 reader
->dtdmode
= DtdProcessing_Prohibit
;
1231 reader
->line
= reader
->pos
= 0;
1232 reader
->imalloc
= imalloc
;
1233 if (imalloc
) IMalloc_AddRef(imalloc
);
1234 reader
->nodetype
= XmlNodeType_None
;
1235 list_init(&reader
->attrs
);
1236 reader
->attr_count
= 0;
1237 reader
->attr
= NULL
;
1239 *obj
= &reader
->IXmlReader_iface
;
1241 TRACE("returning iface %p\n", *obj
);
1246 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
1251 IXmlReaderInput
**ppInput
)
1253 xmlreaderinput
*readerinput
;
1256 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
1257 hint
, wine_dbgstr_w(base_uri
), ppInput
);
1259 if (!stream
|| !ppInput
) return E_INVALIDARG
;
1262 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
1264 readerinput
= heap_alloc(sizeof(*readerinput
));
1265 if(!readerinput
) return E_OUTOFMEMORY
;
1267 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinput_vtbl
;
1268 readerinput
->ref
= 1;
1269 readerinput
->imalloc
= imalloc
;
1270 readerinput
->stream
= NULL
;
1271 if (imalloc
) IMalloc_AddRef(imalloc
);
1272 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
1273 readerinput
->hint
= hint
;
1274 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
1276 hr
= alloc_input_buffer(readerinput
);
1279 readerinput_free(readerinput
, readerinput
);
1282 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
1284 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
1286 TRACE("returning iface %p\n", *ppInput
);