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);
47 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
48 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
50 static const WCHAR dblquoteW
[] = {'\"',0};
51 static const WCHAR quoteW
[] = {'\'',0};
53 struct xml_encoding_data
60 static const struct xml_encoding_data xml_encoding_map
[] = {
61 { utf16W
, XmlEncoding_UTF16
, ~0 },
62 { utf8W
, XmlEncoding_UTF8
, CP_UTF8
}
69 unsigned int allocated
;
73 typedef struct input_buffer input_buffer
;
75 typedef struct _xmlreaderinput
77 IXmlReaderInput IXmlReaderInput_iface
;
79 /* reference passed on IXmlReaderInput creation, is kept when input is created */
82 xml_encoding encoding
;
85 /* stream reference set after SetInput() call from reader,
86 stored as sequential stream, cause currently
87 optimizations possible with IStream aren't implemented */
88 ISequentialStream
*stream
;
105 typedef struct _xmlreader
107 IXmlReader IXmlReader_iface
;
109 xmlreaderinput
*input
;
112 XmlNodeType nodetype
;
113 DtdProcessing dtdmode
;
114 UINT line
, pos
; /* reader position in XML stream */
115 struct list attrs
; /* attributes list for current node */
116 struct attribute
*attr
; /* current attribute */
122 encoded_buffer utf16
;
123 encoded_buffer encoded
;
125 xmlreaderinput
*input
;
128 static inline xmlreader
*impl_from_IXmlReader(IXmlReader
*iface
)
130 return CONTAINING_RECORD(iface
, xmlreader
, IXmlReader_iface
);
133 static inline xmlreaderinput
*impl_from_IXmlReaderInput(IXmlReaderInput
*iface
)
135 return CONTAINING_RECORD(iface
, xmlreaderinput
, IXmlReaderInput_iface
);
138 static inline void *m_alloc(IMalloc
*imalloc
, size_t len
)
141 return IMalloc_Alloc(imalloc
, len
);
143 return heap_alloc(len
);
146 static inline void *m_realloc(IMalloc
*imalloc
, void *mem
, size_t len
)
149 return IMalloc_Realloc(imalloc
, mem
, len
);
151 return heap_realloc(mem
, len
);
154 static inline void m_free(IMalloc
*imalloc
, void *mem
)
157 IMalloc_Free(imalloc
, mem
);
162 /* reader memory allocation functions */
163 static inline void *reader_alloc(xmlreader
*reader
, size_t len
)
165 return m_alloc(reader
->imalloc
, len
);
168 static inline void reader_free(xmlreader
*reader
, void *mem
)
170 m_free(reader
->imalloc
, mem
);
173 /* reader input memory allocation functions */
174 static inline void *readerinput_alloc(xmlreaderinput
*input
, size_t len
)
176 return m_alloc(input
->imalloc
, len
);
179 static inline void *readerinput_realloc(xmlreaderinput
*input
, void *mem
, size_t len
)
181 return m_realloc(input
->imalloc
, mem
, len
);
184 static inline void readerinput_free(xmlreaderinput
*input
, void *mem
)
186 m_free(input
->imalloc
, mem
);
189 static inline WCHAR
*readerinput_strdupW(xmlreaderinput
*input
, const WCHAR
*str
)
196 size
= (strlenW(str
)+1)*sizeof(WCHAR
);
197 ret
= readerinput_alloc(input
, size
);
198 if (ret
) memcpy(ret
, str
, size
);
204 static void reader_clear_attrs(xmlreader
*reader
)
206 struct attribute
*attr
, *attr2
;
207 LIST_FOR_EACH_ENTRY_SAFE(attr
, attr2
, &reader
->attrs
, struct attribute
, entry
)
209 reader_free(reader
, attr
);
211 list_init(&reader
->attrs
);
212 reader
->attr_count
= 0;
215 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
216 while we are on a node with attributes */
217 static HRESULT
reader_add_attr(xmlreader
*reader
, strval
*localname
, strval
*value
)
219 struct attribute
*attr
;
221 attr
= reader_alloc(reader
, sizeof(*attr
));
222 if (!attr
) return E_OUTOFMEMORY
;
224 attr
->localname
= *localname
;
225 attr
->value
= *value
;
226 list_add_tail(&reader
->attrs
, &attr
->entry
);
227 reader
->attr_count
++;
232 static HRESULT
init_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
234 const int initial_len
= 0x2000;
235 buffer
->data
= readerinput_alloc(input
, initial_len
);
236 if (!buffer
->data
) return E_OUTOFMEMORY
;
238 memset(buffer
->data
, 0, 4);
239 buffer
->cur
= buffer
->data
;
240 buffer
->allocated
= initial_len
;
246 static void free_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
248 readerinput_free(input
, buffer
->data
);
251 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
253 if (encoding
== XmlEncoding_Unknown
)
255 FIXME("unsupported encoding %d\n", encoding
);
259 *cp
= xml_encoding_map
[encoding
].cp
;
264 static xml_encoding
parse_encoding_name(const WCHAR
*name
, int len
)
268 if (!name
) return XmlEncoding_Unknown
;
271 max
= sizeof(xml_encoding_map
)/sizeof(struct xml_encoding_data
) - 1;
278 c
= strncmpiW(xml_encoding_map
[n
].name
, name
, len
);
280 c
= strcmpiW(xml_encoding_map
[n
].name
, name
);
282 return xml_encoding_map
[n
].enc
;
290 return XmlEncoding_Unknown
;
293 static HRESULT
alloc_input_buffer(xmlreaderinput
*input
)
295 input_buffer
*buffer
;
298 input
->buffer
= NULL
;
300 buffer
= readerinput_alloc(input
, sizeof(*buffer
));
301 if (!buffer
) return E_OUTOFMEMORY
;
303 buffer
->input
= input
;
304 buffer
->code_page
= ~0; /* code page is unknown at this point */
305 hr
= init_encoded_buffer(input
, &buffer
->utf16
);
307 readerinput_free(input
, buffer
);
311 hr
= init_encoded_buffer(input
, &buffer
->encoded
);
313 free_encoded_buffer(input
, &buffer
->utf16
);
314 readerinput_free(input
, buffer
);
318 input
->buffer
= buffer
;
322 static void free_input_buffer(input_buffer
*buffer
)
324 free_encoded_buffer(buffer
->input
, &buffer
->encoded
);
325 free_encoded_buffer(buffer
->input
, &buffer
->utf16
);
326 readerinput_free(buffer
->input
, buffer
);
329 static void readerinput_release_stream(xmlreaderinput
*readerinput
)
331 if (readerinput
->stream
) {
332 ISequentialStream_Release(readerinput
->stream
);
333 readerinput
->stream
= NULL
;
337 /* Queries already stored interface for IStream/ISequentialStream.
338 Interface supplied on creation will be overwritten */
339 static HRESULT
readerinput_query_for_stream(xmlreaderinput
*readerinput
)
343 readerinput_release_stream(readerinput
);
344 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_IStream
, (void**)&readerinput
->stream
);
346 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_ISequentialStream
, (void**)&readerinput
->stream
);
351 /* reads a chunk to raw buffer */
352 static HRESULT
readerinput_growraw(xmlreaderinput
*readerinput
)
354 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
355 ULONG len
= buffer
->allocated
- buffer
->written
, read
;
358 /* always try to get aligned to 4 bytes, so the only case we can get partialy read characters is
359 variable width encodings like UTF-8 */
360 len
= (len
+ 3) & ~3;
361 /* try to use allocated space or grow */
362 if (buffer
->allocated
- buffer
->written
< len
)
364 buffer
->allocated
*= 2;
365 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, buffer
->allocated
);
366 len
= buffer
->allocated
- buffer
->written
;
369 hr
= ISequentialStream_Read(readerinput
->stream
, buffer
->data
+ buffer
->written
, len
, &read
);
370 if (FAILED(hr
)) return hr
;
371 TRACE("requested %d, read %d, ret 0x%08x\n", len
, read
, hr
);
372 buffer
->written
+= read
;
377 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
378 static void readerinput_grow(xmlreaderinput
*readerinput
, int length
)
380 encoded_buffer
*buffer
= &readerinput
->buffer
->utf16
;
382 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
383 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
385 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
386 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, grown_size
);
387 buffer
->allocated
= grown_size
;
391 static HRESULT
readerinput_detectencoding(xmlreaderinput
*readerinput
, xml_encoding
*enc
)
393 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
394 static char startA
[] = {'<','?','x','m'};
395 static WCHAR startW
[] = {'<','?'};
396 static char utf8bom
[] = {0xef,0xbb,0xbf};
397 static char utf16lebom
[] = {0xff,0xfe};
399 *enc
= XmlEncoding_Unknown
;
401 if (buffer
->written
<= 3) return MX_E_INPUTEND
;
403 /* try start symbols if we have enough data to do that, input buffer should contain
404 first chunk already */
405 if (!memcmp(buffer
->data
, startA
, sizeof(startA
)))
406 *enc
= XmlEncoding_UTF8
;
407 else if (!memcmp(buffer
->data
, startW
, sizeof(startW
)))
408 *enc
= XmlEncoding_UTF16
;
409 /* try with BOM now */
410 else if (!memcmp(buffer
->data
, utf8bom
, sizeof(utf8bom
)))
412 buffer
->cur
+= sizeof(utf8bom
);
413 *enc
= XmlEncoding_UTF8
;
415 else if (!memcmp(buffer
->data
, utf16lebom
, sizeof(utf16lebom
)))
417 buffer
->cur
+= sizeof(utf16lebom
);
418 *enc
= XmlEncoding_UTF16
;
424 static int readerinput_get_utf8_convlen(xmlreaderinput
*readerinput
)
426 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
427 int len
= buffer
->written
;
429 /* complete single byte char */
430 if (!(buffer
->data
[len
-1] & 0x80)) return len
;
432 /* find start byte of multibyte char */
433 while (--len
&& !(buffer
->data
[len
] & 0xc0))
439 /* returns byte length of complete char sequence for specified code page, */
440 static int readerinput_get_convlen(xmlreaderinput
*readerinput
, UINT cp
)
442 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
443 int len
= buffer
->written
;
446 len
= readerinput_get_utf8_convlen(readerinput
);
448 len
= buffer
->written
;
450 return len
- (buffer
->cur
- buffer
->data
);
453 /* note that raw buffer content is kept */
454 static void readerinput_switchencoding(xmlreaderinput
*readerinput
, xml_encoding enc
)
456 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
457 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
462 hr
= get_code_page(enc
, &cp
);
463 if (FAILED(hr
)) return;
465 len
= readerinput_get_convlen(readerinput
, cp
);
467 TRACE("switching to cp %d\n", cp
);
469 /* just copy in this case */
470 if (enc
== XmlEncoding_UTF16
)
472 readerinput_grow(readerinput
, len
);
473 memcpy(dest
->data
, src
->cur
, len
);
474 readerinput
->buffer
->code_page
= cp
;
478 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
479 readerinput_grow(readerinput
, dest_len
);
480 MultiByteToWideChar(cp
, 0, src
->cur
, len
, (WCHAR
*)dest
->data
, dest_len
);
481 dest
->data
[dest_len
] = 0;
482 readerinput
->buffer
->code_page
= cp
;
485 static inline const WCHAR
*reader_get_cur(xmlreader
*reader
)
487 return (WCHAR
*)reader
->input
->buffer
->utf16
.cur
;
490 static int reader_cmp(xmlreader
*reader
, const WCHAR
*str
)
492 const WCHAR
*ptr
= reader_get_cur(reader
);
495 return strncmpW(str
, ptr
, strlenW(str
));
498 if (ptr
[i
] != str
[i
]) return 0;
505 /* moves cursor n WCHARs forward */
506 static void reader_skipn(xmlreader
*reader
, int n
)
508 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
509 const WCHAR
*ptr
= reader_get_cur(reader
);
511 while (*ptr
++ && n
--)
513 buffer
->cur
+= sizeof(WCHAR
);
518 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
519 static int reader_skipspaces(xmlreader
*reader
)
521 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
522 const WCHAR
*ptr
= reader_get_cur(reader
), *start
= ptr
;
524 while (*ptr
== ' ' || *ptr
== '\t' || *ptr
== '\r' || *ptr
== '\n')
526 buffer
->cur
+= sizeof(WCHAR
);
529 else if (*ptr
== '\n')
542 /* [26] VersionNum ::= '1.' [0-9]+ */
543 static HRESULT
reader_parse_versionnum(xmlreader
*reader
, strval
*val
)
545 const WCHAR
*ptr
, *ptr2
, *start
= reader_get_cur(reader
);
546 static const WCHAR onedotW
[] = {'1','.',0};
548 if (reader_cmp(reader
, onedotW
)) return WC_E_XMLDECL
;
550 reader_skipn(reader
, 2);
552 ptr2
= ptr
= reader_get_cur(reader
);
553 while (*ptr
>= '0' && *ptr
<= '9')
556 if (ptr2
== ptr
) return WC_E_DIGIT
;
557 TRACE("version=%s\n", debugstr_wn(start
, ptr
-start
));
559 val
->len
= ptr
-start
;
560 reader_skipn(reader
, ptr
-ptr2
);
564 /* [25] Eq ::= S? '=' S? */
565 static HRESULT
reader_parse_eq(xmlreader
*reader
)
567 static const WCHAR eqW
[] = {'=',0};
568 reader_skipspaces(reader
);
569 if (reader_cmp(reader
, eqW
)) return WC_E_EQUAL
;
571 reader_skipn(reader
, 1);
572 reader_skipspaces(reader
);
576 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
577 static HRESULT
reader_parse_versioninfo(xmlreader
*reader
)
579 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
583 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
585 if (reader_cmp(reader
, versionW
)) return WC_E_XMLDECL
;
586 name
.str
= reader_get_cur(reader
);
589 reader_skipn(reader
, 7);
591 hr
= reader_parse_eq(reader
);
592 if (FAILED(hr
)) return hr
;
594 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
597 reader_skipn(reader
, 1);
599 hr
= reader_parse_versionnum(reader
, &val
);
600 if (FAILED(hr
)) return hr
;
602 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
606 reader_skipn(reader
, 1);
608 return reader_add_attr(reader
, &name
, &val
);
611 /* ([A-Za-z0-9._] | '-') */
612 static inline int is_wchar_encname(WCHAR ch
)
614 return ((ch
>= 'A' && ch
<= 'Z') ||
615 (ch
>= 'a' && ch
<= 'z') ||
616 (ch
>= '0' && ch
<= '9') ||
617 (ch
== '.') || (ch
== '_') ||
621 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
622 static HRESULT
reader_parse_encname(xmlreader
*reader
, strval
*val
)
624 const WCHAR
*start
= reader_get_cur(reader
), *ptr
;
628 if ((*start
< 'A' || *start
> 'Z') && (*start
< 'a' || *start
> 'z'))
632 while (is_wchar_encname(*++ptr
))
636 enc
= parse_encoding_name(start
, len
);
637 TRACE("encoding name %s\n", debugstr_wn(start
, len
));
641 if (enc
== XmlEncoding_Unknown
)
644 /* skip encoding name */
645 reader_skipn(reader
, len
);
649 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
650 static HRESULT
reader_parse_encdecl(xmlreader
*reader
)
652 static const WCHAR encodingW
[] = {'e','n','c','o','d','i','n','g',0};
656 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
658 if (reader_cmp(reader
, encodingW
)) return S_FALSE
;
659 name
.str
= reader_get_cur(reader
);
661 /* skip 'encoding' */
662 reader_skipn(reader
, 8);
664 hr
= reader_parse_eq(reader
);
665 if (FAILED(hr
)) return hr
;
667 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
670 reader_skipn(reader
, 1);
672 hr
= reader_parse_encname(reader
, &val
);
673 if (FAILED(hr
)) return hr
;
675 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
679 reader_skipn(reader
, 1);
681 return reader_add_attr(reader
, &name
, &val
);
684 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
685 static HRESULT
reader_parse_sddecl(xmlreader
*reader
)
687 static const WCHAR standaloneW
[] = {'s','t','a','n','d','a','l','o','n','e',0};
688 static const WCHAR yesW
[] = {'y','e','s',0};
689 static const WCHAR noW
[] = {'n','o',0};
690 const WCHAR
*start
, *ptr
;
694 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
696 if (reader_cmp(reader
, standaloneW
)) return S_FALSE
;
697 name
.str
= reader_get_cur(reader
);
699 /* skip 'standalone' */
700 reader_skipn(reader
, 10);
702 hr
= reader_parse_eq(reader
);
703 if (FAILED(hr
)) return hr
;
705 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
708 reader_skipn(reader
, 1);
710 if (reader_cmp(reader
, yesW
) && reader_cmp(reader
, noW
))
713 start
= reader_get_cur(reader
);
714 /* skip 'yes'|'no' */
715 reader_skipn(reader
, reader_cmp(reader
, yesW
) ? 2 : 3);
716 ptr
= reader_get_cur(reader
);
717 TRACE("standalone=%s\n", debugstr_wn(start
, ptr
-start
));
721 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
724 reader_skipn(reader
, 1);
726 return reader_add_attr(reader
, &name
, &val
);
729 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
730 static HRESULT
reader_parse_xmldecl(xmlreader
*reader
)
732 static const WCHAR xmldeclW
[] = {'<','?','x','m','l',0};
733 static const WCHAR declcloseW
[] = {'?','>',0};
736 /* check if we have "<?xml" */
737 if (reader_cmp(reader
, xmldeclW
)) return S_FALSE
;
739 reader_skipn(reader
, 5);
740 hr
= reader_parse_versioninfo(reader
);
744 hr
= reader_parse_encdecl(reader
);
748 hr
= reader_parse_sddecl(reader
);
752 reader_skipspaces(reader
);
753 if (reader_cmp(reader
, declcloseW
)) return WC_E_XMLDECL
;
754 reader_skipn(reader
, 2);
759 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
761 xmlreader
*This
= impl_from_IXmlReader(iface
);
763 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
765 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
766 IsEqualGUID(riid
, &IID_IXmlReader
))
772 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
773 return E_NOINTERFACE
;
776 IXmlReader_AddRef(iface
);
781 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
783 xmlreader
*This
= impl_from_IXmlReader(iface
);
784 ULONG ref
= InterlockedIncrement(&This
->ref
);
785 TRACE("(%p)->(%d)\n", This
, ref
);
789 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
791 xmlreader
*This
= impl_from_IXmlReader(iface
);
792 LONG ref
= InterlockedDecrement(&This
->ref
);
794 TRACE("(%p)->(%d)\n", This
, ref
);
798 IMalloc
*imalloc
= This
->imalloc
;
799 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
800 reader_clear_attrs(This
);
801 reader_free(This
, This
);
802 if (imalloc
) IMalloc_Release(imalloc
);
808 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
810 xmlreader
*This
= impl_from_IXmlReader(iface
);
813 TRACE("(%p %p)\n", This
, input
);
817 readerinput_release_stream(This
->input
);
818 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
822 This
->line
= This
->pos
= 0;
824 /* just reset current input */
827 This
->state
= XmlReadState_Initial
;
831 /* now try IXmlReaderInput, ISequentialStream, IStream */
832 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&This
->input
);
835 IXmlReaderInput
*readerinput
;
837 /* create IXmlReaderInput basing on supplied interface */
838 hr
= CreateXmlReaderInputWithEncodingName(input
,
839 NULL
, NULL
, FALSE
, NULL
, &readerinput
);
840 if (hr
!= S_OK
) return hr
;
841 This
->input
= impl_from_IXmlReaderInput(readerinput
);
844 /* set stream for supplied IXmlReaderInput */
845 hr
= readerinput_query_for_stream(This
->input
);
847 This
->state
= XmlReadState_Initial
;
852 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
854 xmlreader
*This
= impl_from_IXmlReader(iface
);
856 TRACE("(%p %u %p)\n", This
, property
, value
);
858 if (!value
) return E_INVALIDARG
;
862 case XmlReaderProperty_DtdProcessing
:
863 *value
= This
->dtdmode
;
865 case XmlReaderProperty_ReadState
:
866 *value
= This
->state
;
869 FIXME("Unimplemented property (%u)\n", property
);
876 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
878 xmlreader
*This
= impl_from_IXmlReader(iface
);
880 TRACE("(%p %u %lu)\n", iface
, property
, value
);
884 case XmlReaderProperty_DtdProcessing
:
885 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
886 This
->dtdmode
= value
;
889 FIXME("Unimplemented property (%u)\n", property
);
896 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*node_type
)
898 xmlreader
*This
= impl_from_IXmlReader(iface
);
900 FIXME("(%p)->(%p): stub\n", This
, node_type
);
902 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
904 /* if it's a first call for a new input we need to detect stream encoding */
905 if (This
->state
== XmlReadState_Initial
)
910 hr
= readerinput_growraw(This
->input
);
911 if (FAILED(hr
)) return hr
;
913 /* try to detect encoding by BOM or data and set input code page */
914 hr
= readerinput_detectencoding(This
->input
, &enc
);
915 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
916 if (FAILED(hr
)) return hr
;
918 /* always switch first time cause we have to put something in */
919 readerinput_switchencoding(This
->input
, enc
);
921 /* parse xml declaration */
922 hr
= reader_parse_xmldecl(This
);
923 if (FAILED(hr
)) return hr
;
927 This
->state
= XmlReadState_Interactive
;
928 This
->nodetype
= *node_type
= XmlNodeType_XmlDeclaration
;
936 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
938 xmlreader
*This
= impl_from_IXmlReader(iface
);
939 TRACE("(%p)->(%p)\n", This
, node_type
);
941 /* When we're on attribute always return attribute type, container node type is kept.
942 Note that container is not necessarily an element, and attribute doesn't mean it's
943 an attribute in XML spec terms. */
944 *node_type
= This
->attr
? XmlNodeType_Attribute
: This
->nodetype
;
945 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
948 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
950 xmlreader
*This
= impl_from_IXmlReader(iface
);
952 TRACE("(%p)\n", This
);
954 if (!This
->attr_count
) return S_FALSE
;
955 This
->attr
= LIST_ENTRY(list_head(&This
->attrs
), struct attribute
, entry
);
959 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
961 xmlreader
*This
= impl_from_IXmlReader(iface
);
962 const struct list
*next
;
964 TRACE("(%p)\n", This
);
966 if (!This
->attr_count
) return S_FALSE
;
969 return IXmlReader_MoveToFirstAttribute(iface
);
971 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
973 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
975 return next
? S_OK
: S_FALSE
;
978 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
980 LPCWSTR namespaceUri
)
982 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
986 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
988 xmlreader
*This
= impl_from_IXmlReader(iface
);
990 TRACE("(%p)\n", This
);
992 if (!This
->attr_count
) return S_FALSE
;
997 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*qualifiedName
,
998 UINT
*qualifiedName_length
)
1000 FIXME("(%p %p %p): stub\n", iface
, qualifiedName
, qualifiedName_length
);
1004 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
,
1005 LPCWSTR
*namespaceUri
,
1006 UINT
*namespaceUri_length
)
1008 FIXME("(%p %p %p): stub\n", iface
, namespaceUri
, namespaceUri_length
);
1012 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
,
1013 LPCWSTR
*local_name
,
1014 UINT
*local_name_length
)
1016 FIXME("(%p %p %p): stub\n", iface
, local_name
, local_name_length
);
1020 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
,
1022 UINT
*prefix_length
)
1024 FIXME("(%p %p %p): stub\n", iface
, prefix
, prefix_length
);
1028 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
,
1032 FIXME("(%p %p %p): stub\n", iface
, value
, value_length
);
1036 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
,
1041 FIXME("(%p %p %u %p): stub\n", iface
, buffer
, chunk_size
, read
);
1045 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
1047 UINT
*baseUri_length
)
1049 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
1053 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
1055 FIXME("(%p): stub\n", iface
);
1059 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
1061 FIXME("(%p): stub\n", iface
);
1065 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
1067 xmlreader
*This
= impl_from_IXmlReader(iface
);
1069 TRACE("(%p %p)\n", This
, lineNumber
);
1071 if (!lineNumber
) return E_INVALIDARG
;
1073 *lineNumber
= This
->line
;
1078 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
1080 xmlreader
*This
= impl_from_IXmlReader(iface
);
1082 TRACE("(%p %p)\n", This
, linePosition
);
1084 if (!linePosition
) return E_INVALIDARG
;
1086 *linePosition
= This
->pos
;
1091 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
1093 xmlreader
*This
= impl_from_IXmlReader(iface
);
1095 TRACE("(%p)->(%p)\n", This
, count
);
1097 if (!count
) return E_INVALIDARG
;
1099 *count
= This
->attr_count
;
1103 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
1105 FIXME("(%p %p): stub\n", iface
, depth
);
1109 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
1111 FIXME("(%p): stub\n", iface
);
1115 static const struct IXmlReaderVtbl xmlreader_vtbl
=
1117 xmlreader_QueryInterface
,
1121 xmlreader_GetProperty
,
1122 xmlreader_SetProperty
,
1124 xmlreader_GetNodeType
,
1125 xmlreader_MoveToFirstAttribute
,
1126 xmlreader_MoveToNextAttribute
,
1127 xmlreader_MoveToAttributeByName
,
1128 xmlreader_MoveToElement
,
1129 xmlreader_GetQualifiedName
,
1130 xmlreader_GetNamespaceUri
,
1131 xmlreader_GetLocalName
,
1132 xmlreader_GetPrefix
,
1134 xmlreader_ReadValueChunk
,
1135 xmlreader_GetBaseUri
,
1136 xmlreader_IsDefault
,
1137 xmlreader_IsEmptyElement
,
1138 xmlreader_GetLineNumber
,
1139 xmlreader_GetLinePosition
,
1140 xmlreader_GetAttributeCount
,
1145 /** IXmlReaderInput **/
1146 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
1148 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1150 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
1152 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
1153 IsEqualGUID(riid
, &IID_IUnknown
))
1159 WARN("interface %s not implemented\n", debugstr_guid(riid
));
1160 return E_NOINTERFACE
;
1163 IUnknown_AddRef(iface
);
1168 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
1170 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1171 ULONG ref
= InterlockedIncrement(&This
->ref
);
1172 TRACE("(%p)->(%d)\n", This
, ref
);
1176 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
1178 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
1179 LONG ref
= InterlockedDecrement(&This
->ref
);
1181 TRACE("(%p)->(%d)\n", This
, ref
);
1185 IMalloc
*imalloc
= This
->imalloc
;
1186 if (This
->input
) IUnknown_Release(This
->input
);
1187 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1188 if (This
->buffer
) free_input_buffer(This
->buffer
);
1189 readerinput_free(This
, This
->baseuri
);
1190 readerinput_free(This
, This
);
1191 if (imalloc
) IMalloc_Release(imalloc
);
1197 static const struct IUnknownVtbl xmlreaderinput_vtbl
=
1199 xmlreaderinput_QueryInterface
,
1200 xmlreaderinput_AddRef
,
1201 xmlreaderinput_Release
1204 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1208 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1210 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
1212 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
1217 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
1219 reader
= heap_alloc(sizeof(*reader
));
1220 if(!reader
) return E_OUTOFMEMORY
;
1222 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
1224 reader
->input
= NULL
;
1225 reader
->state
= XmlReadState_Closed
;
1226 reader
->dtdmode
= DtdProcessing_Prohibit
;
1227 reader
->line
= reader
->pos
= 0;
1228 reader
->imalloc
= imalloc
;
1229 if (imalloc
) IMalloc_AddRef(imalloc
);
1230 reader
->nodetype
= XmlNodeType_None
;
1231 list_init(&reader
->attrs
);
1232 reader
->attr_count
= 0;
1233 reader
->attr
= NULL
;
1235 *obj
= &reader
->IXmlReader_iface
;
1237 TRACE("returning iface %p\n", *obj
);
1242 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
1247 IXmlReaderInput
**ppInput
)
1249 xmlreaderinput
*readerinput
;
1252 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
1253 hint
, wine_dbgstr_w(base_uri
), ppInput
);
1255 if (!stream
|| !ppInput
) return E_INVALIDARG
;
1258 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
1260 readerinput
= heap_alloc(sizeof(*readerinput
));
1261 if(!readerinput
) return E_OUTOFMEMORY
;
1263 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinput_vtbl
;
1264 readerinput
->ref
= 1;
1265 readerinput
->imalloc
= imalloc
;
1266 readerinput
->stream
= NULL
;
1267 if (imalloc
) IMalloc_AddRef(imalloc
);
1268 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
1269 readerinput
->hint
= hint
;
1270 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
1272 hr
= alloc_input_buffer(readerinput
);
1275 readerinput_free(readerinput
, readerinput
);
1278 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
1280 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
1282 TRACE("returning iface %p\n", *ppInput
);