2 * IXmlReader implementation
4 * Copyright 2010, 2012-2013, 2016 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 #include "xmllite_private.h"
25 #include <wine/list.h>
26 #include <wine/unicode.h>
28 /* not defined in public headers */
29 DEFINE_GUID(IID_IXmlReaderInput
, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
33 XmlReadInState_Initial
,
34 XmlReadInState_XmlDecl
,
35 XmlReadInState_Misc_DTD
,
37 XmlReadInState_DTD_Misc
,
38 XmlReadInState_Element
,
39 XmlReadInState_Content
,
40 XmlReadInState_MiscEnd
, /* optional Misc at the end of a document */
42 } XmlReaderInternalState
;
44 /* This state denotes where parsing was interrupted by input problem.
45 Reader resumes parsing using this information. */
48 XmlReadResumeState_Initial
,
49 XmlReadResumeState_PITarget
,
50 XmlReadResumeState_PIBody
,
51 XmlReadResumeState_CDATA
,
52 XmlReadResumeState_Comment
,
53 XmlReadResumeState_STag
,
54 XmlReadResumeState_CharData
,
55 XmlReadResumeState_Whitespace
56 } XmlReaderResumeState
;
58 /* saved pointer index to resume from particular input position */
61 XmlReadResume_Name
, /* PITarget, name for NCName, prefix for QName */
62 XmlReadResume_Local
, /* local for QName */
63 XmlReadResume_Body
, /* PI body, comment text, CDATA text, CharData text */
69 StringValue_LocalName
,
71 StringValue_QualifiedName
,
74 } XmlReaderStringValue
;
76 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
77 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
79 static const WCHAR dblquoteW
[] = {'\"',0};
80 static const WCHAR quoteW
[] = {'\'',0};
81 static const WCHAR ltW
[] = {'<',0};
82 static const WCHAR gtW
[] = {'>',0};
83 static const WCHAR commentW
[] = {'<','!','-','-',0};
84 static const WCHAR piW
[] = {'<','?',0};
86 static const char *debugstr_nodetype(XmlNodeType nodetype
)
88 static const char * const type_names
[] =
97 "ProcessingInstruction",
110 if (nodetype
> _XmlNodeType_Last
)
111 return wine_dbg_sprintf("unknown type=%d", nodetype
);
113 return type_names
[nodetype
];
116 static const char *debugstr_reader_prop(XmlReaderProperty prop
)
118 static const char * const prop_names
[] =
130 if (prop
> _XmlReaderProperty_Last
)
131 return wine_dbg_sprintf("unknown property=%d", prop
);
133 return prop_names
[prop
];
136 struct xml_encoding_data
143 static const struct xml_encoding_data xml_encoding_map
[] = {
144 { utf16W
, XmlEncoding_UTF16
, ~0 },
145 { utf8W
, XmlEncoding_UTF8
, CP_UTF8
}
148 const WCHAR
*get_encoding_name(xml_encoding encoding
)
150 return xml_encoding_map
[encoding
].name
;
153 xml_encoding
get_encoding_from_codepage(UINT codepage
)
156 for (i
= 0; i
< sizeof(xml_encoding_map
)/sizeof(xml_encoding_map
[0]); i
++)
158 if (xml_encoding_map
[i
].cp
== codepage
) return xml_encoding_map
[i
].enc
;
160 return XmlEncoding_Unknown
;
167 unsigned int allocated
;
168 unsigned int written
;
171 typedef struct input_buffer input_buffer
;
175 IXmlReaderInput IXmlReaderInput_iface
;
177 /* reference passed on IXmlReaderInput creation, is kept when input is created */
180 xml_encoding encoding
;
183 /* stream reference set after SetInput() call from reader,
184 stored as sequential stream, cause currently
185 optimizations possible with IStream aren't implemented */
186 ISequentialStream
*stream
;
187 input_buffer
*buffer
;
188 unsigned int pending
: 1;
191 static const struct IUnknownVtbl xmlreaderinputvtbl
;
193 /* Structure to hold parsed string of specific length.
195 Reader stores node value as 'start' pointer, on request
196 a null-terminated version of it is allocated.
198 To init a strval variable use reader_init_strval(),
199 to set strval as a reader value use reader_set_strval().
203 WCHAR
*str
; /* allocated null-terminated string */
204 UINT len
; /* length in WCHARs, altered after ReadValueChunk */
205 UINT start
; /* input position where value starts */
208 static WCHAR emptyW
[] = {0};
209 static WCHAR xmlW
[] = {'x','m','l',0};
210 static WCHAR xmlnsW
[] = {'x','m','l','n','s',0};
211 static const strval strval_empty
= { emptyW
};
212 static const strval strval_xml
= { xmlW
, 3 };
213 static const strval strval_xmlns
= { xmlnsW
, 5 };
236 struct element
*element
;
241 IXmlReader IXmlReader_iface
;
243 xmlreaderinput
*input
;
246 XmlReaderInternalState instate
;
247 XmlReaderResumeState resumestate
;
248 XmlNodeType nodetype
;
249 DtdProcessing dtdmode
;
250 IXmlResolver
*resolver
;
252 UINT line
, pos
; /* reader position in XML stream */
253 struct list attrs
; /* attributes list for current node */
254 struct attribute
*attr
; /* current attribute */
258 struct list elements
;
259 strval strvalues
[StringValue_Last
];
262 BOOL is_empty_element
;
263 struct element empty_element
;
264 UINT resume
[XmlReadResume_Last
]; /* offsets used to resume reader */
269 encoded_buffer utf16
;
270 encoded_buffer encoded
;
272 xmlreaderinput
*input
;
275 static inline xmlreader
*impl_from_IXmlReader(IXmlReader
*iface
)
277 return CONTAINING_RECORD(iface
, xmlreader
, IXmlReader_iface
);
280 static inline xmlreaderinput
*impl_from_IXmlReaderInput(IXmlReaderInput
*iface
)
282 return CONTAINING_RECORD(iface
, xmlreaderinput
, IXmlReaderInput_iface
);
285 /* reader memory allocation functions */
286 static inline void *reader_alloc(xmlreader
*reader
, size_t len
)
288 return m_alloc(reader
->imalloc
, len
);
291 static inline void *reader_alloc_zero(xmlreader
*reader
, size_t len
)
293 void *ret
= reader_alloc(reader
, len
);
299 static inline void reader_free(xmlreader
*reader
, void *mem
)
301 m_free(reader
->imalloc
, mem
);
304 /* Just return pointer from offset, no attempt to read more. */
305 static inline WCHAR
*reader_get_ptr2(const xmlreader
*reader
, UINT offset
)
307 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
308 return (WCHAR
*)buffer
->data
+ offset
;
311 static inline WCHAR
*reader_get_strptr(const xmlreader
*reader
, const strval
*v
)
313 return v
->str
? v
->str
: reader_get_ptr2(reader
, v
->start
);
316 static HRESULT
reader_strvaldup(xmlreader
*reader
, const strval
*src
, strval
*dest
)
320 if (src
->str
!= strval_empty
.str
)
322 dest
->str
= reader_alloc(reader
, (dest
->len
+1)*sizeof(WCHAR
));
323 if (!dest
->str
) return E_OUTOFMEMORY
;
324 memcpy(dest
->str
, reader_get_strptr(reader
, src
), dest
->len
*sizeof(WCHAR
));
325 dest
->str
[dest
->len
] = 0;
332 /* reader input memory allocation functions */
333 static inline void *readerinput_alloc(xmlreaderinput
*input
, size_t len
)
335 return m_alloc(input
->imalloc
, len
);
338 static inline void *readerinput_realloc(xmlreaderinput
*input
, void *mem
, size_t len
)
340 return m_realloc(input
->imalloc
, mem
, len
);
343 static inline void readerinput_free(xmlreaderinput
*input
, void *mem
)
345 m_free(input
->imalloc
, mem
);
348 static inline WCHAR
*readerinput_strdupW(xmlreaderinput
*input
, const WCHAR
*str
)
355 size
= (strlenW(str
)+1)*sizeof(WCHAR
);
356 ret
= readerinput_alloc(input
, size
);
357 if (ret
) memcpy(ret
, str
, size
);
363 static void reader_clear_attrs(xmlreader
*reader
)
365 struct attribute
*attr
, *attr2
;
366 LIST_FOR_EACH_ENTRY_SAFE(attr
, attr2
, &reader
->attrs
, struct attribute
, entry
)
368 reader_free(reader
, attr
);
370 list_init(&reader
->attrs
);
371 reader
->attr_count
= 0;
375 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
376 while we are on a node with attributes */
377 static HRESULT
reader_add_attr(xmlreader
*reader
, strval
*prefix
, strval
*localname
, strval
*value
)
379 struct attribute
*attr
;
381 attr
= reader_alloc(reader
, sizeof(*attr
));
382 if (!attr
) return E_OUTOFMEMORY
;
385 attr
->prefix
= *prefix
;
387 memset(&attr
->prefix
, 0, sizeof(attr
->prefix
));
388 attr
->localname
= *localname
;
389 attr
->value
= *value
;
390 list_add_tail(&reader
->attrs
, &attr
->entry
);
391 reader
->attr_count
++;
396 /* This one frees stored string value if needed */
397 static void reader_free_strvalued(xmlreader
*reader
, strval
*v
)
399 if (v
->str
!= strval_empty
.str
)
401 reader_free(reader
, v
->str
);
406 static inline void reader_init_strvalue(UINT start
, UINT len
, strval
*v
)
413 static inline const char* debug_strval(const xmlreader
*reader
, const strval
*v
)
415 return debugstr_wn(reader_get_strptr(reader
, v
), v
->len
);
418 /* used to initialize from constant string */
419 static inline void reader_init_cstrvalue(WCHAR
*str
, UINT len
, strval
*v
)
426 static void reader_free_strvalue(xmlreader
*reader
, XmlReaderStringValue type
)
428 reader_free_strvalued(reader
, &reader
->strvalues
[type
]);
431 static void reader_free_strvalues(xmlreader
*reader
)
434 for (type
= 0; type
< StringValue_Last
; type
++)
435 reader_free_strvalue(reader
, type
);
438 /* This helper should only be used to test if strings are the same,
439 it doesn't try to sort. */
440 static inline int strval_eq(const xmlreader
*reader
, const strval
*str1
, const strval
*str2
)
442 if (str1
->len
!= str2
->len
) return 0;
443 return !memcmp(reader_get_strptr(reader
, str1
), reader_get_strptr(reader
, str2
), str1
->len
*sizeof(WCHAR
));
446 static void reader_clear_elements(xmlreader
*reader
)
448 struct element
*elem
, *elem2
;
449 LIST_FOR_EACH_ENTRY_SAFE(elem
, elem2
, &reader
->elements
, struct element
, entry
)
451 reader_free_strvalued(reader
, &elem
->prefix
);
452 reader_free_strvalued(reader
, &elem
->localname
);
453 reader_free_strvalued(reader
, &elem
->qname
);
454 reader_free(reader
, elem
);
456 list_init(&reader
->elements
);
457 reader
->is_empty_element
= FALSE
;
460 static HRESULT
reader_inc_depth(xmlreader
*reader
)
462 if (++reader
->depth
> reader
->max_depth
) return SC_E_MAXELEMENTDEPTH
;
466 static void reader_dec_depth(xmlreader
*reader
)
468 if (reader
->depth
> 1) reader
->depth
--;
471 static HRESULT
reader_push_ns(xmlreader
*reader
, const strval
*prefix
, const strval
*uri
, BOOL def
)
476 ns
= reader_alloc(reader
, sizeof(*ns
));
477 if (!ns
) return E_OUTOFMEMORY
;
480 memset(&ns
->prefix
, 0, sizeof(ns
->prefix
));
482 hr
= reader_strvaldup(reader
, prefix
, &ns
->prefix
);
484 reader_free(reader
, ns
);
489 hr
= reader_strvaldup(reader
, uri
, &ns
->uri
);
491 reader_free_strvalued(reader
, &ns
->prefix
);
492 reader_free(reader
, ns
);
497 list_add_head(def
? &reader
->nsdef
: &reader
->ns
, &ns
->entry
);
501 static void reader_free_element(xmlreader
*reader
, struct element
*element
)
503 reader_free_strvalued(reader
, &element
->prefix
);
504 reader_free_strvalued(reader
, &element
->localname
);
505 reader_free_strvalued(reader
, &element
->qname
);
506 reader_free(reader
, element
);
509 static void reader_mark_ns_nodes(xmlreader
*reader
, struct element
*element
)
513 LIST_FOR_EACH_ENTRY(ns
, &reader
->ns
, struct ns
, entry
) {
516 ns
->element
= element
;
519 LIST_FOR_EACH_ENTRY(ns
, &reader
->nsdef
, struct ns
, entry
) {
522 ns
->element
= element
;
526 static HRESULT
reader_push_element(xmlreader
*reader
, strval
*prefix
, strval
*localname
,
529 struct element
*element
;
532 if (!list_empty(&reader
->elements
))
534 hr
= reader_inc_depth(reader
);
539 element
= reader_alloc_zero(reader
, sizeof(*element
));
545 if ((hr
= reader_strvaldup(reader
, prefix
, &element
->prefix
)) != S_OK
||
546 (hr
= reader_strvaldup(reader
, localname
, &element
->localname
)) != S_OK
||
547 (hr
= reader_strvaldup(reader
, qname
, &element
->qname
)) != S_OK
)
549 reader_free_element(reader
, element
);
553 list_add_head(&reader
->elements
, &element
->entry
);
554 reader_mark_ns_nodes(reader
, element
);
555 reader
->is_empty_element
= FALSE
;
558 reader_dec_depth(reader
);
562 static void reader_pop_ns_nodes(xmlreader
*reader
, struct element
*element
)
566 LIST_FOR_EACH_ENTRY_SAFE_REV(ns
, ns2
, &reader
->ns
, struct ns
, entry
) {
567 if (ns
->element
!= element
)
570 list_remove(&ns
->entry
);
571 reader_free_strvalued(reader
, &ns
->prefix
);
572 reader_free_strvalued(reader
, &ns
->uri
);
573 reader_free(reader
, ns
);
576 if (!list_empty(&reader
->nsdef
)) {
577 ns
= LIST_ENTRY(list_head(&reader
->nsdef
), struct ns
, entry
);
578 if (ns
->element
== element
) {
579 list_remove(&ns
->entry
);
580 reader_free_strvalued(reader
, &ns
->prefix
);
581 reader_free_strvalued(reader
, &ns
->uri
);
582 reader_free(reader
, ns
);
587 static void reader_pop_element(xmlreader
*reader
)
589 struct element
*element
;
591 if (list_empty(&reader
->elements
))
594 element
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
595 list_remove(&element
->entry
);
597 reader_pop_ns_nodes(reader
, element
);
598 reader_free_element(reader
, element
);
599 reader_dec_depth(reader
);
601 /* It was a root element, the rest is expected as Misc */
602 if (list_empty(&reader
->elements
))
603 reader
->instate
= XmlReadInState_MiscEnd
;
606 /* Always make a copy, cause strings are supposed to be null terminated. Null pointer for 'value'
607 means node value is to be determined. */
608 static void reader_set_strvalue(xmlreader
*reader
, XmlReaderStringValue type
, const strval
*value
)
610 strval
*v
= &reader
->strvalues
[type
];
612 reader_free_strvalue(reader
, type
);
621 if (value
->str
== strval_empty
.str
)
625 if (type
== StringValue_Value
)
627 /* defer allocation for value string */
629 v
->start
= value
->start
;
634 v
->str
= reader_alloc(reader
, (value
->len
+ 1)*sizeof(WCHAR
));
635 memcpy(v
->str
, reader_get_strptr(reader
, value
), value
->len
*sizeof(WCHAR
));
636 v
->str
[value
->len
] = 0;
642 static inline int is_reader_pending(xmlreader
*reader
)
644 return reader
->input
->pending
;
647 static HRESULT
init_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
649 const int initial_len
= 0x2000;
650 buffer
->data
= readerinput_alloc(input
, initial_len
);
651 if (!buffer
->data
) return E_OUTOFMEMORY
;
653 memset(buffer
->data
, 0, 4);
655 buffer
->allocated
= initial_len
;
661 static void free_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
663 readerinput_free(input
, buffer
->data
);
666 HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
668 if (encoding
== XmlEncoding_Unknown
)
670 FIXME("unsupported encoding %d\n", encoding
);
674 *cp
= xml_encoding_map
[encoding
].cp
;
679 xml_encoding
parse_encoding_name(const WCHAR
*name
, int len
)
683 if (!name
) return XmlEncoding_Unknown
;
686 max
= sizeof(xml_encoding_map
)/sizeof(struct xml_encoding_data
) - 1;
693 c
= strncmpiW(xml_encoding_map
[n
].name
, name
, len
);
695 c
= strcmpiW(xml_encoding_map
[n
].name
, name
);
697 return xml_encoding_map
[n
].enc
;
705 return XmlEncoding_Unknown
;
708 static HRESULT
alloc_input_buffer(xmlreaderinput
*input
)
710 input_buffer
*buffer
;
713 input
->buffer
= NULL
;
715 buffer
= readerinput_alloc(input
, sizeof(*buffer
));
716 if (!buffer
) return E_OUTOFMEMORY
;
718 buffer
->input
= input
;
719 buffer
->code_page
= ~0; /* code page is unknown at this point */
720 hr
= init_encoded_buffer(input
, &buffer
->utf16
);
722 readerinput_free(input
, buffer
);
726 hr
= init_encoded_buffer(input
, &buffer
->encoded
);
728 free_encoded_buffer(input
, &buffer
->utf16
);
729 readerinput_free(input
, buffer
);
733 input
->buffer
= buffer
;
737 static void free_input_buffer(input_buffer
*buffer
)
739 free_encoded_buffer(buffer
->input
, &buffer
->encoded
);
740 free_encoded_buffer(buffer
->input
, &buffer
->utf16
);
741 readerinput_free(buffer
->input
, buffer
);
744 static void readerinput_release_stream(xmlreaderinput
*readerinput
)
746 if (readerinput
->stream
) {
747 ISequentialStream_Release(readerinput
->stream
);
748 readerinput
->stream
= NULL
;
752 /* Queries already stored interface for IStream/ISequentialStream.
753 Interface supplied on creation will be overwritten */
754 static inline HRESULT
readerinput_query_for_stream(xmlreaderinput
*readerinput
)
758 readerinput_release_stream(readerinput
);
759 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_IStream
, (void**)&readerinput
->stream
);
761 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_ISequentialStream
, (void**)&readerinput
->stream
);
766 /* reads a chunk to raw buffer */
767 static HRESULT
readerinput_growraw(xmlreaderinput
*readerinput
)
769 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
770 /* to make sure aligned length won't exceed allocated length */
771 ULONG len
= buffer
->allocated
- buffer
->written
- 4;
775 /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
776 variable width encodings like UTF-8 */
777 len
= (len
+ 3) & ~3;
778 /* try to use allocated space or grow */
779 if (buffer
->allocated
- buffer
->written
< len
)
781 buffer
->allocated
*= 2;
782 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, buffer
->allocated
);
783 len
= buffer
->allocated
- buffer
->written
;
787 hr
= ISequentialStream_Read(readerinput
->stream
, buffer
->data
+ buffer
->written
, len
, &read
);
788 TRACE("written=%d, alloc=%d, requested=%d, read=%d, ret=0x%08x\n", buffer
->written
, buffer
->allocated
, len
, read
, hr
);
789 readerinput
->pending
= hr
== E_PENDING
;
790 if (FAILED(hr
)) return hr
;
791 buffer
->written
+= read
;
796 /* grows UTF-16 buffer so it has at least 'length' WCHAR chars free on return */
797 static void readerinput_grow(xmlreaderinput
*readerinput
, int length
)
799 encoded_buffer
*buffer
= &readerinput
->buffer
->utf16
;
801 length
*= sizeof(WCHAR
);
802 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
803 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
805 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
806 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, grown_size
);
807 buffer
->allocated
= grown_size
;
811 static inline BOOL
readerinput_is_utf8(xmlreaderinput
*readerinput
)
813 static const char startA
[] = {'<','?'};
814 static const char commentA
[] = {'<','!'};
815 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
816 unsigned char *ptr
= (unsigned char*)buffer
->data
;
818 return !memcmp(buffer
->data
, startA
, sizeof(startA
)) ||
819 !memcmp(buffer
->data
, commentA
, sizeof(commentA
)) ||
820 /* test start byte */
823 (ptr
[1] && (ptr
[1] <= 0x7f)) ||
824 (buffer
->data
[1] >> 5) == 0x6 || /* 2 bytes */
825 (buffer
->data
[1] >> 4) == 0xe || /* 3 bytes */
826 (buffer
->data
[1] >> 3) == 0x1e) /* 4 bytes */
830 static HRESULT
readerinput_detectencoding(xmlreaderinput
*readerinput
, xml_encoding
*enc
)
832 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
833 static const WCHAR startW
[] = {'<','?'};
834 static const WCHAR commentW
[] = {'<','!'};
835 static const char utf8bom
[] = {0xef,0xbb,0xbf};
836 static const char utf16lebom
[] = {0xff,0xfe};
838 *enc
= XmlEncoding_Unknown
;
840 if (buffer
->written
<= 3)
842 HRESULT hr
= readerinput_growraw(readerinput
);
843 if (FAILED(hr
)) return hr
;
844 if (buffer
->written
<= 3) return MX_E_INPUTEND
;
847 /* try start symbols if we have enough data to do that, input buffer should contain
848 first chunk already */
849 if (readerinput_is_utf8(readerinput
))
850 *enc
= XmlEncoding_UTF8
;
851 else if (!memcmp(buffer
->data
, startW
, sizeof(startW
)) ||
852 !memcmp(buffer
->data
, commentW
, sizeof(commentW
)))
853 *enc
= XmlEncoding_UTF16
;
854 /* try with BOM now */
855 else if (!memcmp(buffer
->data
, utf8bom
, sizeof(utf8bom
)))
857 buffer
->cur
+= sizeof(utf8bom
);
858 *enc
= XmlEncoding_UTF8
;
860 else if (!memcmp(buffer
->data
, utf16lebom
, sizeof(utf16lebom
)))
862 buffer
->cur
+= sizeof(utf16lebom
);
863 *enc
= XmlEncoding_UTF16
;
869 static int readerinput_get_utf8_convlen(xmlreaderinput
*readerinput
)
871 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
872 int len
= buffer
->written
;
874 /* complete single byte char */
875 if (!(buffer
->data
[len
-1] & 0x80)) return len
;
877 /* find start byte of multibyte char */
878 while (--len
&& !(buffer
->data
[len
] & 0xc0))
884 /* Returns byte length of complete char sequence for buffer code page,
885 it's relative to current buffer position which is currently used for BOM handling
887 static int readerinput_get_convlen(xmlreaderinput
*readerinput
)
889 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
892 if (readerinput
->buffer
->code_page
== CP_UTF8
)
893 len
= readerinput_get_utf8_convlen(readerinput
);
895 len
= buffer
->written
;
897 TRACE("%d\n", len
- buffer
->cur
);
898 return len
- buffer
->cur
;
901 /* It's possible that raw buffer has some leftovers from last conversion - some char
902 sequence that doesn't represent a full code point. Length argument should be calculated with
903 readerinput_get_convlen(), if it's -1 it will be calculated here. */
904 static void readerinput_shrinkraw(xmlreaderinput
*readerinput
, int len
)
906 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
909 len
= readerinput_get_convlen(readerinput
);
911 memmove(buffer
->data
, buffer
->data
+ buffer
->cur
+ (buffer
->written
- len
), len
);
912 /* everything below cur is lost too */
913 buffer
->written
-= len
+ buffer
->cur
;
914 /* after this point we don't need cur offset really,
915 it's used only to mark where actual data begins when first chunk is read */
919 /* note that raw buffer content is kept */
920 static void readerinput_switchencoding(xmlreaderinput
*readerinput
, xml_encoding enc
)
922 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
923 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
929 hr
= get_code_page(enc
, &cp
);
930 if (FAILED(hr
)) return;
932 readerinput
->buffer
->code_page
= cp
;
933 len
= readerinput_get_convlen(readerinput
);
935 TRACE("switching to cp %d\n", cp
);
937 /* just copy in this case */
938 if (enc
== XmlEncoding_UTF16
)
940 readerinput_grow(readerinput
, len
);
941 memcpy(dest
->data
, src
->data
+ src
->cur
, len
);
942 dest
->written
+= len
*sizeof(WCHAR
);
946 dest_len
= MultiByteToWideChar(cp
, 0, src
->data
+ src
->cur
, len
, NULL
, 0);
947 readerinput_grow(readerinput
, dest_len
);
948 ptr
= (WCHAR
*)dest
->data
;
949 MultiByteToWideChar(cp
, 0, src
->data
+ src
->cur
, len
, ptr
, dest_len
);
951 dest
->written
+= dest_len
*sizeof(WCHAR
);
954 /* shrinks parsed data a buffer begins with */
955 static void reader_shrink(xmlreader
*reader
)
957 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
959 /* avoid to move too often using threshold shrink length */
960 if (buffer
->cur
*sizeof(WCHAR
) > buffer
->written
/ 2)
962 buffer
->written
-= buffer
->cur
*sizeof(WCHAR
);
963 memmove(buffer
->data
, (WCHAR
*)buffer
->data
+ buffer
->cur
, buffer
->written
);
965 *(WCHAR
*)&buffer
->data
[buffer
->written
] = 0;
969 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
970 It won't attempt to shrink but will grow destination buffer if needed */
971 static HRESULT
reader_more(xmlreader
*reader
)
973 xmlreaderinput
*readerinput
= reader
->input
;
974 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
975 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
976 UINT cp
= readerinput
->buffer
->code_page
;
981 /* get some raw data from stream first */
982 hr
= readerinput_growraw(readerinput
);
983 len
= readerinput_get_convlen(readerinput
);
985 /* just copy for UTF-16 case */
988 readerinput_grow(readerinput
, len
);
989 memcpy(dest
->data
+ dest
->written
, src
->data
+ src
->cur
, len
);
990 dest
->written
+= len
*sizeof(WCHAR
);
994 dest_len
= MultiByteToWideChar(cp
, 0, src
->data
+ src
->cur
, len
, NULL
, 0);
995 readerinput_grow(readerinput
, dest_len
);
996 ptr
= (WCHAR
*)(dest
->data
+ dest
->written
);
997 MultiByteToWideChar(cp
, 0, src
->data
+ src
->cur
, len
, ptr
, dest_len
);
999 dest
->written
+= dest_len
*sizeof(WCHAR
);
1000 /* get rid of processed data */
1001 readerinput_shrinkraw(readerinput
, len
);
1006 static inline UINT
reader_get_cur(xmlreader
*reader
)
1008 return reader
->input
->buffer
->utf16
.cur
;
1011 static inline WCHAR
*reader_get_ptr(xmlreader
*reader
)
1013 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
1014 WCHAR
*ptr
= (WCHAR
*)buffer
->data
+ buffer
->cur
;
1015 if (!*ptr
) reader_more(reader
);
1016 return (WCHAR
*)buffer
->data
+ buffer
->cur
;
1019 static int reader_cmp(xmlreader
*reader
, const WCHAR
*str
)
1022 const WCHAR
*ptr
= reader_get_ptr(reader
);
1027 reader_more(reader
);
1028 ptr
= reader_get_ptr(reader
);
1030 if (str
[i
] != ptr
[i
])
1031 return ptr
[i
] - str
[i
];
1037 /* moves cursor n WCHARs forward */
1038 static void reader_skipn(xmlreader
*reader
, int n
)
1040 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
1041 const WCHAR
*ptr
= reader_get_ptr(reader
);
1043 while (*ptr
++ && n
--)
1050 static inline BOOL
is_wchar_space(WCHAR ch
)
1052 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
1055 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
1056 static int reader_skipspaces(xmlreader
*reader
)
1058 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
1059 const WCHAR
*ptr
= reader_get_ptr(reader
);
1060 UINT start
= reader_get_cur(reader
);
1062 while (is_wchar_space(*ptr
))
1066 else if (*ptr
== '\n')
1075 ptr
= reader_get_ptr(reader
);
1078 return reader_get_cur(reader
) - start
;
1081 /* [26] VersionNum ::= '1.' [0-9]+ */
1082 static HRESULT
reader_parse_versionnum(xmlreader
*reader
, strval
*val
)
1084 static const WCHAR onedotW
[] = {'1','.',0};
1088 if (reader_cmp(reader
, onedotW
)) return WC_E_XMLDECL
;
1090 start
= reader_get_cur(reader
);
1092 reader_skipn(reader
, 2);
1094 ptr2
= ptr
= reader_get_ptr(reader
);
1095 while (*ptr
>= '0' && *ptr
<= '9')
1097 reader_skipn(reader
, 1);
1098 ptr
= reader_get_ptr(reader
);
1101 if (ptr2
== ptr
) return WC_E_DIGIT
;
1102 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, val
);
1103 TRACE("version=%s\n", debug_strval(reader
, val
));
1107 /* [25] Eq ::= S? '=' S? */
1108 static HRESULT
reader_parse_eq(xmlreader
*reader
)
1110 static const WCHAR eqW
[] = {'=',0};
1111 reader_skipspaces(reader
);
1112 if (reader_cmp(reader
, eqW
)) return WC_E_EQUAL
;
1114 reader_skipn(reader
, 1);
1115 reader_skipspaces(reader
);
1119 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
1120 static HRESULT
reader_parse_versioninfo(xmlreader
*reader
)
1122 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
1126 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1128 if (reader_cmp(reader
, versionW
)) return WC_E_XMLDECL
;
1129 reader_init_strvalue(reader_get_cur(reader
), 7, &name
);
1130 /* skip 'version' */
1131 reader_skipn(reader
, 7);
1133 hr
= reader_parse_eq(reader
);
1134 if (FAILED(hr
)) return hr
;
1136 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1139 reader_skipn(reader
, 1);
1141 hr
= reader_parse_versionnum(reader
, &val
);
1142 if (FAILED(hr
)) return hr
;
1144 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1148 reader_skipn(reader
, 1);
1150 return reader_add_attr(reader
, NULL
, &name
, &val
);
1153 /* ([A-Za-z0-9._] | '-') */
1154 static inline BOOL
is_wchar_encname(WCHAR ch
)
1156 return ((ch
>= 'A' && ch
<= 'Z') ||
1157 (ch
>= 'a' && ch
<= 'z') ||
1158 (ch
>= '0' && ch
<= '9') ||
1159 (ch
== '.') || (ch
== '_') ||
1163 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
1164 static HRESULT
reader_parse_encname(xmlreader
*reader
, strval
*val
)
1166 WCHAR
*start
= reader_get_ptr(reader
), *ptr
;
1170 if ((*start
< 'A' || *start
> 'Z') && (*start
< 'a' || *start
> 'z'))
1171 return WC_E_ENCNAME
;
1173 val
->start
= reader_get_cur(reader
);
1176 while (is_wchar_encname(*++ptr
))
1180 enc
= parse_encoding_name(start
, len
);
1181 TRACE("encoding name %s\n", debugstr_wn(start
, len
));
1185 if (enc
== XmlEncoding_Unknown
)
1186 return WC_E_ENCNAME
;
1188 /* skip encoding name */
1189 reader_skipn(reader
, len
);
1193 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
1194 static HRESULT
reader_parse_encdecl(xmlreader
*reader
)
1196 static const WCHAR encodingW
[] = {'e','n','c','o','d','i','n','g',0};
1200 if (!reader_skipspaces(reader
)) return S_FALSE
;
1202 if (reader_cmp(reader
, encodingW
)) return S_FALSE
;
1203 name
.str
= reader_get_ptr(reader
);
1204 name
.start
= reader_get_cur(reader
);
1206 /* skip 'encoding' */
1207 reader_skipn(reader
, 8);
1209 hr
= reader_parse_eq(reader
);
1210 if (FAILED(hr
)) return hr
;
1212 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1215 reader_skipn(reader
, 1);
1217 hr
= reader_parse_encname(reader
, &val
);
1218 if (FAILED(hr
)) return hr
;
1220 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1224 reader_skipn(reader
, 1);
1226 return reader_add_attr(reader
, NULL
, &name
, &val
);
1229 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
1230 static HRESULT
reader_parse_sddecl(xmlreader
*reader
)
1232 static const WCHAR standaloneW
[] = {'s','t','a','n','d','a','l','o','n','e',0};
1233 static const WCHAR yesW
[] = {'y','e','s',0};
1234 static const WCHAR noW
[] = {'n','o',0};
1239 if (!reader_skipspaces(reader
)) return S_FALSE
;
1241 if (reader_cmp(reader
, standaloneW
)) return S_FALSE
;
1242 reader_init_strvalue(reader_get_cur(reader
), 10, &name
);
1243 /* skip 'standalone' */
1244 reader_skipn(reader
, 10);
1246 hr
= reader_parse_eq(reader
);
1247 if (FAILED(hr
)) return hr
;
1249 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1252 reader_skipn(reader
, 1);
1254 if (reader_cmp(reader
, yesW
) && reader_cmp(reader
, noW
))
1255 return WC_E_XMLDECL
;
1257 start
= reader_get_cur(reader
);
1258 /* skip 'yes'|'no' */
1259 reader_skipn(reader
, reader_cmp(reader
, yesW
) ? 2 : 3);
1260 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, &val
);
1261 TRACE("standalone=%s\n", debug_strval(reader
, &val
));
1263 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1266 reader_skipn(reader
, 1);
1268 return reader_add_attr(reader
, NULL
, &name
, &val
);
1271 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
1272 static HRESULT
reader_parse_xmldecl(xmlreader
*reader
)
1274 static const WCHAR xmldeclW
[] = {'<','?','x','m','l',' ',0};
1275 static const WCHAR declcloseW
[] = {'?','>',0};
1278 /* check if we have "<?xml " */
1279 if (reader_cmp(reader
, xmldeclW
)) return S_FALSE
;
1281 reader_skipn(reader
, 5);
1282 hr
= reader_parse_versioninfo(reader
);
1286 hr
= reader_parse_encdecl(reader
);
1290 hr
= reader_parse_sddecl(reader
);
1294 reader_skipspaces(reader
);
1295 if (reader_cmp(reader
, declcloseW
)) return WC_E_XMLDECL
;
1296 reader_skipn(reader
, 2);
1298 reader_inc_depth(reader
);
1299 reader
->nodetype
= XmlNodeType_XmlDeclaration
;
1300 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1301 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1302 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1307 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1308 static HRESULT
reader_parse_comment(xmlreader
*reader
)
1313 if (reader
->resumestate
== XmlReadResumeState_Comment
)
1315 start
= reader
->resume
[XmlReadResume_Body
];
1316 ptr
= reader_get_ptr(reader
);
1321 reader_skipn(reader
, 4);
1322 reader_shrink(reader
);
1323 ptr
= reader_get_ptr(reader
);
1324 start
= reader_get_cur(reader
);
1325 reader
->nodetype
= XmlNodeType_Comment
;
1326 reader
->resume
[XmlReadResume_Body
] = start
;
1327 reader
->resumestate
= XmlReadResumeState_Comment
;
1328 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
1329 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
1330 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
1333 /* will exit when there's no more data, it won't attempt to
1334 read more from stream */
1345 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, &value
);
1346 TRACE("%s\n", debug_strval(reader
, &value
));
1348 /* skip rest of markup '->' */
1349 reader_skipn(reader
, 3);
1351 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1352 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1353 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1354 reader
->resume
[XmlReadResume_Body
] = 0;
1355 reader
->resumestate
= XmlReadResumeState_Initial
;
1359 return WC_E_COMMENT
;
1363 reader_skipn(reader
, 1);
1370 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1371 static inline BOOL
is_char(WCHAR ch
)
1373 return (ch
== '\t') || (ch
== '\r') || (ch
== '\n') ||
1374 (ch
>= 0x20 && ch
<= 0xd7ff) ||
1375 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1376 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1377 (ch
>= 0xe000 && ch
<= 0xfffd);
1380 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1381 static inline BOOL
is_pubchar(WCHAR ch
)
1383 return (ch
== ' ') ||
1384 (ch
>= 'a' && ch
<= 'z') ||
1385 (ch
>= 'A' && ch
<= 'Z') ||
1386 (ch
>= '0' && ch
<= '9') ||
1387 (ch
>= '-' && ch
<= ';') || /* '()*+,-./:; */
1388 (ch
== '=') || (ch
== '?') ||
1389 (ch
== '@') || (ch
== '!') ||
1390 (ch
>= '#' && ch
<= '%') || /* #$% */
1391 (ch
== '_') || (ch
== '\r') || (ch
== '\n');
1394 static inline BOOL
is_namestartchar(WCHAR ch
)
1396 return (ch
== ':') || (ch
>= 'A' && ch
<= 'Z') ||
1397 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1398 (ch
>= 0xc0 && ch
<= 0xd6) ||
1399 (ch
>= 0xd8 && ch
<= 0xf6) ||
1400 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1401 (ch
>= 0x370 && ch
<= 0x37d) ||
1402 (ch
>= 0x37f && ch
<= 0x1fff) ||
1403 (ch
>= 0x200c && ch
<= 0x200d) ||
1404 (ch
>= 0x2070 && ch
<= 0x218f) ||
1405 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1406 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1407 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1408 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1409 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1410 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1413 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1414 static inline BOOL
is_ncnamechar(WCHAR ch
)
1416 return (ch
>= 'A' && ch
<= 'Z') ||
1417 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1418 (ch
== '-') || (ch
== '.') ||
1419 (ch
>= '0' && ch
<= '9') ||
1421 (ch
>= 0xc0 && ch
<= 0xd6) ||
1422 (ch
>= 0xd8 && ch
<= 0xf6) ||
1423 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1424 (ch
>= 0x300 && ch
<= 0x36f) ||
1425 (ch
>= 0x370 && ch
<= 0x37d) ||
1426 (ch
>= 0x37f && ch
<= 0x1fff) ||
1427 (ch
>= 0x200c && ch
<= 0x200d) ||
1428 (ch
>= 0x203f && ch
<= 0x2040) ||
1429 (ch
>= 0x2070 && ch
<= 0x218f) ||
1430 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1431 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1432 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1433 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1434 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1435 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1438 static inline BOOL
is_namechar(WCHAR ch
)
1440 return (ch
== ':') || is_ncnamechar(ch
);
1443 static XmlNodeType
reader_get_nodetype(const xmlreader
*reader
)
1445 /* When we're on attribute always return attribute type, container node type is kept.
1446 Note that container is not necessarily an element, and attribute doesn't mean it's
1447 an attribute in XML spec terms. */
1448 return reader
->attr
? XmlNodeType_Attribute
: reader
->nodetype
;
1451 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
1452 [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
1453 [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
1454 [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
1455 [5] Name ::= NameStartChar (NameChar)* */
1456 static HRESULT
reader_parse_name(xmlreader
*reader
, strval
*name
)
1461 if (reader
->resume
[XmlReadResume_Name
])
1463 start
= reader
->resume
[XmlReadResume_Name
];
1464 ptr
= reader_get_ptr(reader
);
1468 ptr
= reader_get_ptr(reader
);
1469 start
= reader_get_cur(reader
);
1470 if (!is_namestartchar(*ptr
)) return WC_E_NAMECHARACTER
;
1473 while (is_namechar(*ptr
))
1475 reader_skipn(reader
, 1);
1476 ptr
= reader_get_ptr(reader
);
1479 if (is_reader_pending(reader
))
1481 reader
->resume
[XmlReadResume_Name
] = start
;
1485 reader
->resume
[XmlReadResume_Name
] = 0;
1487 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, name
);
1488 TRACE("name %s:%d\n", debug_strval(reader
, name
), name
->len
);
1493 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1494 static HRESULT
reader_parse_pitarget(xmlreader
*reader
, strval
*target
)
1496 static const WCHAR xmlW
[] = {'x','m','l'};
1497 static const strval xmlval
= { (WCHAR
*)xmlW
, 3 };
1503 hr
= reader_parse_name(reader
, &name
);
1504 if (FAILED(hr
)) return is_reader_pending(reader
) ? E_PENDING
: WC_E_PI
;
1506 /* now that we got name check for illegal content */
1507 if (strval_eq(reader
, &name
, &xmlval
))
1508 return WC_E_LEADINGXML
;
1510 /* PITarget can't be a qualified name */
1511 ptr
= reader_get_strptr(reader
, &name
);
1512 for (i
= 0; i
< name
.len
; i
++)
1514 return i
? NC_E_NAMECOLON
: WC_E_PI
;
1516 TRACE("pitarget %s:%d\n", debug_strval(reader
, &name
), name
.len
);
1521 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1522 static HRESULT
reader_parse_pi(xmlreader
*reader
)
1529 switch (reader
->resumestate
)
1531 case XmlReadResumeState_Initial
:
1533 reader_skipn(reader
, 2);
1534 reader_shrink(reader
);
1535 reader
->resumestate
= XmlReadResumeState_PITarget
;
1536 case XmlReadResumeState_PITarget
:
1537 hr
= reader_parse_pitarget(reader
, &target
);
1538 if (FAILED(hr
)) return hr
;
1539 reader_set_strvalue(reader
, StringValue_LocalName
, &target
);
1540 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
1541 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1542 reader
->resumestate
= XmlReadResumeState_PIBody
;
1543 reader
->resume
[XmlReadResume_Body
] = reader_get_cur(reader
);
1548 start
= reader
->resume
[XmlReadResume_Body
];
1549 ptr
= reader_get_ptr(reader
);
1556 UINT cur
= reader_get_cur(reader
);
1559 /* strip all leading whitespace chars */
1562 ptr
= reader_get_ptr2(reader
, start
);
1563 if (!is_wchar_space(*ptr
)) break;
1567 reader_init_strvalue(start
, cur
-start
, &value
);
1570 reader_skipn(reader
, 2);
1571 TRACE("%s\n", debug_strval(reader
, &value
));
1572 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1573 reader
->resumestate
= XmlReadResumeState_Initial
;
1574 reader
->resume
[XmlReadResume_Body
] = 0;
1575 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1580 reader_skipn(reader
, 1);
1581 ptr
= reader_get_ptr(reader
);
1587 /* This one is used to parse significant whitespace nodes, like in Misc production */
1588 static HRESULT
reader_parse_whitespace(xmlreader
*reader
)
1590 switch (reader
->resumestate
)
1592 case XmlReadResumeState_Initial
:
1593 reader_shrink(reader
);
1594 reader
->resumestate
= XmlReadResumeState_Whitespace
;
1595 reader
->resume
[XmlReadResume_Body
] = reader_get_cur(reader
);
1596 reader
->nodetype
= XmlNodeType_Whitespace
;
1597 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1598 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1599 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1601 case XmlReadResumeState_Whitespace
:
1606 reader_skipspaces(reader
);
1607 if (is_reader_pending(reader
)) return S_OK
;
1609 start
= reader
->resume
[XmlReadResume_Body
];
1610 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, &value
);
1611 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1612 TRACE("%s\n", debug_strval(reader
, &value
));
1613 reader
->resumestate
= XmlReadResumeState_Initial
;
1622 /* [27] Misc ::= Comment | PI | S */
1623 static HRESULT
reader_parse_misc(xmlreader
*reader
)
1625 HRESULT hr
= S_FALSE
;
1627 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1629 hr
= reader_more(reader
);
1630 if (FAILED(hr
)) return hr
;
1632 /* finish current node */
1633 switch (reader
->resumestate
)
1635 case XmlReadResumeState_PITarget
:
1636 case XmlReadResumeState_PIBody
:
1637 return reader_parse_pi(reader
);
1638 case XmlReadResumeState_Comment
:
1639 return reader_parse_comment(reader
);
1640 case XmlReadResumeState_Whitespace
:
1641 return reader_parse_whitespace(reader
);
1643 ERR("unknown resume state %d\n", reader
->resumestate
);
1649 const WCHAR
*cur
= reader_get_ptr(reader
);
1651 if (is_wchar_space(*cur
))
1652 hr
= reader_parse_whitespace(reader
);
1653 else if (!reader_cmp(reader
, commentW
))
1654 hr
= reader_parse_comment(reader
);
1655 else if (!reader_cmp(reader
, piW
))
1656 hr
= reader_parse_pi(reader
);
1660 if (hr
!= S_FALSE
) return hr
;
1666 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1667 static HRESULT
reader_parse_sys_literal(xmlreader
*reader
, strval
*literal
)
1669 WCHAR
*cur
= reader_get_ptr(reader
), quote
;
1672 if (*cur
!= '"' && *cur
!= '\'') return WC_E_QUOTE
;
1675 reader_skipn(reader
, 1);
1677 cur
= reader_get_ptr(reader
);
1678 start
= reader_get_cur(reader
);
1679 while (is_char(*cur
) && *cur
!= quote
)
1681 reader_skipn(reader
, 1);
1682 cur
= reader_get_ptr(reader
);
1684 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, literal
);
1685 if (*cur
== quote
) reader_skipn(reader
, 1);
1687 TRACE("%s\n", debug_strval(reader
, literal
));
1691 /* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1692 [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1693 static HRESULT
reader_parse_pub_literal(xmlreader
*reader
, strval
*literal
)
1695 WCHAR
*cur
= reader_get_ptr(reader
), quote
;
1698 if (*cur
!= '"' && *cur
!= '\'') return WC_E_QUOTE
;
1701 reader_skipn(reader
, 1);
1703 start
= reader_get_cur(reader
);
1704 cur
= reader_get_ptr(reader
);
1705 while (is_pubchar(*cur
) && *cur
!= quote
)
1707 reader_skipn(reader
, 1);
1708 cur
= reader_get_ptr(reader
);
1710 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, literal
);
1711 if (*cur
== quote
) reader_skipn(reader
, 1);
1713 TRACE("%s\n", debug_strval(reader
, literal
));
1717 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1718 static HRESULT
reader_parse_externalid(xmlreader
*reader
)
1720 static WCHAR systemW
[] = {'S','Y','S','T','E','M',0};
1721 static WCHAR publicW
[] = {'P','U','B','L','I','C',0};
1726 if (!reader_cmp(reader
, publicW
)) {
1730 reader_skipn(reader
, 6);
1731 cnt
= reader_skipspaces(reader
);
1732 if (!cnt
) return WC_E_WHITESPACE
;
1734 hr
= reader_parse_pub_literal(reader
, &pub
);
1735 if (FAILED(hr
)) return hr
;
1737 reader_init_cstrvalue(publicW
, strlenW(publicW
), &name
);
1738 hr
= reader_add_attr(reader
, NULL
, &name
, &pub
);
1739 if (FAILED(hr
)) return hr
;
1741 cnt
= reader_skipspaces(reader
);
1742 if (!cnt
) return S_OK
;
1744 /* optional system id */
1745 hr
= reader_parse_sys_literal(reader
, &sys
);
1746 if (FAILED(hr
)) return S_OK
;
1748 reader_init_cstrvalue(systemW
, strlenW(systemW
), &name
);
1749 hr
= reader_add_attr(reader
, NULL
, &name
, &sys
);
1750 if (FAILED(hr
)) return hr
;
1753 } else if (!reader_cmp(reader
, systemW
)) {
1755 reader_skipn(reader
, 6);
1756 cnt
= reader_skipspaces(reader
);
1757 if (!cnt
) return WC_E_WHITESPACE
;
1759 hr
= reader_parse_sys_literal(reader
, &sys
);
1760 if (FAILED(hr
)) return hr
;
1762 reader_init_cstrvalue(systemW
, strlenW(systemW
), &name
);
1763 return reader_add_attr(reader
, NULL
, &name
, &sys
);
1769 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1770 static HRESULT
reader_parse_dtd(xmlreader
*reader
)
1772 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',0};
1777 /* check if we have "<!DOCTYPE" */
1778 if (reader_cmp(reader
, doctypeW
)) return S_FALSE
;
1779 reader_shrink(reader
);
1781 /* DTD processing is not allowed by default */
1782 if (reader
->dtdmode
== DtdProcessing_Prohibit
) return WC_E_DTDPROHIBITED
;
1784 reader_skipn(reader
, 9);
1785 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1788 hr
= reader_parse_name(reader
, &name
);
1789 if (FAILED(hr
)) return WC_E_DECLDOCTYPE
;
1791 reader_skipspaces(reader
);
1793 hr
= reader_parse_externalid(reader
);
1794 if (FAILED(hr
)) return hr
;
1796 reader_skipspaces(reader
);
1798 cur
= reader_get_ptr(reader
);
1801 FIXME("internal subset parsing not implemented\n");
1806 reader_skipn(reader
, 1);
1808 reader
->nodetype
= XmlNodeType_DocumentType
;
1809 reader_set_strvalue(reader
, StringValue_LocalName
, &name
);
1810 reader_set_strvalue(reader
, StringValue_QualifiedName
, &name
);
1815 /* [11 NS] LocalPart ::= NCName */
1816 static HRESULT
reader_parse_local(xmlreader
*reader
, strval
*local
)
1821 if (reader
->resume
[XmlReadResume_Local
])
1823 start
= reader
->resume
[XmlReadResume_Local
];
1824 ptr
= reader_get_ptr(reader
);
1828 ptr
= reader_get_ptr(reader
);
1829 start
= reader_get_cur(reader
);
1832 while (is_ncnamechar(*ptr
))
1834 reader_skipn(reader
, 1);
1835 ptr
= reader_get_ptr(reader
);
1838 if (is_reader_pending(reader
))
1840 reader
->resume
[XmlReadResume_Local
] = start
;
1844 reader
->resume
[XmlReadResume_Local
] = 0;
1846 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, local
);
1851 /* [7 NS] QName ::= PrefixedName | UnprefixedName
1852 [8 NS] PrefixedName ::= Prefix ':' LocalPart
1853 [9 NS] UnprefixedName ::= LocalPart
1854 [10 NS] Prefix ::= NCName */
1855 static HRESULT
reader_parse_qname(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
)
1861 if (reader
->resume
[XmlReadResume_Name
])
1863 start
= reader
->resume
[XmlReadResume_Name
];
1864 ptr
= reader_get_ptr(reader
);
1868 ptr
= reader_get_ptr(reader
);
1869 start
= reader_get_cur(reader
);
1870 reader
->resume
[XmlReadResume_Name
] = start
;
1871 if (!is_ncnamechar(*ptr
)) return NC_E_QNAMECHARACTER
;
1874 if (reader
->resume
[XmlReadResume_Local
])
1876 hr
= reader_parse_local(reader
, local
);
1877 if (FAILED(hr
)) return hr
;
1879 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
],
1880 local
->start
- reader
->resume
[XmlReadResume_Name
] - 1,
1885 /* skip prefix part */
1886 while (is_ncnamechar(*ptr
))
1888 reader_skipn(reader
, 1);
1889 ptr
= reader_get_ptr(reader
);
1892 if (is_reader_pending(reader
)) return E_PENDING
;
1894 /* got a qualified name */
1897 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, prefix
);
1900 reader_skipn(reader
, 1);
1901 hr
= reader_parse_local(reader
, local
);
1902 if (FAILED(hr
)) return hr
;
1906 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
], reader_get_cur(reader
)-reader
->resume
[XmlReadResume_Name
], local
);
1907 reader_init_strvalue(0, 0, prefix
);
1912 TRACE("qname %s:%s\n", debug_strval(reader
, prefix
), debug_strval(reader
, local
));
1914 TRACE("ncname %s\n", debug_strval(reader
, local
));
1916 reader_init_strvalue(prefix
->len
? prefix
->start
: local
->start
,
1918 (prefix
->len
? prefix
->len
+ 1 : 0) + local
->len
,
1921 reader
->resume
[XmlReadResume_Name
] = 0;
1922 reader
->resume
[XmlReadResume_Local
] = 0;
1927 /* Applies normalization rules to a single char, used for attribute values.
1929 Rules include 2 steps:
1931 1) replacing \r\n with a single \n;
1932 2) replacing all whitespace chars with ' '.
1935 static void reader_normalize_space(xmlreader
*reader
, WCHAR
*ptr
)
1937 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
1939 if (!is_wchar_space(*ptr
)) return;
1941 if (*ptr
== '\r' && *(ptr
+1) == '\n')
1943 int len
= buffer
->written
- ((char*)ptr
- buffer
->data
) - 2*sizeof(WCHAR
);
1944 memmove(ptr
+1, ptr
+2, len
);
1949 static WCHAR
get_predefined_entity(const xmlreader
*reader
, const strval
*name
)
1951 static const WCHAR entltW
[] = {'l','t'};
1952 static const WCHAR entgtW
[] = {'g','t'};
1953 static const WCHAR entampW
[] = {'a','m','p'};
1954 static const WCHAR entaposW
[] = {'a','p','o','s'};
1955 static const WCHAR entquotW
[] = {'q','u','o','t'};
1956 static const strval lt
= { (WCHAR
*)entltW
, 2 };
1957 static const strval gt
= { (WCHAR
*)entgtW
, 2 };
1958 static const strval amp
= { (WCHAR
*)entampW
, 3 };
1959 static const strval apos
= { (WCHAR
*)entaposW
, 4 };
1960 static const strval quot
= { (WCHAR
*)entquotW
, 4 };
1961 WCHAR
*str
= reader_get_strptr(reader
, name
);
1966 if (strval_eq(reader
, name
, <
)) return '<';
1969 if (strval_eq(reader
, name
, >
)) return '>';
1972 if (strval_eq(reader
, name
, &
))
1974 else if (strval_eq(reader
, name
, &apos
))
1978 if (strval_eq(reader
, name
, "
)) return '\"';
1987 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1988 [67] Reference ::= EntityRef | CharRef
1989 [68] EntityRef ::= '&' Name ';' */
1990 static HRESULT
reader_parse_reference(xmlreader
*reader
)
1992 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
1993 WCHAR
*start
= reader_get_ptr(reader
), *ptr
;
1994 UINT cur
= reader_get_cur(reader
);
1999 reader_skipn(reader
, 1);
2000 ptr
= reader_get_ptr(reader
);
2004 reader_skipn(reader
, 1);
2005 ptr
= reader_get_ptr(reader
);
2007 /* hex char or decimal */
2010 reader_skipn(reader
, 1);
2011 ptr
= reader_get_ptr(reader
);
2015 if ((*ptr
>= '0' && *ptr
<= '9'))
2016 ch
= ch
*16 + *ptr
- '0';
2017 else if ((*ptr
>= 'a' && *ptr
<= 'f'))
2018 ch
= ch
*16 + *ptr
- 'a' + 10;
2019 else if ((*ptr
>= 'A' && *ptr
<= 'F'))
2020 ch
= ch
*16 + *ptr
- 'A' + 10;
2022 return ch
? WC_E_SEMICOLON
: WC_E_HEXDIGIT
;
2023 reader_skipn(reader
, 1);
2024 ptr
= reader_get_ptr(reader
);
2031 if ((*ptr
>= '0' && *ptr
<= '9'))
2033 ch
= ch
*10 + *ptr
- '0';
2034 reader_skipn(reader
, 1);
2035 ptr
= reader_get_ptr(reader
);
2038 return ch
? WC_E_SEMICOLON
: WC_E_DIGIT
;
2042 if (!is_char(ch
)) return WC_E_XMLCHARACTER
;
2045 if (is_wchar_space(ch
)) ch
= ' ';
2047 len
= buffer
->written
- ((char*)ptr
- buffer
->data
) - sizeof(WCHAR
);
2048 memmove(start
+1, ptr
+1, len
);
2049 buffer
->cur
= cur
+ 1;
2058 hr
= reader_parse_name(reader
, &name
);
2059 if (FAILED(hr
)) return hr
;
2061 ptr
= reader_get_ptr(reader
);
2062 if (*ptr
!= ';') return WC_E_SEMICOLON
;
2064 /* predefined entities resolve to a single character */
2065 ch
= get_predefined_entity(reader
, &name
);
2068 len
= buffer
->written
- ((char*)ptr
- buffer
->data
) - sizeof(WCHAR
);
2069 memmove(start
+1, ptr
+1, len
);
2070 buffer
->cur
= cur
+ 1;
2076 FIXME("undeclared entity %s\n", debug_strval(reader
, &name
));
2077 return WC_E_UNDECLAREDENTITY
;
2085 /* [10 NS] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" */
2086 static HRESULT
reader_parse_attvalue(xmlreader
*reader
, strval
*value
)
2091 ptr
= reader_get_ptr(reader
);
2093 /* skip opening quote */
2095 if (quote
!= '\"' && quote
!= '\'') return WC_E_QUOTE
;
2096 reader_skipn(reader
, 1);
2098 ptr
= reader_get_ptr(reader
);
2099 start
= reader_get_cur(reader
);
2102 if (*ptr
== '<') return WC_E_LESSTHAN
;
2106 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, value
);
2107 /* skip closing quote */
2108 reader_skipn(reader
, 1);
2114 HRESULT hr
= reader_parse_reference(reader
);
2115 if (FAILED(hr
)) return hr
;
2119 reader_normalize_space(reader
, ptr
);
2120 reader_skipn(reader
, 1);
2122 ptr
= reader_get_ptr(reader
);
2128 /* [1 NS] NSAttName ::= PrefixedAttName | DefaultAttName
2129 [2 NS] PrefixedAttName ::= 'xmlns:' NCName
2130 [3 NS] DefaultAttName ::= 'xmlns'
2131 [15 NS] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue */
2132 static HRESULT
reader_parse_attribute(xmlreader
*reader
)
2134 strval prefix
, local
, qname
, value
;
2135 BOOL ns
= FALSE
, nsdef
= FALSE
;
2138 hr
= reader_parse_qname(reader
, &prefix
, &local
, &qname
);
2139 if (FAILED(hr
)) return hr
;
2141 if (strval_eq(reader
, &prefix
, &strval_xmlns
))
2144 if (strval_eq(reader
, &qname
, &strval_xmlns
))
2147 hr
= reader_parse_eq(reader
);
2148 if (FAILED(hr
)) return hr
;
2150 hr
= reader_parse_attvalue(reader
, &value
);
2151 if (FAILED(hr
)) return hr
;
2154 reader_push_ns(reader
, nsdef
? &strval_xmlns
: &local
, &value
, nsdef
);
2156 TRACE("%s=%s\n", debug_strval(reader
, &local
), debug_strval(reader
, &value
));
2157 return reader_add_attr(reader
, &prefix
, &local
, &value
);
2160 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
2161 [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
2162 static HRESULT
reader_parse_stag(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
, int *empty
)
2166 hr
= reader_parse_qname(reader
, prefix
, local
, qname
);
2167 if (FAILED(hr
)) return hr
;
2171 static const WCHAR endW
[] = {'/','>',0};
2173 reader_skipspaces(reader
);
2176 if ((*empty
= !reader_cmp(reader
, endW
)))
2179 reader_skipn(reader
, 2);
2180 reader
->is_empty_element
= TRUE
;
2181 reader
->empty_element
.prefix
= *prefix
;
2182 reader
->empty_element
.localname
= *local
;
2183 reader
->empty_element
.qname
= *qname
;
2184 reader_mark_ns_nodes(reader
, &reader
->empty_element
);
2188 /* got a start tag */
2189 if (!reader_cmp(reader
, gtW
))
2192 reader_skipn(reader
, 1);
2193 return reader_push_element(reader
, prefix
, local
, qname
);
2196 hr
= reader_parse_attribute(reader
);
2197 if (FAILED(hr
)) return hr
;
2203 /* [39] element ::= EmptyElemTag | STag content ETag */
2204 static HRESULT
reader_parse_element(xmlreader
*reader
)
2208 switch (reader
->resumestate
)
2210 case XmlReadResumeState_Initial
:
2211 /* check if we are really on element */
2212 if (reader_cmp(reader
, ltW
)) return S_FALSE
;
2215 reader_skipn(reader
, 1);
2217 reader_shrink(reader
);
2218 reader
->resumestate
= XmlReadResumeState_STag
;
2219 case XmlReadResumeState_STag
:
2221 strval qname
, prefix
, local
;
2224 /* this handles empty elements too */
2225 hr
= reader_parse_stag(reader
, &prefix
, &local
, &qname
, &empty
);
2226 if (FAILED(hr
)) return hr
;
2228 /* FIXME: need to check for defined namespace to reject invalid prefix */
2230 /* if we got empty element and stack is empty go straight to Misc */
2231 if (empty
&& list_empty(&reader
->elements
))
2232 reader
->instate
= XmlReadInState_MiscEnd
;
2234 reader
->instate
= XmlReadInState_Content
;
2236 reader
->nodetype
= XmlNodeType_Element
;
2237 reader
->resumestate
= XmlReadResumeState_Initial
;
2238 reader_set_strvalue(reader
, StringValue_Prefix
, &prefix
);
2239 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
2240 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
2250 /* [13 NS] ETag ::= '</' QName S? '>' */
2251 static HRESULT
reader_parse_endtag(xmlreader
*reader
)
2253 strval prefix
, local
, qname
;
2254 struct element
*elem
;
2258 reader_skipn(reader
, 2);
2260 hr
= reader_parse_qname(reader
, &prefix
, &local
, &qname
);
2261 if (FAILED(hr
)) return hr
;
2263 reader_skipspaces(reader
);
2265 if (reader_cmp(reader
, gtW
)) return WC_E_GREATERTHAN
;
2268 reader_skipn(reader
, 1);
2270 /* Element stack should never be empty at this point, cause we shouldn't get to
2271 content parsing if it's empty. */
2272 elem
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
2273 if (!strval_eq(reader
, &elem
->qname
, &qname
)) return WC_E_ELEMENTMATCH
;
2275 reader
->nodetype
= XmlNodeType_EndElement
;
2276 reader_set_strvalue(reader
, StringValue_Prefix
, &prefix
);
2277 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
2278 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
2283 /* [18] CDSect ::= CDStart CData CDEnd
2284 [19] CDStart ::= '<![CDATA['
2285 [20] CData ::= (Char* - (Char* ']]>' Char*))
2286 [21] CDEnd ::= ']]>' */
2287 static HRESULT
reader_parse_cdata(xmlreader
*reader
)
2292 if (reader
->resumestate
== XmlReadResumeState_CDATA
)
2294 start
= reader
->resume
[XmlReadResume_Body
];
2295 ptr
= reader_get_ptr(reader
);
2299 /* skip markup '<![CDATA[' */
2300 reader_skipn(reader
, 9);
2301 reader_shrink(reader
);
2302 ptr
= reader_get_ptr(reader
);
2303 start
= reader_get_cur(reader
);
2304 reader
->nodetype
= XmlNodeType_CDATA
;
2305 reader
->resume
[XmlReadResume_Body
] = start
;
2306 reader
->resumestate
= XmlReadResumeState_CDATA
;
2307 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
2308 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
2309 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
2314 if (*ptr
== ']' && *(ptr
+1) == ']' && *(ptr
+2) == '>')
2318 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, &value
);
2321 reader_skipn(reader
, 3);
2322 TRACE("%s\n", debug_strval(reader
, &value
));
2324 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
2325 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
2326 reader_set_strvalue(reader
, StringValue_Value
, &value
);
2327 reader
->resume
[XmlReadResume_Body
] = 0;
2328 reader
->resumestate
= XmlReadResumeState_Initial
;
2333 /* Value normalization is not fully implemented, rules are:
2335 - single '\r' -> '\n';
2336 - sequence '\r\n' -> '\n', in this case value length changes;
2338 if (*ptr
== '\r') *ptr
= '\n';
2339 reader_skipn(reader
, 1);
2347 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
2348 static HRESULT
reader_parse_chardata(xmlreader
*reader
)
2353 if (reader
->resumestate
== XmlReadResumeState_CharData
)
2355 start
= reader
->resume
[XmlReadResume_Body
];
2356 ptr
= reader_get_ptr(reader
);
2360 reader_shrink(reader
);
2361 ptr
= reader_get_ptr(reader
);
2362 start
= reader_get_cur(reader
);
2363 /* There's no text */
2364 if (!*ptr
|| *ptr
== '<') return S_OK
;
2365 reader
->nodetype
= is_wchar_space(*ptr
) ? XmlNodeType_Whitespace
: XmlNodeType_Text
;
2366 reader
->resume
[XmlReadResume_Body
] = start
;
2367 reader
->resumestate
= XmlReadResumeState_CharData
;
2368 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
2369 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
2370 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
2375 static const WCHAR ampW
[] = {'&',0};
2377 /* CDATA closing sequence ']]>' is not allowed */
2378 if (ptr
[0] == ']' && ptr
[1] == ']' && ptr
[2] == '>')
2379 return WC_E_CDSECTEND
;
2381 /* Found next markup part */
2386 reader_init_strvalue(start
, reader_get_cur(reader
)-start
, &value
);
2387 reader_set_strvalue(reader
, StringValue_Value
, &value
);
2388 reader
->resume
[XmlReadResume_Body
] = 0;
2389 reader
->resumestate
= XmlReadResumeState_Initial
;
2393 /* this covers a case when text has leading whitespace chars */
2394 if (!is_wchar_space(*ptr
)) reader
->nodetype
= XmlNodeType_Text
;
2396 if (!reader_cmp(reader
, ampW
))
2397 reader_parse_reference(reader
);
2399 reader_skipn(reader
, 1);
2401 ptr
= reader_get_ptr(reader
);
2407 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
2408 static HRESULT
reader_parse_content(xmlreader
*reader
)
2410 static const WCHAR cdstartW
[] = {'<','!','[','C','D','A','T','A','[',0};
2411 static const WCHAR etagW
[] = {'<','/',0};
2413 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
2415 switch (reader
->resumestate
)
2417 case XmlReadResumeState_CDATA
:
2418 return reader_parse_cdata(reader
);
2419 case XmlReadResumeState_Comment
:
2420 return reader_parse_comment(reader
);
2421 case XmlReadResumeState_PIBody
:
2422 case XmlReadResumeState_PITarget
:
2423 return reader_parse_pi(reader
);
2424 case XmlReadResumeState_CharData
:
2425 return reader_parse_chardata(reader
);
2427 ERR("unknown resume state %d\n", reader
->resumestate
);
2431 reader_shrink(reader
);
2433 /* handle end tag here, it indicates end of content as well */
2434 if (!reader_cmp(reader
, etagW
))
2435 return reader_parse_endtag(reader
);
2437 if (!reader_cmp(reader
, commentW
))
2438 return reader_parse_comment(reader
);
2440 if (!reader_cmp(reader
, piW
))
2441 return reader_parse_pi(reader
);
2443 if (!reader_cmp(reader
, cdstartW
))
2444 return reader_parse_cdata(reader
);
2446 if (!reader_cmp(reader
, ltW
))
2447 return reader_parse_element(reader
);
2449 /* what's left must be CharData */
2450 return reader_parse_chardata(reader
);
2453 static HRESULT
reader_parse_nextnode(xmlreader
*reader
)
2455 XmlNodeType nodetype
= reader_get_nodetype(reader
);
2458 if (!is_reader_pending(reader
))
2459 reader_clear_attrs(reader
);
2461 /* When moving from EndElement or empty element, pop its own namespace definitions */
2462 if (nodetype
== XmlNodeType_Element
&& reader
->is_empty_element
)
2463 reader_pop_ns_nodes(reader
, &reader
->empty_element
);
2464 else if (nodetype
== XmlNodeType_EndElement
)
2465 reader_pop_element(reader
);
2469 switch (reader
->instate
)
2471 /* if it's a first call for a new input we need to detect stream encoding */
2472 case XmlReadInState_Initial
:
2476 hr
= readerinput_growraw(reader
->input
);
2477 if (FAILED(hr
)) return hr
;
2479 /* try to detect encoding by BOM or data and set input code page */
2480 hr
= readerinput_detectencoding(reader
->input
, &enc
);
2481 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
2482 if (FAILED(hr
)) return hr
;
2484 /* always switch first time cause we have to put something in */
2485 readerinput_switchencoding(reader
->input
, enc
);
2487 /* parse xml declaration */
2488 hr
= reader_parse_xmldecl(reader
);
2489 if (FAILED(hr
)) return hr
;
2491 readerinput_shrinkraw(reader
->input
, -1);
2492 reader
->instate
= XmlReadInState_Misc_DTD
;
2493 if (hr
== S_OK
) return hr
;
2496 case XmlReadInState_Misc_DTD
:
2497 hr
= reader_parse_misc(reader
);
2498 if (FAILED(hr
)) return hr
;
2501 reader
->instate
= XmlReadInState_DTD
;
2505 case XmlReadInState_DTD
:
2506 hr
= reader_parse_dtd(reader
);
2507 if (FAILED(hr
)) return hr
;
2511 reader
->instate
= XmlReadInState_DTD_Misc
;
2515 reader
->instate
= XmlReadInState_Element
;
2517 case XmlReadInState_DTD_Misc
:
2518 hr
= reader_parse_misc(reader
);
2519 if (FAILED(hr
)) return hr
;
2522 reader
->instate
= XmlReadInState_Element
;
2526 case XmlReadInState_Element
:
2527 return reader_parse_element(reader
);
2528 case XmlReadInState_Content
:
2529 return reader_parse_content(reader
);
2530 case XmlReadInState_MiscEnd
:
2531 hr
= reader_parse_misc(reader
);
2532 if (FAILED(hr
)) return hr
;
2535 reader
->instate
= XmlReadInState_Eof
;
2537 case XmlReadInState_Eof
:
2540 FIXME("internal state %d not handled\n", reader
->instate
);
2548 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
2550 xmlreader
*This
= impl_from_IXmlReader(iface
);
2552 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2554 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
2555 IsEqualGUID(riid
, &IID_IXmlReader
))
2561 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
2563 return E_NOINTERFACE
;
2566 IXmlReader_AddRef(iface
);
2571 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
2573 xmlreader
*This
= impl_from_IXmlReader(iface
);
2574 ULONG ref
= InterlockedIncrement(&This
->ref
);
2575 TRACE("(%p)->(%d)\n", This
, ref
);
2579 static void reader_clear_ns(xmlreader
*reader
)
2581 struct ns
*ns
, *ns2
;
2583 LIST_FOR_EACH_ENTRY_SAFE(ns
, ns2
, &reader
->ns
, struct ns
, entry
) {
2584 reader_free_strvalued(reader
, &ns
->prefix
);
2585 reader_free_strvalued(reader
, &ns
->uri
);
2586 reader_free(reader
, ns
);
2589 LIST_FOR_EACH_ENTRY_SAFE(ns
, ns2
, &reader
->nsdef
, struct ns
, entry
) {
2590 reader_free_strvalued(reader
, &ns
->uri
);
2591 reader_free(reader
, ns
);
2595 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
2597 xmlreader
*This
= impl_from_IXmlReader(iface
);
2598 LONG ref
= InterlockedDecrement(&This
->ref
);
2600 TRACE("(%p)->(%d)\n", This
, ref
);
2604 IMalloc
*imalloc
= This
->imalloc
;
2605 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2606 if (This
->resolver
) IXmlResolver_Release(This
->resolver
);
2607 if (This
->mlang
) IUnknown_Release(This
->mlang
);
2608 reader_clear_attrs(This
);
2609 reader_clear_ns(This
);
2610 reader_clear_elements(This
);
2611 reader_free_strvalues(This
);
2612 reader_free(This
, This
);
2613 if (imalloc
) IMalloc_Release(imalloc
);
2619 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
2621 xmlreader
*This
= impl_from_IXmlReader(iface
);
2622 IXmlReaderInput
*readerinput
;
2625 TRACE("(%p)->(%p)\n", This
, input
);
2629 readerinput_release_stream(This
->input
);
2630 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2634 This
->line
= This
->pos
= 0;
2635 reader_clear_elements(This
);
2637 This
->resumestate
= XmlReadResumeState_Initial
;
2638 memset(This
->resume
, 0, sizeof(This
->resume
));
2640 /* just reset current input */
2643 This
->state
= XmlReadState_Initial
;
2647 /* now try IXmlReaderInput, ISequentialStream, IStream */
2648 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&readerinput
);
2651 if (readerinput
->lpVtbl
== &xmlreaderinputvtbl
)
2652 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2655 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2656 readerinput
, readerinput
->lpVtbl
);
2657 IUnknown_Release(readerinput
);
2663 if (hr
!= S_OK
|| !readerinput
)
2665 /* create IXmlReaderInput basing on supplied interface */
2666 hr
= CreateXmlReaderInputWithEncodingName(input
,
2667 This
->imalloc
, NULL
, FALSE
, NULL
, &readerinput
);
2668 if (hr
!= S_OK
) return hr
;
2669 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2672 /* set stream for supplied IXmlReaderInput */
2673 hr
= readerinput_query_for_stream(This
->input
);
2676 This
->state
= XmlReadState_Initial
;
2677 This
->instate
= XmlReadInState_Initial
;
2683 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
2685 xmlreader
*This
= impl_from_IXmlReader(iface
);
2687 TRACE("(%p)->(%s %p)\n", This
, debugstr_reader_prop(property
), value
);
2689 if (!value
) return E_INVALIDARG
;
2693 case XmlReaderProperty_MultiLanguage
:
2694 *value
= (LONG_PTR
)This
->mlang
;
2696 IUnknown_AddRef(This
->mlang
);
2698 case XmlReaderProperty_XmlResolver
:
2699 *value
= (LONG_PTR
)This
->resolver
;
2701 IXmlResolver_AddRef(This
->resolver
);
2703 case XmlReaderProperty_DtdProcessing
:
2704 *value
= This
->dtdmode
;
2706 case XmlReaderProperty_ReadState
:
2707 *value
= This
->state
;
2710 FIXME("Unimplemented property (%u)\n", property
);
2717 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
2719 xmlreader
*This
= impl_from_IXmlReader(iface
);
2721 TRACE("(%p)->(%s 0x%lx)\n", This
, debugstr_reader_prop(property
), value
);
2725 case XmlReaderProperty_MultiLanguage
:
2727 IUnknown_Release(This
->mlang
);
2728 This
->mlang
= (IUnknown
*)value
;
2730 IUnknown_AddRef(This
->mlang
);
2732 FIXME("Ignoring MultiLanguage %p\n", This
->mlang
);
2734 case XmlReaderProperty_XmlResolver
:
2736 IXmlResolver_Release(This
->resolver
);
2737 This
->resolver
= (IXmlResolver
*)value
;
2739 IXmlResolver_AddRef(This
->resolver
);
2741 case XmlReaderProperty_DtdProcessing
:
2742 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
2743 This
->dtdmode
= value
;
2745 case XmlReaderProperty_MaxElementDepth
:
2746 FIXME("Ignoring MaxElementDepth %ld\n", value
);
2749 FIXME("Unimplemented property (%u)\n", property
);
2756 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*nodetype
)
2758 xmlreader
*This
= impl_from_IXmlReader(iface
);
2759 XmlNodeType oldtype
= This
->nodetype
;
2762 TRACE("(%p)->(%p)\n", This
, nodetype
);
2764 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
2766 hr
= reader_parse_nextnode(This
);
2767 if (oldtype
== XmlNodeType_None
&& This
->nodetype
!= oldtype
)
2768 This
->state
= XmlReadState_Interactive
;
2771 TRACE("node type %s\n", debugstr_nodetype(This
->nodetype
));
2773 *nodetype
= This
->nodetype
;
2779 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
2781 xmlreader
*This
= impl_from_IXmlReader(iface
);
2783 TRACE("(%p)->(%p)\n", This
, node_type
);
2786 return E_INVALIDARG
;
2788 *node_type
= reader_get_nodetype(This
);
2789 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
2792 static HRESULT
reader_move_to_first_attribute(xmlreader
*reader
)
2794 if (!reader
->attr_count
)
2797 reader
->attr
= LIST_ENTRY(list_head(&reader
->attrs
), struct attribute
, entry
);
2798 reader_set_strvalue(reader
, StringValue_Prefix
, &reader
->attr
->prefix
);
2799 reader_set_strvalue(reader
, StringValue_LocalName
, &reader
->attr
->localname
);
2800 reader_set_strvalue(reader
, StringValue_Value
, &reader
->attr
->value
);
2805 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
2807 xmlreader
*This
= impl_from_IXmlReader(iface
);
2809 TRACE("(%p)\n", This
);
2811 return reader_move_to_first_attribute(This
);
2814 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
2816 xmlreader
*This
= impl_from_IXmlReader(iface
);
2817 const struct list
*next
;
2819 TRACE("(%p)\n", This
);
2821 if (!This
->attr_count
) return S_FALSE
;
2824 return reader_move_to_first_attribute(This
);
2826 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
2829 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
2830 reader_set_strvalue(This
, StringValue_Prefix
, &This
->attr
->prefix
);
2831 reader_set_strvalue(This
, StringValue_LocalName
, &This
->attr
->localname
);
2832 reader_set_strvalue(This
, StringValue_Value
, &This
->attr
->value
);
2835 return next
? S_OK
: S_FALSE
;
2838 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
2840 LPCWSTR namespaceUri
)
2842 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
2846 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
2848 xmlreader
*This
= impl_from_IXmlReader(iface
);
2850 TRACE("(%p)\n", This
);
2852 if (!This
->attr_count
) return S_FALSE
;
2855 /* FIXME: support other node types with 'attributes' like DTD */
2856 if (This
->is_empty_element
) {
2857 reader_set_strvalue(This
, StringValue_LocalName
, &This
->empty_element
.localname
);
2858 reader_set_strvalue(This
, StringValue_QualifiedName
, &This
->empty_element
.qname
);
2861 struct element
*element
= LIST_ENTRY(list_head(&This
->elements
), struct element
, entry
);
2863 reader_set_strvalue(This
, StringValue_LocalName
, &element
->localname
);
2864 reader_set_strvalue(This
, StringValue_QualifiedName
, &element
->qname
);
2871 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2873 xmlreader
*This
= impl_from_IXmlReader(iface
);
2875 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2876 *name
= This
->strvalues
[StringValue_QualifiedName
].str
;
2877 if (len
) *len
= This
->strvalues
[StringValue_QualifiedName
].len
;
2881 static struct ns
*reader_lookup_ns(xmlreader
*reader
, const strval
*prefix
)
2883 struct list
*nslist
= prefix
? &reader
->ns
: &reader
->nsdef
;
2886 LIST_FOR_EACH_ENTRY_REV(ns
, nslist
, struct ns
, entry
) {
2887 if (strval_eq(reader
, prefix
, &ns
->prefix
))
2894 static struct ns
*reader_lookup_nsdef(xmlreader
*reader
)
2896 if (list_empty(&reader
->nsdef
))
2899 return LIST_ENTRY(list_head(&reader
->nsdef
), struct ns
, entry
);
2902 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
, const WCHAR
**uri
, UINT
*len
)
2904 xmlreader
*This
= impl_from_IXmlReader(iface
);
2905 const strval
*prefix
= &This
->strvalues
[StringValue_Prefix
];
2906 XmlNodeType nodetype
;
2910 TRACE("(%p %p %p)\n", iface
, uri
, len
);
2918 switch ((nodetype
= reader_get_nodetype(This
)))
2920 case XmlNodeType_Attribute
:
2922 static const WCHAR xmlns_uriW
[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
2923 '2','0','0','0','/','x','m','l','n','s','/',0};
2924 static const WCHAR xml_uriW
[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
2925 'X','M','L','/','1','9','9','8','/','n','a','m','e','s','p','a','c','e',0};
2926 const strval
*local
= &This
->strvalues
[StringValue_LocalName
];
2928 /* check for reserved prefixes first */
2929 if ((strval_eq(This
, prefix
, &strval_empty
) && strval_eq(This
, local
, &strval_xmlns
)) ||
2930 strval_eq(This
, prefix
, &strval_xmlns
))
2933 *len
= sizeof(xmlns_uriW
)/sizeof(xmlns_uriW
[0]) - 1;
2935 else if (strval_eq(This
, prefix
, &strval_xml
)) {
2937 *len
= sizeof(xml_uriW
)/sizeof(xml_uriW
[0]) - 1;
2941 ns
= reader_lookup_ns(This
, prefix
);
2953 case XmlNodeType_Element
:
2954 case XmlNodeType_EndElement
:
2956 ns
= reader_lookup_ns(This
, prefix
);
2958 /* pick top default ns if any */
2960 ns
= reader_lookup_nsdef(This
);
2973 FIXME("Unhandled node type %d\n", nodetype
);
2980 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2982 xmlreader
*This
= impl_from_IXmlReader(iface
);
2984 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2985 *name
= This
->strvalues
[StringValue_LocalName
].str
;
2986 if (len
) *len
= This
->strvalues
[StringValue_LocalName
].len
;
2990 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
, LPCWSTR
*prefix
, UINT
*len
)
2992 xmlreader
*This
= impl_from_IXmlReader(iface
);
2994 TRACE("(%p)->(%p %p)\n", This
, prefix
, len
);
2995 *prefix
= This
->strvalues
[StringValue_Prefix
].str
;
2996 if (len
) *len
= This
->strvalues
[StringValue_Prefix
].len
;
3000 static BOOL
is_namespace_definition(xmlreader
*reader
)
3002 const strval
*local
= &reader
->strvalues
[StringValue_LocalName
];
3003 const strval
*prefix
= &reader
->strvalues
[StringValue_Prefix
];
3005 if (reader_get_nodetype(reader
) != XmlNodeType_Attribute
)
3008 return ((strval_eq(reader
, prefix
, &strval_empty
) && strval_eq(reader
, local
, &strval_xmlns
)) ||
3009 strval_eq(reader
, prefix
, &strval_xmlns
));
3012 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
, const WCHAR
**value
, UINT
*len
)
3014 xmlreader
*reader
= impl_from_IXmlReader(iface
);
3015 strval
*val
= &reader
->strvalues
[StringValue_Value
];
3017 TRACE("(%p)->(%p %p)\n", reader
, value
, len
);
3021 if ((reader
->nodetype
== XmlNodeType_Comment
&& !val
->str
) || is_reader_pending(reader
))
3026 hr
= IXmlReader_Read(iface
, &type
);
3027 if (FAILED(hr
)) return hr
;
3029 /* return if still pending, partially read values are not reported */
3030 if (is_reader_pending(reader
)) return E_PENDING
;
3035 WCHAR
*ptr
= reader_alloc(reader
, (val
->len
+1)*sizeof(WCHAR
));
3036 if (!ptr
) return E_OUTOFMEMORY
;
3037 memcpy(ptr
, reader_get_strptr(reader
, val
), val
->len
*sizeof(WCHAR
));
3042 /* For namespace definition attributes return values from namespace list */
3043 if (is_namespace_definition(reader
)) {
3044 const strval
*local
= &reader
->strvalues
[StringValue_LocalName
];
3047 ns
= reader_lookup_ns(reader
, local
);
3049 ns
= reader_lookup_nsdef(reader
);
3055 if (len
) *len
= val
->len
;
3059 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
, WCHAR
*buffer
, UINT chunk_size
, UINT
*read
)
3061 xmlreader
*reader
= impl_from_IXmlReader(iface
);
3062 strval
*val
= &reader
->strvalues
[StringValue_Value
];
3065 TRACE("(%p)->(%p %u %p)\n", reader
, buffer
, chunk_size
, read
);
3067 /* Value is already allocated, chunked reads are not possible. */
3068 if (val
->str
) return S_FALSE
;
3072 len
= min(chunk_size
, val
->len
);
3073 memcpy(buffer
, reader_get_ptr2(reader
, val
->start
), len
);
3076 if (read
) *read
= len
;
3082 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
3084 UINT
*baseUri_length
)
3086 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
3090 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
3092 FIXME("(%p): stub\n", iface
);
3096 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
3098 xmlreader
*This
= impl_from_IXmlReader(iface
);
3099 TRACE("(%p)\n", This
);
3100 /* Empty elements are not placed in stack, it's stored as a global reader flag that makes sense
3101 when current node is start tag of an element */
3102 return (reader_get_nodetype(This
) == XmlNodeType_Element
) ? This
->is_empty_element
: FALSE
;
3105 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
3107 xmlreader
*This
= impl_from_IXmlReader(iface
);
3109 TRACE("(%p %p)\n", This
, lineNumber
);
3111 if (!lineNumber
) return E_INVALIDARG
;
3113 *lineNumber
= This
->line
;
3118 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
3120 xmlreader
*This
= impl_from_IXmlReader(iface
);
3122 TRACE("(%p %p)\n", This
, linePosition
);
3124 if (!linePosition
) return E_INVALIDARG
;
3126 *linePosition
= This
->pos
;
3131 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
3133 xmlreader
*This
= impl_from_IXmlReader(iface
);
3135 TRACE("(%p)->(%p)\n", This
, count
);
3137 if (!count
) return E_INVALIDARG
;
3139 *count
= This
->attr_count
;
3143 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
3145 xmlreader
*This
= impl_from_IXmlReader(iface
);
3146 TRACE("(%p)->(%p)\n", This
, depth
);
3147 *depth
= This
->depth
;
3151 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
3153 FIXME("(%p): stub\n", iface
);
3157 static const struct IXmlReaderVtbl xmlreader_vtbl
=
3159 xmlreader_QueryInterface
,
3163 xmlreader_GetProperty
,
3164 xmlreader_SetProperty
,
3166 xmlreader_GetNodeType
,
3167 xmlreader_MoveToFirstAttribute
,
3168 xmlreader_MoveToNextAttribute
,
3169 xmlreader_MoveToAttributeByName
,
3170 xmlreader_MoveToElement
,
3171 xmlreader_GetQualifiedName
,
3172 xmlreader_GetNamespaceUri
,
3173 xmlreader_GetLocalName
,
3174 xmlreader_GetPrefix
,
3176 xmlreader_ReadValueChunk
,
3177 xmlreader_GetBaseUri
,
3178 xmlreader_IsDefault
,
3179 xmlreader_IsEmptyElement
,
3180 xmlreader_GetLineNumber
,
3181 xmlreader_GetLinePosition
,
3182 xmlreader_GetAttributeCount
,
3187 /** IXmlReaderInput **/
3188 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
3190 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
3192 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
3194 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
3195 IsEqualGUID(riid
, &IID_IUnknown
))
3201 WARN("interface %s not implemented\n", debugstr_guid(riid
));
3203 return E_NOINTERFACE
;
3206 IUnknown_AddRef(iface
);
3211 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
3213 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
3214 ULONG ref
= InterlockedIncrement(&This
->ref
);
3215 TRACE("(%p)->(%d)\n", This
, ref
);
3219 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
3221 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
3222 LONG ref
= InterlockedDecrement(&This
->ref
);
3224 TRACE("(%p)->(%d)\n", This
, ref
);
3228 IMalloc
*imalloc
= This
->imalloc
;
3229 if (This
->input
) IUnknown_Release(This
->input
);
3230 if (This
->stream
) ISequentialStream_Release(This
->stream
);
3231 if (This
->buffer
) free_input_buffer(This
->buffer
);
3232 readerinput_free(This
, This
->baseuri
);
3233 readerinput_free(This
, This
);
3234 if (imalloc
) IMalloc_Release(imalloc
);
3240 static const struct IUnknownVtbl xmlreaderinputvtbl
=
3242 xmlreaderinput_QueryInterface
,
3243 xmlreaderinput_AddRef
,
3244 xmlreaderinput_Release
3247 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
3252 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
3254 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
3256 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
3261 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
3263 reader
= heap_alloc(sizeof(*reader
));
3264 if(!reader
) return E_OUTOFMEMORY
;
3266 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
3268 reader
->input
= NULL
;
3269 reader
->state
= XmlReadState_Closed
;
3270 reader
->instate
= XmlReadInState_Initial
;
3271 reader
->resumestate
= XmlReadResumeState_Initial
;
3272 reader
->dtdmode
= DtdProcessing_Prohibit
;
3273 reader
->resolver
= NULL
;
3274 reader
->mlang
= NULL
;
3275 reader
->line
= reader
->pos
= 0;
3276 reader
->imalloc
= imalloc
;
3277 if (imalloc
) IMalloc_AddRef(imalloc
);
3278 reader
->nodetype
= XmlNodeType_None
;
3279 list_init(&reader
->attrs
);
3280 reader
->attr_count
= 0;
3281 reader
->attr
= NULL
;
3282 list_init(&reader
->nsdef
);
3283 list_init(&reader
->ns
);
3284 list_init(&reader
->elements
);
3286 reader
->max_depth
= 256;
3287 reader
->is_empty_element
= FALSE
;
3288 memset(reader
->resume
, 0, sizeof(reader
->resume
));
3290 for (i
= 0; i
< StringValue_Last
; i
++)
3291 reader
->strvalues
[i
] = strval_empty
;
3293 *obj
= &reader
->IXmlReader_iface
;
3295 TRACE("returning iface %p\n", *obj
);
3300 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
3305 IXmlReaderInput
**ppInput
)
3307 xmlreaderinput
*readerinput
;
3310 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
3311 hint
, wine_dbgstr_w(base_uri
), ppInput
);
3313 if (!stream
|| !ppInput
) return E_INVALIDARG
;
3316 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
3318 readerinput
= heap_alloc(sizeof(*readerinput
));
3319 if(!readerinput
) return E_OUTOFMEMORY
;
3321 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinputvtbl
;
3322 readerinput
->ref
= 1;
3323 readerinput
->imalloc
= imalloc
;
3324 readerinput
->stream
= NULL
;
3325 if (imalloc
) IMalloc_AddRef(imalloc
);
3326 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
3327 readerinput
->hint
= hint
;
3328 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
3329 readerinput
->pending
= 0;
3331 hr
= alloc_input_buffer(readerinput
);
3334 readerinput_free(readerinput
, readerinput
->baseuri
);
3335 readerinput_free(readerinput
, readerinput
);
3336 if (imalloc
) IMalloc_Release(imalloc
);
3339 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
3341 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
3343 TRACE("returning iface %p\n", *ppInput
);