2 * IXmlReader implementation
4 * Copyright 2010, 2012-2013 Nikolay Sivov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "xmllite_private.h"
31 #include "wine/debug.h"
32 #include "wine/list.h"
33 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(xmllite
);
37 /* not defined in public headers */
38 DEFINE_GUID(IID_IXmlReaderInput
, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
49 XmlReadInState_Initial
,
50 XmlReadInState_XmlDecl
,
51 XmlReadInState_Misc_DTD
,
53 XmlReadInState_DTD_Misc
,
54 XmlReadInState_Element
,
55 XmlReadInState_Content
,
56 XmlReadInState_MiscEnd
57 } XmlReaderInternalState
;
59 /* This state denotes where parsing was interrupted by input problem.
60 Reader resumes parsing using this information. */
63 XmlReadResumeState_Initial
,
64 XmlReadResumeState_PITarget
,
65 XmlReadResumeState_PIBody
,
66 XmlReadResumeState_CDATA
,
67 XmlReadResumeState_Comment
,
68 XmlReadResumeState_STag
69 } XmlReaderResumeState
;
71 /* saved pointer index to resume from particular input position */
74 XmlReadResume_Name
, /* PITarget, name for NCName, prefix for QName */
75 XmlReadResume_Local
, /* local for QName */
76 XmlReadResume_Body
, /* PI body, comment text, CDATA text */
82 StringValue_LocalName
,
83 StringValue_QualifiedName
,
86 } XmlReaderStringValue
;
88 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
89 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
91 static const WCHAR dblquoteW
[] = {'\"',0};
92 static const WCHAR quoteW
[] = {'\'',0};
93 static const WCHAR ltW
[] = {'<',0};
94 static const WCHAR gtW
[] = {'>',0};
95 static const WCHAR commentW
[] = {'<','!','-','-',0};
96 static const WCHAR piW
[] = {'<','?',0};
98 struct xml_encoding_data
105 static const struct xml_encoding_data xml_encoding_map
[] = {
106 { utf16W
, XmlEncoding_UTF16
, ~0 },
107 { utf8W
, XmlEncoding_UTF8
, CP_UTF8
}
114 unsigned int allocated
;
115 unsigned int written
;
118 typedef struct input_buffer input_buffer
;
122 IXmlReaderInput IXmlReaderInput_iface
;
124 /* reference passed on IXmlReaderInput creation, is kept when input is created */
127 xml_encoding encoding
;
130 /* stream reference set after SetInput() call from reader,
131 stored as sequential stream, cause currently
132 optimizations possible with IStream aren't implemented */
133 ISequentialStream
*stream
;
134 input_buffer
*buffer
;
135 unsigned int pending
: 1;
138 static const struct IUnknownVtbl xmlreaderinputvtbl
;
140 /* Structure to hold parsed string of specific length.
142 Reader stores node value as 'start' pointer, on request
143 a null-terminated version of it is allocated.
145 To init a strval variable use reader_init_strval(),
146 to set strval as a reader value use reader_set_strval().
150 WCHAR
*start
; /* input position where value starts */
151 UINT len
; /* length in WCHARs, altered after ReadValueChunk */
152 WCHAR
*str
; /* allocated null-terminated string */
155 static WCHAR emptyW
[] = {0};
156 static const strval strval_empty
= {emptyW
, 0, emptyW
};
173 IXmlReader IXmlReader_iface
;
175 xmlreaderinput
*input
;
178 XmlReaderInternalState instate
;
179 XmlReaderResumeState resumestate
;
180 XmlNodeType nodetype
;
181 DtdProcessing dtdmode
;
182 UINT line
, pos
; /* reader position in XML stream */
183 struct list attrs
; /* attributes list for current node */
184 struct attribute
*attr
; /* current attribute */
186 struct list elements
;
187 strval strvalues
[StringValue_Last
];
189 WCHAR
*resume
[XmlReadResume_Last
]; /* pointers used to resume reader */
194 encoded_buffer utf16
;
195 encoded_buffer encoded
;
197 xmlreaderinput
*input
;
200 static inline xmlreader
*impl_from_IXmlReader(IXmlReader
*iface
)
202 return CONTAINING_RECORD(iface
, xmlreader
, IXmlReader_iface
);
205 static inline xmlreaderinput
*impl_from_IXmlReaderInput(IXmlReaderInput
*iface
)
207 return CONTAINING_RECORD(iface
, xmlreaderinput
, IXmlReaderInput_iface
);
210 static inline void *m_alloc(IMalloc
*imalloc
, size_t len
)
213 return IMalloc_Alloc(imalloc
, len
);
215 return heap_alloc(len
);
218 static inline void *m_realloc(IMalloc
*imalloc
, void *mem
, size_t len
)
221 return IMalloc_Realloc(imalloc
, mem
, len
);
223 return heap_realloc(mem
, len
);
226 static inline void m_free(IMalloc
*imalloc
, void *mem
)
229 IMalloc_Free(imalloc
, mem
);
234 /* reader memory allocation functions */
235 static inline void *reader_alloc(xmlreader
*reader
, size_t len
)
237 return m_alloc(reader
->imalloc
, len
);
240 static inline void reader_free(xmlreader
*reader
, void *mem
)
242 m_free(reader
->imalloc
, mem
);
245 static HRESULT
reader_strvaldup(xmlreader
*reader
, const strval
*src
, strval
*dest
)
249 if (src
->str
!= strval_empty
.str
)
251 dest
->str
= reader_alloc(reader
, (dest
->len
+1)*sizeof(WCHAR
));
252 if (!dest
->str
) return E_OUTOFMEMORY
;
253 memcpy(dest
->str
, src
->str
, dest
->len
*sizeof(WCHAR
));
254 dest
->str
[dest
->len
] = 0;
260 /* reader input memory allocation functions */
261 static inline void *readerinput_alloc(xmlreaderinput
*input
, size_t len
)
263 return m_alloc(input
->imalloc
, len
);
266 static inline void *readerinput_realloc(xmlreaderinput
*input
, void *mem
, size_t len
)
268 return m_realloc(input
->imalloc
, mem
, len
);
271 static inline void readerinput_free(xmlreaderinput
*input
, void *mem
)
273 m_free(input
->imalloc
, mem
);
276 static inline WCHAR
*readerinput_strdupW(xmlreaderinput
*input
, const WCHAR
*str
)
283 size
= (strlenW(str
)+1)*sizeof(WCHAR
);
284 ret
= readerinput_alloc(input
, size
);
285 if (ret
) memcpy(ret
, str
, size
);
291 static void reader_clear_attrs(xmlreader
*reader
)
293 struct attribute
*attr
, *attr2
;
294 LIST_FOR_EACH_ENTRY_SAFE(attr
, attr2
, &reader
->attrs
, struct attribute
, entry
)
296 reader_free(reader
, attr
);
298 list_init(&reader
->attrs
);
299 reader
->attr_count
= 0;
302 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
303 while we are on a node with attributes */
304 static HRESULT
reader_add_attr(xmlreader
*reader
, strval
*localname
, strval
*value
)
306 struct attribute
*attr
;
308 attr
= reader_alloc(reader
, sizeof(*attr
));
309 if (!attr
) return E_OUTOFMEMORY
;
311 attr
->localname
= *localname
;
312 attr
->value
= *value
;
313 list_add_tail(&reader
->attrs
, &attr
->entry
);
314 reader
->attr_count
++;
319 /* This one frees stored string value if needed */
320 static void reader_free_strvalued(xmlreader
*reader
, strval
*v
)
322 if (v
->str
!= strval_empty
.str
)
324 reader_free(reader
, v
->str
);
329 static inline void reader_init_strvalue(WCHAR
*str
, UINT len
, strval
*v
)
331 v
->start
= v
->str
= str
;
335 static void reader_free_strvalue(xmlreader
*reader
, XmlReaderStringValue type
)
337 reader_free_strvalued(reader
, &reader
->strvalues
[type
]);
340 static void reader_free_strvalues(xmlreader
*reader
)
343 for (type
= 0; type
< StringValue_Last
; type
++)
344 reader_free_strvalue(reader
, type
);
347 /* This helper should only be used to test if strings are the same,
348 it doesn't try to sort. */
349 static inline int strval_eq(const strval
*str1
, const strval
*str2
)
351 if (str1
->len
!= str2
->len
) return 0;
352 return !memcmp(str1
->str
, str2
->str
, str1
->len
*sizeof(WCHAR
));
355 static void reader_clear_elements(xmlreader
*reader
)
357 struct element
*elem
, *elem2
;
358 LIST_FOR_EACH_ENTRY_SAFE(elem
, elem2
, &reader
->elements
, struct element
, entry
)
360 reader_free_strvalued(reader
, &elem
->qname
);
361 reader_free(reader
, elem
);
363 list_init(&reader
->elements
);
366 static HRESULT
reader_inc_depth(xmlreader
*reader
)
368 /* FIXME: handle XmlReaderProperty_MaxElementDepth property */
373 static HRESULT
reader_push_element(xmlreader
*reader
, strval
*qname
)
375 struct element
*elem
;
378 elem
= reader_alloc(reader
, sizeof(*elem
));
379 if (!elem
) return E_OUTOFMEMORY
;
381 hr
= reader_strvaldup(reader
, qname
, &elem
->qname
);
383 reader_free(reader
, elem
);
387 if (!list_empty(&reader
->elements
))
389 hr
= reader_inc_depth(reader
);
391 reader_free(reader
, elem
);
396 list_add_head(&reader
->elements
, &elem
->entry
);
400 static void reader_pop_element(xmlreader
*reader
)
402 struct element
*elem
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
406 list_remove(&elem
->entry
);
407 reader_free_strvalued(reader
, &elem
->qname
);
408 reader_free(reader
, elem
);
412 /* Always make a copy, cause strings are supposed to be null terminated. Null pointer for 'value'
413 means node value is to be determined. */
414 static void reader_set_strvalue(xmlreader
*reader
, XmlReaderStringValue type
, const strval
*value
)
416 strval
*v
= &reader
->strvalues
[type
];
418 reader_free_strvalue(reader
, type
);
427 if (value
->str
== strval_empty
.str
)
431 if (type
== StringValue_Value
)
433 /* defer allocation for value string */
435 v
->start
= value
->start
;
440 v
->str
= reader_alloc(reader
, (value
->len
+ 1)*sizeof(WCHAR
));
441 memcpy(v
->str
, value
->start
, value
->len
*sizeof(WCHAR
));
442 v
->str
[value
->len
] = 0;
448 static inline int is_reader_pending(xmlreader
*reader
)
450 return reader
->input
->pending
;
453 static HRESULT
init_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
455 const int initial_len
= 0x2000;
456 buffer
->data
= readerinput_alloc(input
, initial_len
);
457 if (!buffer
->data
) return E_OUTOFMEMORY
;
459 memset(buffer
->data
, 0, 4);
460 buffer
->cur
= buffer
->data
;
461 buffer
->allocated
= initial_len
;
467 static void free_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
469 readerinput_free(input
, buffer
->data
);
472 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
474 if (encoding
== XmlEncoding_Unknown
)
476 FIXME("unsupported encoding %d\n", encoding
);
480 *cp
= xml_encoding_map
[encoding
].cp
;
485 static xml_encoding
parse_encoding_name(const WCHAR
*name
, int len
)
489 if (!name
) return XmlEncoding_Unknown
;
492 max
= sizeof(xml_encoding_map
)/sizeof(struct xml_encoding_data
) - 1;
499 c
= strncmpiW(xml_encoding_map
[n
].name
, name
, len
);
501 c
= strcmpiW(xml_encoding_map
[n
].name
, name
);
503 return xml_encoding_map
[n
].enc
;
511 return XmlEncoding_Unknown
;
514 static HRESULT
alloc_input_buffer(xmlreaderinput
*input
)
516 input_buffer
*buffer
;
519 input
->buffer
= NULL
;
521 buffer
= readerinput_alloc(input
, sizeof(*buffer
));
522 if (!buffer
) return E_OUTOFMEMORY
;
524 buffer
->input
= input
;
525 buffer
->code_page
= ~0; /* code page is unknown at this point */
526 hr
= init_encoded_buffer(input
, &buffer
->utf16
);
528 readerinput_free(input
, buffer
);
532 hr
= init_encoded_buffer(input
, &buffer
->encoded
);
534 free_encoded_buffer(input
, &buffer
->utf16
);
535 readerinput_free(input
, buffer
);
539 input
->buffer
= buffer
;
543 static void free_input_buffer(input_buffer
*buffer
)
545 free_encoded_buffer(buffer
->input
, &buffer
->encoded
);
546 free_encoded_buffer(buffer
->input
, &buffer
->utf16
);
547 readerinput_free(buffer
->input
, buffer
);
550 static void readerinput_release_stream(xmlreaderinput
*readerinput
)
552 if (readerinput
->stream
) {
553 ISequentialStream_Release(readerinput
->stream
);
554 readerinput
->stream
= NULL
;
558 /* Queries already stored interface for IStream/ISequentialStream.
559 Interface supplied on creation will be overwritten */
560 static HRESULT
readerinput_query_for_stream(xmlreaderinput
*readerinput
)
564 readerinput_release_stream(readerinput
);
565 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_IStream
, (void**)&readerinput
->stream
);
567 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_ISequentialStream
, (void**)&readerinput
->stream
);
572 /* reads a chunk to raw buffer */
573 static HRESULT
readerinput_growraw(xmlreaderinput
*readerinput
)
575 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
576 /* to make sure aligned length won't exceed allocated length */
577 ULONG len
= buffer
->allocated
- buffer
->written
- 4;
581 /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
582 variable width encodings like UTF-8 */
583 len
= (len
+ 3) & ~3;
584 /* try to use allocated space or grow */
585 if (buffer
->allocated
- buffer
->written
< len
)
587 buffer
->allocated
*= 2;
588 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, buffer
->allocated
);
589 len
= buffer
->allocated
- buffer
->written
;
593 hr
= ISequentialStream_Read(readerinput
->stream
, buffer
->data
+ buffer
->written
, len
, &read
);
594 TRACE("requested %d, read %d, ret 0x%08x\n", len
, read
, hr
);
595 readerinput
->pending
= hr
== E_PENDING
;
596 if (FAILED(hr
)) return hr
;
597 buffer
->written
+= read
;
602 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
603 static void readerinput_grow(xmlreaderinput
*readerinput
, int length
)
605 encoded_buffer
*buffer
= &readerinput
->buffer
->utf16
;
607 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
608 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
610 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
611 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, grown_size
);
612 buffer
->allocated
= grown_size
;
616 static inline int readerinput_is_utf8(xmlreaderinput
*readerinput
)
618 static char startA
[] = {'<','?'};
619 static char commentA
[] = {'<','!'};
620 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
621 unsigned char *ptr
= (unsigned char*)buffer
->data
;
623 return !memcmp(buffer
->data
, startA
, sizeof(startA
)) ||
624 !memcmp(buffer
->data
, commentA
, sizeof(commentA
)) ||
625 /* test start byte */
628 (ptr
[1] && (ptr
[1] <= 0x7f)) ||
629 (buffer
->data
[1] >> 5) == 0x6 || /* 2 bytes */
630 (buffer
->data
[1] >> 4) == 0xe || /* 3 bytes */
631 (buffer
->data
[1] >> 3) == 0x1e) /* 4 bytes */
635 static HRESULT
readerinput_detectencoding(xmlreaderinput
*readerinput
, xml_encoding
*enc
)
637 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
638 static WCHAR startW
[] = {'<','?'};
639 static WCHAR commentW
[] = {'<','!'};
640 static char utf8bom
[] = {0xef,0xbb,0xbf};
641 static char utf16lebom
[] = {0xff,0xfe};
643 *enc
= XmlEncoding_Unknown
;
645 if (buffer
->written
<= 3)
647 HRESULT hr
= readerinput_growraw(readerinput
);
648 if (FAILED(hr
)) return hr
;
649 if (buffer
->written
<= 3) return MX_E_INPUTEND
;
652 /* try start symbols if we have enough data to do that, input buffer should contain
653 first chunk already */
654 if (readerinput_is_utf8(readerinput
))
655 *enc
= XmlEncoding_UTF8
;
656 else if (!memcmp(buffer
->data
, startW
, sizeof(startW
)) ||
657 !memcmp(buffer
->data
, commentW
, sizeof(commentW
)))
658 *enc
= XmlEncoding_UTF16
;
659 /* try with BOM now */
660 else if (!memcmp(buffer
->data
, utf8bom
, sizeof(utf8bom
)))
662 buffer
->cur
+= sizeof(utf8bom
);
663 *enc
= XmlEncoding_UTF8
;
665 else if (!memcmp(buffer
->data
, utf16lebom
, sizeof(utf16lebom
)))
667 buffer
->cur
+= sizeof(utf16lebom
);
668 *enc
= XmlEncoding_UTF16
;
674 static int readerinput_get_utf8_convlen(xmlreaderinput
*readerinput
)
676 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
677 int len
= buffer
->written
;
679 /* complete single byte char */
680 if (!(buffer
->data
[len
-1] & 0x80)) return len
;
682 /* find start byte of multibyte char */
683 while (--len
&& !(buffer
->data
[len
] & 0xc0))
689 /* Returns byte length of complete char sequence for buffer code page,
690 it's relative to current buffer position which is currently used for BOM handling
692 static int readerinput_get_convlen(xmlreaderinput
*readerinput
)
694 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
697 if (readerinput
->buffer
->code_page
== CP_UTF8
)
698 len
= readerinput_get_utf8_convlen(readerinput
);
700 len
= buffer
->written
;
702 TRACE("%d\n", len
- (int)(buffer
->cur
- buffer
->data
));
703 return len
- (buffer
->cur
- buffer
->data
);
706 /* It's possible that raw buffer has some leftovers from last conversion - some char
707 sequence that doesn't represent a full code point. Length argument should be calculated with
708 readerinput_get_convlen(), if it's -1 it will be calculated here. */
709 static void readerinput_shrinkraw(xmlreaderinput
*readerinput
, int len
)
711 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
714 len
= readerinput_get_convlen(readerinput
);
716 memmove(buffer
->data
, buffer
->cur
+ (buffer
->written
- len
), len
);
717 /* everything below cur is lost too */
718 buffer
->written
-= len
+ (buffer
->cur
- buffer
->data
);
719 /* after this point we don't need cur pointer really,
720 it's used only to mark where actual data begins when first chunk is read */
721 buffer
->cur
= buffer
->data
;
724 /* note that raw buffer content is kept */
725 static void readerinput_switchencoding(xmlreaderinput
*readerinput
, xml_encoding enc
)
727 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
728 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
734 hr
= get_code_page(enc
, &cp
);
735 if (FAILED(hr
)) return;
737 readerinput
->buffer
->code_page
= cp
;
738 len
= readerinput_get_convlen(readerinput
);
740 TRACE("switching to cp %d\n", cp
);
742 /* just copy in this case */
743 if (enc
== XmlEncoding_UTF16
)
745 readerinput_grow(readerinput
, len
);
746 memcpy(dest
->data
, src
->cur
, len
);
747 dest
->written
+= len
*sizeof(WCHAR
);
751 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
752 readerinput_grow(readerinput
, dest_len
);
753 ptr
= (WCHAR
*)dest
->data
;
754 MultiByteToWideChar(cp
, 0, src
->cur
, len
, ptr
, dest_len
);
756 dest
->written
+= dest_len
*sizeof(WCHAR
);
759 /* shrinks parsed data a buffer begins with */
760 static void reader_shrink(xmlreader
*reader
)
762 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
764 /* avoid to move too often using threshold shrink length */
765 if (buffer
->cur
- buffer
->data
> buffer
->written
/ 2)
767 buffer
->written
-= buffer
->cur
- buffer
->data
;
768 memmove(buffer
->data
, buffer
->cur
, buffer
->written
);
769 buffer
->cur
= buffer
->data
;
770 *(WCHAR
*)&buffer
->cur
[buffer
->written
] = 0;
774 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
775 It won't attempt to shrink but will grow destination buffer if needed */
776 static HRESULT
reader_more(xmlreader
*reader
)
778 xmlreaderinput
*readerinput
= reader
->input
;
779 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
780 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
781 UINT cp
= readerinput
->buffer
->code_page
;
786 /* get some raw data from stream first */
787 hr
= readerinput_growraw(readerinput
);
788 len
= readerinput_get_convlen(readerinput
);
790 /* just copy for UTF-16 case */
793 readerinput_grow(readerinput
, len
);
794 memcpy(dest
->data
, src
->cur
, len
);
795 dest
->written
+= len
*sizeof(WCHAR
);
799 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
800 readerinput_grow(readerinput
, dest_len
);
801 ptr
= (WCHAR
*)dest
->data
;
802 MultiByteToWideChar(cp
, 0, src
->cur
, len
, ptr
, dest_len
);
804 dest
->written
+= dest_len
*sizeof(WCHAR
);
805 /* get rid of processed data */
806 readerinput_shrinkraw(readerinput
, len
);
811 static inline WCHAR
*reader_get_cur(xmlreader
*reader
)
813 WCHAR
*ptr
= (WCHAR
*)reader
->input
->buffer
->utf16
.cur
;
814 if (!*ptr
) reader_more(reader
);
818 static int reader_cmp(xmlreader
*reader
, const WCHAR
*str
)
820 const WCHAR
*ptr
= reader_get_cur(reader
);
821 return strncmpW(str
, ptr
, strlenW(str
));
824 /* moves cursor n WCHARs forward */
825 static void reader_skipn(xmlreader
*reader
, int n
)
827 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
828 const WCHAR
*ptr
= reader_get_cur(reader
);
830 while (*ptr
++ && n
--)
832 buffer
->cur
+= sizeof(WCHAR
);
837 static inline int is_wchar_space(WCHAR ch
)
839 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
842 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
843 static int reader_skipspaces(xmlreader
*reader
)
845 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
846 const WCHAR
*ptr
= reader_get_cur(reader
), *start
= ptr
;
848 while (is_wchar_space(*ptr
))
850 buffer
->cur
+= sizeof(WCHAR
);
853 else if (*ptr
== '\n')
866 /* [26] VersionNum ::= '1.' [0-9]+ */
867 static HRESULT
reader_parse_versionnum(xmlreader
*reader
, strval
*val
)
869 WCHAR
*ptr
, *ptr2
, *start
= reader_get_cur(reader
);
870 static const WCHAR onedotW
[] = {'1','.',0};
872 if (reader_cmp(reader
, onedotW
)) return WC_E_XMLDECL
;
874 reader_skipn(reader
, 2);
876 ptr2
= ptr
= reader_get_cur(reader
);
877 while (*ptr
>= '0' && *ptr
<= '9')
880 if (ptr2
== ptr
) return WC_E_DIGIT
;
881 TRACE("version=%s\n", debugstr_wn(start
, ptr
-start
));
882 reader_init_strvalue(start
, ptr
-start
, val
);
883 reader_skipn(reader
, ptr
-ptr2
);
887 /* [25] Eq ::= S? '=' S? */
888 static HRESULT
reader_parse_eq(xmlreader
*reader
)
890 static const WCHAR eqW
[] = {'=',0};
891 reader_skipspaces(reader
);
892 if (reader_cmp(reader
, eqW
)) return WC_E_EQUAL
;
894 reader_skipn(reader
, 1);
895 reader_skipspaces(reader
);
899 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
900 static HRESULT
reader_parse_versioninfo(xmlreader
*reader
)
902 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
906 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
908 if (reader_cmp(reader
, versionW
)) return WC_E_XMLDECL
;
909 reader_init_strvalue(reader_get_cur(reader
), 7, &name
);
911 reader_skipn(reader
, 7);
913 hr
= reader_parse_eq(reader
);
914 if (FAILED(hr
)) return hr
;
916 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
919 reader_skipn(reader
, 1);
921 hr
= reader_parse_versionnum(reader
, &val
);
922 if (FAILED(hr
)) return hr
;
924 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
928 reader_skipn(reader
, 1);
930 return reader_add_attr(reader
, &name
, &val
);
933 /* ([A-Za-z0-9._] | '-') */
934 static inline int is_wchar_encname(WCHAR ch
)
936 return ((ch
>= 'A' && ch
<= 'Z') ||
937 (ch
>= 'a' && ch
<= 'z') ||
938 (ch
>= '0' && ch
<= '9') ||
939 (ch
== '.') || (ch
== '_') ||
943 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
944 static HRESULT
reader_parse_encname(xmlreader
*reader
, strval
*val
)
946 WCHAR
*start
= reader_get_cur(reader
), *ptr
;
950 if ((*start
< 'A' || *start
> 'Z') && (*start
< 'a' || *start
> 'z'))
954 while (is_wchar_encname(*++ptr
))
958 enc
= parse_encoding_name(start
, len
);
959 TRACE("encoding name %s\n", debugstr_wn(start
, len
));
963 if (enc
== XmlEncoding_Unknown
)
966 /* skip encoding name */
967 reader_skipn(reader
, len
);
971 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
972 static HRESULT
reader_parse_encdecl(xmlreader
*reader
)
974 static const WCHAR encodingW
[] = {'e','n','c','o','d','i','n','g',0};
978 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
980 if (reader_cmp(reader
, encodingW
)) return S_FALSE
;
981 name
.str
= reader_get_cur(reader
);
983 /* skip 'encoding' */
984 reader_skipn(reader
, 8);
986 hr
= reader_parse_eq(reader
);
987 if (FAILED(hr
)) return hr
;
989 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
992 reader_skipn(reader
, 1);
994 hr
= reader_parse_encname(reader
, &val
);
995 if (FAILED(hr
)) return hr
;
997 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1001 reader_skipn(reader
, 1);
1003 return reader_add_attr(reader
, &name
, &val
);
1006 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
1007 static HRESULT
reader_parse_sddecl(xmlreader
*reader
)
1009 static const WCHAR standaloneW
[] = {'s','t','a','n','d','a','l','o','n','e',0};
1010 static const WCHAR yesW
[] = {'y','e','s',0};
1011 static const WCHAR noW
[] = {'n','o',0};
1016 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1018 if (reader_cmp(reader
, standaloneW
)) return S_FALSE
;
1019 reader_init_strvalue(reader_get_cur(reader
), 10, &name
);
1020 /* skip 'standalone' */
1021 reader_skipn(reader
, 10);
1023 hr
= reader_parse_eq(reader
);
1024 if (FAILED(hr
)) return hr
;
1026 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1029 reader_skipn(reader
, 1);
1031 if (reader_cmp(reader
, yesW
) && reader_cmp(reader
, noW
))
1032 return WC_E_XMLDECL
;
1034 start
= reader_get_cur(reader
);
1035 /* skip 'yes'|'no' */
1036 reader_skipn(reader
, reader_cmp(reader
, yesW
) ? 2 : 3);
1037 ptr
= reader_get_cur(reader
);
1038 TRACE("standalone=%s\n", debugstr_wn(start
, ptr
-start
));
1039 val
.str
= val
.start
= start
;
1040 val
.len
= ptr
-start
;
1042 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1045 reader_skipn(reader
, 1);
1047 return reader_add_attr(reader
, &name
, &val
);
1050 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
1051 static HRESULT
reader_parse_xmldecl(xmlreader
*reader
)
1053 static const WCHAR xmldeclW
[] = {'<','?','x','m','l',' ',0};
1054 static const WCHAR declcloseW
[] = {'?','>',0};
1057 /* check if we have "<?xml " */
1058 if (reader_cmp(reader
, xmldeclW
)) return S_FALSE
;
1060 reader_skipn(reader
, 5);
1061 hr
= reader_parse_versioninfo(reader
);
1065 hr
= reader_parse_encdecl(reader
);
1069 hr
= reader_parse_sddecl(reader
);
1073 reader_skipspaces(reader
);
1074 if (reader_cmp(reader
, declcloseW
)) return WC_E_XMLDECL
;
1075 reader_skipn(reader
, 2);
1077 reader
->nodetype
= XmlNodeType_XmlDeclaration
;
1078 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1079 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1080 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1085 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1086 static HRESULT
reader_parse_comment(xmlreader
*reader
)
1090 if (reader
->resume
[XmlReadResume_Body
])
1092 start
= reader
->resume
[XmlReadResume_Body
];
1093 ptr
= reader_get_cur(reader
);
1098 reader_skipn(reader
, 4);
1099 reader_shrink(reader
);
1100 ptr
= start
= reader_get_cur(reader
);
1101 reader
->nodetype
= XmlNodeType_Comment
;
1102 reader
->resume
[XmlReadResume_Body
] = start
;
1103 reader
->resumestate
= XmlReadResumeState_Comment
;
1104 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
1105 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
1106 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
1109 /* will exit when there's no more data, it won't attempt to
1110 read more from stream */
1121 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1123 reader_skipn(reader
, 3);
1124 reader_init_strvalue(start
, ptr
-start
, &value
);
1125 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1126 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1127 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1128 reader
->resume
[XmlReadResume_Body
] = NULL
;
1129 reader
->resumestate
= XmlReadResumeState_Initial
;
1133 return WC_E_COMMENT
;
1140 reader_skipn(reader
, 1);
1148 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1149 static inline int is_char(WCHAR ch
)
1151 return (ch
== '\t') || (ch
== '\r') || (ch
== '\n') ||
1152 (ch
>= 0x20 && ch
<= 0xd7ff) ||
1153 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1154 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1155 (ch
>= 0xe000 && ch
<= 0xfffd);
1158 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1159 static inline int is_pubchar(WCHAR ch
)
1161 return (ch
== ' ') ||
1162 (ch
>= 'a' && ch
<= 'z') ||
1163 (ch
>= 'A' && ch
<= 'Z') ||
1164 (ch
>= '0' && ch
<= '9') ||
1165 (ch
>= '-' && ch
<= ';') || /* '()*+,-./:; */
1166 (ch
== '=') || (ch
== '?') ||
1167 (ch
== '@') || (ch
== '!') ||
1168 (ch
>= '#' && ch
<= '%') || /* #$% */
1169 (ch
== '_') || (ch
== '\r') || (ch
== '\n');
1172 static inline int is_namestartchar(WCHAR ch
)
1174 return (ch
== ':') || (ch
>= 'A' && ch
<= 'Z') ||
1175 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1176 (ch
>= 0xc0 && ch
<= 0xd6) ||
1177 (ch
>= 0xd8 && ch
<= 0xf6) ||
1178 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1179 (ch
>= 0x370 && ch
<= 0x37d) ||
1180 (ch
>= 0x37f && ch
<= 0x1fff) ||
1181 (ch
>= 0x200c && ch
<= 0x200d) ||
1182 (ch
>= 0x2070 && ch
<= 0x218f) ||
1183 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1184 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1185 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1186 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1187 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1188 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1191 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1192 static inline int is_ncnamechar(WCHAR ch
)
1194 return (ch
>= 'A' && ch
<= 'Z') ||
1195 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1196 (ch
== '-') || (ch
== '.') ||
1197 (ch
>= '0' && ch
<= '9') ||
1199 (ch
>= 0xc0 && ch
<= 0xd6) ||
1200 (ch
>= 0xd8 && ch
<= 0xf6) ||
1201 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1202 (ch
>= 0x300 && ch
<= 0x36f) ||
1203 (ch
>= 0x370 && ch
<= 0x37d) ||
1204 (ch
>= 0x37f && ch
<= 0x1fff) ||
1205 (ch
>= 0x200c && ch
<= 0x200d) ||
1206 (ch
>= 0x203f && ch
<= 0x2040) ||
1207 (ch
>= 0x2070 && ch
<= 0x218f) ||
1208 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1209 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1210 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1211 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1212 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1213 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1216 static inline int is_namechar(WCHAR ch
)
1218 return (ch
== ':') || is_ncnamechar(ch
);
1221 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
1222 [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
1223 [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
1224 [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
1225 [5] Name ::= NameStartChar (NameChar)* */
1226 static HRESULT
reader_parse_name(xmlreader
*reader
, strval
*name
)
1230 if (reader
->resume
[XmlReadResume_Name
])
1232 start
= reader
->resume
[XmlReadResume_Name
];
1233 ptr
= reader_get_cur(reader
);
1237 ptr
= start
= reader_get_cur(reader
);
1238 if (!is_namestartchar(*ptr
)) return WC_E_NAMECHARACTER
;
1241 while (is_namechar(*ptr
))
1243 reader_skipn(reader
, 1);
1244 ptr
= reader_get_cur(reader
);
1247 if (is_reader_pending(reader
))
1249 reader
->resume
[XmlReadResume_Name
] = start
;
1253 reader
->resume
[XmlReadResume_Name
] = NULL
;
1255 TRACE("name %s:%d\n", debugstr_wn(start
, ptr
-start
), (int)(ptr
-start
));
1256 reader_init_strvalue(start
, ptr
-start
, name
);
1261 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1262 static HRESULT
reader_parse_pitarget(xmlreader
*reader
, strval
*target
)
1264 static const WCHAR xmlW
[] = {'x','m','l'};
1269 hr
= reader_parse_name(reader
, &name
);
1270 if (FAILED(hr
)) return is_reader_pending(reader
) ? E_PENDING
: WC_E_PI
;
1272 /* now that we got name check for illegal content */
1273 if (name
.len
== 3 && !strncmpiW(name
.str
, xmlW
, 3))
1274 return WC_E_LEADINGXML
;
1276 /* PITarget can't be a qualified name */
1277 for (i
= 0; i
< name
.len
; i
++)
1278 if (name
.str
[i
] == ':')
1279 return i
? NC_E_NAMECOLON
: WC_E_PI
;
1281 TRACE("pitarget %s:%d\n", debugstr_wn(name
.str
, name
.len
), name
.len
);
1286 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1287 static HRESULT
reader_parse_pi(xmlreader
*reader
)
1293 switch (reader
->resumestate
)
1295 case XmlReadResumeState_Initial
:
1297 reader_skipn(reader
, 2);
1298 reader_shrink(reader
);
1299 reader
->resumestate
= XmlReadResumeState_PITarget
;
1300 case XmlReadResumeState_PITarget
:
1301 hr
= reader_parse_pitarget(reader
, &target
);
1302 if (FAILED(hr
)) return hr
;
1303 reader
->resumestate
= XmlReadResumeState_PIBody
;
1308 ptr
= reader_get_cur(reader
);
1309 /* exit earlier if there's no content */
1310 if (ptr
[0] == '?' && ptr
[1] == '>')
1313 reader_skipn(reader
, 2);
1314 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1315 reader
->resumestate
= XmlReadResumeState_Initial
;
1316 reader_set_strvalue(reader
, StringValue_LocalName
, &target
);
1317 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
1318 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1322 if (!reader
->resume
[XmlReadResume_Body
])
1324 /* now at least a single space char should be there */
1325 if (!is_wchar_space(*ptr
)) return WC_E_WHITESPACE
;
1326 reader_skipspaces(reader
);
1327 ptr
= start
= reader_get_cur(reader
);
1328 reader
->resume
[XmlReadResume_Body
] = start
;
1332 start
= reader
->resume
[XmlReadResume_Body
];
1333 ptr
= reader_get_cur(reader
);
1344 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1346 reader_skipn(reader
, 2);
1347 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1348 reader
->resumestate
= XmlReadResumeState_Initial
;
1349 reader
->resume
[XmlReadResume_Body
] = NULL
;
1350 reader_init_strvalue(start
, ptr
-start
, &value
);
1351 reader_set_strvalue(reader
, StringValue_LocalName
, &target
);
1352 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
1353 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1359 reader_more(reader
);
1364 reader_skipn(reader
, 1);
1365 ptr
= reader_get_cur(reader
);
1372 /* This one is used to parse significant whitespace nodes, like in Misc production */
1373 static HRESULT
reader_parse_whitespace(xmlreader
*reader
)
1377 reader_shrink(reader
);
1378 start
= reader_get_cur(reader
);
1380 reader_skipspaces(reader
);
1381 ptr
= reader_get_cur(reader
);
1382 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1384 reader
->nodetype
= XmlNodeType_Whitespace
;
1385 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1386 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1387 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1391 /* [27] Misc ::= Comment | PI | S */
1392 static HRESULT
reader_parse_misc(xmlreader
*reader
)
1394 HRESULT hr
= S_FALSE
;
1396 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1398 hr
= reader_more(reader
);
1399 if (FAILED(hr
)) return hr
;
1401 /* finish current node */
1402 switch (reader
->resumestate
)
1404 case XmlReadResumeState_PITarget
:
1405 case XmlReadResumeState_PIBody
:
1406 return reader_parse_pi(reader
);
1407 case XmlReadResumeState_Comment
:
1408 return reader_parse_comment(reader
);
1410 ERR("unknown resume state %d\n", reader
->resumestate
);
1416 const WCHAR
*cur
= reader_get_cur(reader
);
1418 if (is_wchar_space(*cur
))
1419 hr
= reader_parse_whitespace(reader
);
1420 else if (!reader_cmp(reader
, commentW
))
1421 hr
= reader_parse_comment(reader
);
1422 else if (!reader_cmp(reader
, piW
))
1423 hr
= reader_parse_pi(reader
);
1427 if (hr
!= S_FALSE
) return hr
;
1433 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1434 static HRESULT
reader_parse_sys_literal(xmlreader
*reader
, strval
*literal
)
1436 WCHAR
*start
= reader_get_cur(reader
), *cur
, quote
;
1438 if (*start
!= '"' && *start
!= '\'') return WC_E_QUOTE
;
1441 reader_skipn(reader
, 1);
1443 cur
= start
= reader_get_cur(reader
);
1444 while (is_char(*cur
) && *cur
!= quote
)
1446 reader_skipn(reader
, 1);
1447 cur
= reader_get_cur(reader
);
1449 if (*cur
== quote
) reader_skipn(reader
, 1);
1451 literal
->str
= start
;
1452 literal
->len
= cur
-start
;
1453 TRACE("%s\n", debugstr_wn(start
, cur
-start
));
1457 /* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1458 [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1459 static HRESULT
reader_parse_pub_literal(xmlreader
*reader
, strval
*literal
)
1461 WCHAR
*start
= reader_get_cur(reader
), *cur
, quote
;
1463 if (*start
!= '"' && *start
!= '\'') return WC_E_QUOTE
;
1466 reader_skipn(reader
, 1);
1469 while (is_pubchar(*cur
) && *cur
!= quote
)
1471 reader_skipn(reader
, 1);
1472 cur
= reader_get_cur(reader
);
1475 reader_init_strvalue(start
, cur
-start
, literal
);
1476 TRACE("%s\n", debugstr_wn(start
, cur
-start
));
1480 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1481 static HRESULT
reader_parse_externalid(xmlreader
*reader
)
1483 static WCHAR systemW
[] = {'S','Y','S','T','E','M',0};
1484 static WCHAR publicW
[] = {'P','U','B','L','I','C',0};
1489 if (reader_cmp(reader
, systemW
))
1491 if (reader_cmp(reader
, publicW
))
1498 reader_skipn(reader
, 6);
1499 cnt
= reader_skipspaces(reader
);
1500 if (!cnt
) return WC_E_WHITESPACE
;
1502 hr
= reader_parse_pub_literal(reader
, &pub
);
1503 if (FAILED(hr
)) return hr
;
1505 reader_init_strvalue(publicW
, strlenW(publicW
), &name
);
1506 return reader_add_attr(reader
, &name
, &pub
);
1514 reader_skipn(reader
, 6);
1515 cnt
= reader_skipspaces(reader
);
1516 if (!cnt
) return WC_E_WHITESPACE
;
1518 hr
= reader_parse_sys_literal(reader
, &sys
);
1519 if (FAILED(hr
)) return hr
;
1521 reader_init_strvalue(systemW
, strlenW(systemW
), &name
);
1522 return reader_add_attr(reader
, &name
, &sys
);
1528 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1529 static HRESULT
reader_parse_dtd(xmlreader
*reader
)
1531 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',0};
1536 /* check if we have "<!DOCTYPE" */
1537 if (reader_cmp(reader
, doctypeW
)) return S_FALSE
;
1538 reader_shrink(reader
);
1540 /* DTD processing is not allowed by default */
1541 if (reader
->dtdmode
== DtdProcessing_Prohibit
) return WC_E_DTDPROHIBITED
;
1543 reader_skipn(reader
, 9);
1544 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1547 hr
= reader_parse_name(reader
, &name
);
1548 if (FAILED(hr
)) return WC_E_DECLDOCTYPE
;
1550 reader_skipspaces(reader
);
1552 hr
= reader_parse_externalid(reader
);
1553 if (FAILED(hr
)) return hr
;
1555 reader_skipspaces(reader
);
1557 cur
= reader_get_cur(reader
);
1560 FIXME("internal subset parsing not implemented\n");
1565 reader_skipn(reader
, 1);
1567 reader
->nodetype
= XmlNodeType_DocumentType
;
1568 reader_set_strvalue(reader
, StringValue_LocalName
, &name
);
1569 reader_set_strvalue(reader
, StringValue_QualifiedName
, &name
);
1574 /* [11 NS] LocalPart ::= NCName */
1575 static HRESULT
reader_parse_local(xmlreader
*reader
, strval
*local
)
1579 if (reader
->resume
[XmlReadResume_Local
])
1581 start
= reader
->resume
[XmlReadResume_Local
];
1582 ptr
= reader_get_cur(reader
);
1586 ptr
= start
= reader_get_cur(reader
);
1589 while (is_ncnamechar(*ptr
))
1591 reader_skipn(reader
, 1);
1592 ptr
= reader_get_cur(reader
);
1595 if (is_reader_pending(reader
))
1597 reader
->resume
[XmlReadResume_Local
] = start
;
1601 reader
->resume
[XmlReadResume_Local
] = NULL
;
1603 reader_init_strvalue(start
, ptr
-start
, local
);
1608 /* [7 NS] QName ::= PrefixedName | UnprefixedName
1609 [8 NS] PrefixedName ::= Prefix ':' LocalPart
1610 [9 NS] UnprefixedName ::= LocalPart
1611 [10 NS] Prefix ::= NCName */
1612 static HRESULT
reader_parse_qname(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
)
1617 if (reader
->resume
[XmlReadResume_Name
])
1619 start
= reader
->resume
[XmlReadResume_Name
];
1620 ptr
= reader_get_cur(reader
);
1624 ptr
= start
= reader_get_cur(reader
);
1625 reader
->resume
[XmlReadResume_Name
] = start
;
1626 if (!is_ncnamechar(*ptr
)) return NC_E_QNAMECHARACTER
;
1629 if (reader
->resume
[XmlReadResume_Local
])
1631 hr
= reader_parse_local(reader
, local
);
1632 if (FAILED(hr
)) return hr
;
1634 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
],
1635 local
->start
- reader
->resume
[XmlReadResume_Name
] - 1,
1640 /* skip prefix part */
1641 while (is_ncnamechar(*ptr
))
1643 reader_skipn(reader
, 1);
1644 ptr
= reader_get_cur(reader
);
1647 if (is_reader_pending(reader
)) return E_PENDING
;
1649 /* got a qualified name */
1652 reader_init_strvalue(start
, ptr
-start
, prefix
);
1655 reader_skipn(reader
, 1);
1656 hr
= reader_parse_local(reader
, local
);
1657 if (FAILED(hr
)) return hr
;
1661 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
], ptr
-reader
->resume
[XmlReadResume_Name
], local
);
1662 reader_init_strvalue(NULL
, 0, prefix
);
1666 reader_init_strvalue(start
, ptr
-start
, local
);
1669 TRACE("qname %s:%s\n", debugstr_wn(prefix
->start
, prefix
->len
), debugstr_wn(local
->start
, local
->len
));
1671 TRACE("ncname %s\n", debugstr_wn(local
->start
, local
->len
));
1673 reader_init_strvalue(prefix
->start
? prefix
->start
: local
->start
,
1675 (prefix
->len
? prefix
->len
+ 1 : 0) + local
->len
,
1678 reader
->resume
[XmlReadResume_Name
] = NULL
;
1679 reader
->resume
[XmlReadResume_Local
] = NULL
;
1684 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
1685 [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
1686 static HRESULT
reader_parse_stag(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
, int *empty
)
1688 static const WCHAR endW
[] = {'/','>',0};
1691 hr
= reader_parse_qname(reader
, prefix
, local
, qname
);
1692 if (FAILED(hr
)) return hr
;
1694 reader_skipspaces(reader
);
1697 if ((*empty
= !reader_cmp(reader
, endW
)))
1700 reader_skipn(reader
, 2);
1704 /* got a start tag */
1705 if (!reader_cmp(reader
, gtW
))
1708 reader_skipn(reader
, 1);
1709 return reader_push_element(reader
, qname
);
1712 FIXME("only empty elements/start tags without attribute list supported\n");
1716 /* [39] element ::= EmptyElemTag | STag content ETag */
1717 static HRESULT
reader_parse_element(xmlreader
*reader
)
1721 switch (reader
->resumestate
)
1723 case XmlReadResumeState_Initial
:
1724 /* check if we are really on element */
1725 if (reader_cmp(reader
, ltW
)) return S_FALSE
;
1728 reader_skipn(reader
, 1);
1730 reader_shrink(reader
);
1731 reader
->resumestate
= XmlReadResumeState_STag
;
1732 case XmlReadResumeState_STag
:
1734 strval qname
, prefix
, local
;
1737 /* this handles empty elements too */
1738 hr
= reader_parse_stag(reader
, &prefix
, &local
, &qname
, &empty
);
1739 if (FAILED(hr
)) return hr
;
1741 /* FIXME: need to check for defined namespace to reject invalid prefix,
1742 currently reject all prefixes */
1743 if (prefix
.len
) return NC_E_UNDECLAREDPREFIX
;
1745 /* if we got empty element and stack is empty go straight to Misc */
1746 if (empty
&& list_empty(&reader
->elements
))
1747 reader
->instate
= XmlReadInState_MiscEnd
;
1749 reader
->instate
= XmlReadInState_Content
;
1751 reader
->nodetype
= XmlNodeType_Element
;
1752 reader
->resumestate
= XmlReadResumeState_Initial
;
1753 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
1754 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
1764 /* [13 NS] ETag ::= '</' QName S? '>' */
1765 static HRESULT
reader_parse_endtag(xmlreader
*reader
)
1767 strval prefix
, local
, qname
;
1768 struct element
*elem
;
1772 reader_skipn(reader
, 2);
1774 hr
= reader_parse_qname(reader
, &prefix
, &local
, &qname
);
1775 if (FAILED(hr
)) return hr
;
1777 reader_skipspaces(reader
);
1779 if (reader_cmp(reader
, gtW
)) return WC_E_GREATERTHAN
;
1782 reader_skipn(reader
, 1);
1784 /* Element stack should never be empty at this point, cause we shouldn't get to
1785 content parsing if it's empty. */
1786 elem
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
1787 if (!strval_eq(&elem
->qname
, &qname
)) return WC_E_ELEMENTMATCH
;
1789 reader_pop_element(reader
);
1791 reader
->nodetype
= XmlNodeType_EndElement
;
1792 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
1793 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
1798 /* [18] CDSect ::= CDStart CData CDEnd
1799 [19] CDStart ::= '<![CDATA['
1800 [20] CData ::= (Char* - (Char* ']]>' Char*))
1801 [21] CDEnd ::= ']]>' */
1802 static HRESULT
reader_parse_cdata(xmlreader
*reader
)
1806 if (reader
->resume
[XmlReadResume_Body
])
1808 start
= reader
->resume
[XmlReadResume_Body
];
1809 ptr
= reader_get_cur(reader
);
1813 /* skip markup '<![CDATA[' */
1814 reader_skipn(reader
, 9);
1815 reader_shrink(reader
);
1816 ptr
= start
= reader_get_cur(reader
);
1817 reader
->nodetype
= XmlNodeType_CDATA
;
1818 reader
->resume
[XmlReadResume_Body
] = start
;
1819 reader
->resumestate
= XmlReadResumeState_CDATA
;
1820 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
1821 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
1822 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
1827 if (*ptr
== ']' && *(ptr
+1) == ']' && *(ptr
+2) == '>')
1831 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1833 reader_skipn(reader
, 3);
1834 reader_init_strvalue(start
, ptr
-start
, &value
);
1835 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1836 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1837 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1838 reader
->resume
[XmlReadResume_Body
] = NULL
;
1839 reader
->resumestate
= XmlReadResumeState_Initial
;
1844 /* Value normalization is not fully implemented, rules are:
1846 - single '\r' -> '\n';
1847 - sequence '\r\n' -> '\n', in this case value length changes;
1849 if (*ptr
== '\r') *ptr
= '\n';
1850 reader_skipn(reader
, 1);
1858 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1859 [67] Reference ::= EntityRef | CharRef
1860 [68] EntityRef ::= '&' Name ';' */
1861 static HRESULT
reader_parse_reference(xmlreader
*reader
)
1863 FIXME("References not supported\n");
1867 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1868 static HRESULT
reader_parse_chardata(xmlreader
*reader
)
1870 FIXME("CharData not supported\n");
1874 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1875 static HRESULT
reader_parse_content(xmlreader
*reader
)
1877 static const WCHAR cdstartW
[] = {'<','!','[','C','D','A','T','A','[',0};
1878 static const WCHAR etagW
[] = {'<','/',0};
1879 static const WCHAR ampW
[] = {'&',0};
1881 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1883 switch (reader
->resumestate
)
1885 case XmlReadResumeState_CDATA
:
1886 return reader_parse_cdata(reader
);
1887 case XmlReadResumeState_Comment
:
1888 return reader_parse_comment(reader
);
1889 case XmlReadResumeState_PIBody
:
1890 case XmlReadResumeState_PITarget
:
1891 return reader_parse_pi(reader
);
1893 ERR("unknown resume state %d\n", reader
->resumestate
);
1897 reader_shrink(reader
);
1899 /* handle end tag here, it indicates end of content as well */
1900 if (!reader_cmp(reader
, etagW
))
1901 return reader_parse_endtag(reader
);
1903 if (!reader_cmp(reader
, commentW
))
1904 return reader_parse_comment(reader
);
1906 if (!reader_cmp(reader
, piW
))
1907 return reader_parse_pi(reader
);
1909 if (!reader_cmp(reader
, cdstartW
))
1910 return reader_parse_cdata(reader
);
1912 if (!reader_cmp(reader
, ampW
))
1913 return reader_parse_reference(reader
);
1915 if (!reader_cmp(reader
, ltW
))
1916 return reader_parse_element(reader
);
1918 /* what's left must be CharData */
1919 return reader_parse_chardata(reader
);
1922 static HRESULT
reader_parse_nextnode(xmlreader
*reader
)
1928 switch (reader
->instate
)
1930 /* if it's a first call for a new input we need to detect stream encoding */
1931 case XmlReadInState_Initial
:
1935 hr
= readerinput_growraw(reader
->input
);
1936 if (FAILED(hr
)) return hr
;
1938 /* try to detect encoding by BOM or data and set input code page */
1939 hr
= readerinput_detectencoding(reader
->input
, &enc
);
1940 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
1941 if (FAILED(hr
)) return hr
;
1943 /* always switch first time cause we have to put something in */
1944 readerinput_switchencoding(reader
->input
, enc
);
1946 /* parse xml declaration */
1947 hr
= reader_parse_xmldecl(reader
);
1948 if (FAILED(hr
)) return hr
;
1950 readerinput_shrinkraw(reader
->input
, -1);
1951 reader
->instate
= XmlReadInState_Misc_DTD
;
1952 if (hr
== S_OK
) return hr
;
1955 case XmlReadInState_Misc_DTD
:
1956 hr
= reader_parse_misc(reader
);
1957 if (FAILED(hr
)) return hr
;
1960 reader
->instate
= XmlReadInState_DTD
;
1964 case XmlReadInState_DTD
:
1965 hr
= reader_parse_dtd(reader
);
1966 if (FAILED(hr
)) return hr
;
1970 reader
->instate
= XmlReadInState_DTD_Misc
;
1974 reader
->instate
= XmlReadInState_Element
;
1976 case XmlReadInState_DTD_Misc
:
1977 hr
= reader_parse_misc(reader
);
1978 if (FAILED(hr
)) return hr
;
1981 reader
->instate
= XmlReadInState_Element
;
1985 case XmlReadInState_Element
:
1986 return reader_parse_element(reader
);
1987 case XmlReadInState_Content
:
1988 return reader_parse_content(reader
);
1990 FIXME("internal state %d not handled\n", reader
->instate
);
1998 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
2000 xmlreader
*This
= impl_from_IXmlReader(iface
);
2002 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2004 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
2005 IsEqualGUID(riid
, &IID_IXmlReader
))
2011 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
2013 return E_NOINTERFACE
;
2016 IXmlReader_AddRef(iface
);
2021 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
2023 xmlreader
*This
= impl_from_IXmlReader(iface
);
2024 ULONG ref
= InterlockedIncrement(&This
->ref
);
2025 TRACE("(%p)->(%d)\n", This
, ref
);
2029 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
2031 xmlreader
*This
= impl_from_IXmlReader(iface
);
2032 LONG ref
= InterlockedDecrement(&This
->ref
);
2034 TRACE("(%p)->(%d)\n", This
, ref
);
2038 IMalloc
*imalloc
= This
->imalloc
;
2039 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2040 reader_clear_attrs(This
);
2041 reader_clear_elements(This
);
2042 reader_free_strvalues(This
);
2043 reader_free(This
, This
);
2044 if (imalloc
) IMalloc_Release(imalloc
);
2050 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
2052 xmlreader
*This
= impl_from_IXmlReader(iface
);
2053 IXmlReaderInput
*readerinput
;
2056 TRACE("(%p)->(%p)\n", This
, input
);
2060 readerinput_release_stream(This
->input
);
2061 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2065 This
->line
= This
->pos
= 0;
2066 reader_clear_elements(This
);
2068 This
->resumestate
= XmlReadResumeState_Initial
;
2069 memset(This
->resume
, 0, sizeof(This
->resume
));
2071 /* just reset current input */
2074 This
->state
= XmlReadState_Initial
;
2078 /* now try IXmlReaderInput, ISequentialStream, IStream */
2079 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&readerinput
);
2082 if (readerinput
->lpVtbl
== &xmlreaderinputvtbl
)
2083 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2086 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2087 readerinput
, readerinput
->lpVtbl
);
2088 IUnknown_Release(readerinput
);
2094 if (hr
!= S_OK
|| !readerinput
)
2096 /* create IXmlReaderInput basing on supplied interface */
2097 hr
= CreateXmlReaderInputWithEncodingName(input
,
2098 NULL
, NULL
, FALSE
, NULL
, &readerinput
);
2099 if (hr
!= S_OK
) return hr
;
2100 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2103 /* set stream for supplied IXmlReaderInput */
2104 hr
= readerinput_query_for_stream(This
->input
);
2107 This
->state
= XmlReadState_Initial
;
2108 This
->instate
= XmlReadInState_Initial
;
2114 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
2116 xmlreader
*This
= impl_from_IXmlReader(iface
);
2118 TRACE("(%p %u %p)\n", This
, property
, value
);
2120 if (!value
) return E_INVALIDARG
;
2124 case XmlReaderProperty_DtdProcessing
:
2125 *value
= This
->dtdmode
;
2127 case XmlReaderProperty_ReadState
:
2128 *value
= This
->state
;
2131 FIXME("Unimplemented property (%u)\n", property
);
2138 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
2140 xmlreader
*This
= impl_from_IXmlReader(iface
);
2142 TRACE("(%p %u %lu)\n", iface
, property
, value
);
2146 case XmlReaderProperty_DtdProcessing
:
2147 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
2148 This
->dtdmode
= value
;
2151 FIXME("Unimplemented property (%u)\n", property
);
2158 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*nodetype
)
2160 xmlreader
*This
= impl_from_IXmlReader(iface
);
2161 XmlNodeType oldtype
= This
->nodetype
;
2164 TRACE("(%p)->(%p)\n", This
, nodetype
);
2166 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
2168 hr
= reader_parse_nextnode(This
);
2169 if (oldtype
== XmlNodeType_None
&& This
->nodetype
!= oldtype
)
2170 This
->state
= XmlReadState_Interactive
;
2171 if (hr
== S_OK
) *nodetype
= This
->nodetype
;
2176 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
2178 xmlreader
*This
= impl_from_IXmlReader(iface
);
2179 TRACE("(%p)->(%p)\n", This
, node_type
);
2181 /* When we're on attribute always return attribute type, container node type is kept.
2182 Note that container is not necessarily an element, and attribute doesn't mean it's
2183 an attribute in XML spec terms. */
2184 *node_type
= This
->attr
? XmlNodeType_Attribute
: This
->nodetype
;
2185 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
2188 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
2190 xmlreader
*This
= impl_from_IXmlReader(iface
);
2192 TRACE("(%p)\n", This
);
2194 if (!This
->attr_count
) return S_FALSE
;
2195 This
->attr
= LIST_ENTRY(list_head(&This
->attrs
), struct attribute
, entry
);
2199 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
2201 xmlreader
*This
= impl_from_IXmlReader(iface
);
2202 const struct list
*next
;
2204 TRACE("(%p)\n", This
);
2206 if (!This
->attr_count
) return S_FALSE
;
2209 return IXmlReader_MoveToFirstAttribute(iface
);
2211 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
2213 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
2215 return next
? S_OK
: S_FALSE
;
2218 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
2220 LPCWSTR namespaceUri
)
2222 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
2226 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
2228 xmlreader
*This
= impl_from_IXmlReader(iface
);
2230 TRACE("(%p)\n", This
);
2232 if (!This
->attr_count
) return S_FALSE
;
2237 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2239 xmlreader
*This
= impl_from_IXmlReader(iface
);
2241 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2242 *name
= This
->strvalues
[StringValue_QualifiedName
].str
;
2243 *len
= This
->strvalues
[StringValue_QualifiedName
].len
;
2247 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
,
2248 LPCWSTR
*namespaceUri
,
2249 UINT
*namespaceUri_length
)
2251 FIXME("(%p %p %p): stub\n", iface
, namespaceUri
, namespaceUri_length
);
2255 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2257 xmlreader
*This
= impl_from_IXmlReader(iface
);
2259 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2260 *name
= This
->strvalues
[StringValue_LocalName
].str
;
2261 *len
= This
->strvalues
[StringValue_LocalName
].len
;
2265 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
,
2267 UINT
*prefix_length
)
2269 FIXME("(%p %p %p): stub\n", iface
, prefix
, prefix_length
);
2273 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
, const WCHAR
**value
, UINT
*len
)
2275 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2276 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2278 TRACE("(%p)->(%p %p)\n", reader
, value
, len
);
2282 if ((reader
->nodetype
== XmlNodeType_Comment
&& !val
->str
) || is_reader_pending(reader
))
2287 hr
= IXmlReader_Read(iface
, &type
);
2288 if (FAILED(hr
)) return hr
;
2290 /* return if still pending, partially read values are not reported */
2291 if (is_reader_pending(reader
)) return E_PENDING
;
2296 val
->str
= reader_alloc(reader
, (val
->len
+1)*sizeof(WCHAR
));
2297 if (!val
->str
) return E_OUTOFMEMORY
;
2298 memcpy(val
->str
, val
->start
, val
->len
*sizeof(WCHAR
));
2299 val
->str
[val
->len
] = 0;
2303 if (len
) *len
= val
->len
;
2307 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
, WCHAR
*buffer
, UINT chunk_size
, UINT
*read
)
2309 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2310 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2313 TRACE("(%p)->(%p %u %p)\n", reader
, buffer
, chunk_size
, read
);
2315 /* Value is already allocated, chunked reads are not possible. */
2316 if (val
->str
) return S_FALSE
;
2320 len
= min(chunk_size
, val
->len
);
2321 memcpy(buffer
, val
->start
, len
);
2324 if (read
) *read
= len
;
2330 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
2332 UINT
*baseUri_length
)
2334 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
2338 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
2340 FIXME("(%p): stub\n", iface
);
2344 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
2346 FIXME("(%p): stub\n", iface
);
2350 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
2352 xmlreader
*This
= impl_from_IXmlReader(iface
);
2354 TRACE("(%p %p)\n", This
, lineNumber
);
2356 if (!lineNumber
) return E_INVALIDARG
;
2358 *lineNumber
= This
->line
;
2363 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
2365 xmlreader
*This
= impl_from_IXmlReader(iface
);
2367 TRACE("(%p %p)\n", This
, linePosition
);
2369 if (!linePosition
) return E_INVALIDARG
;
2371 *linePosition
= This
->pos
;
2376 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
2378 xmlreader
*This
= impl_from_IXmlReader(iface
);
2380 TRACE("(%p)->(%p)\n", This
, count
);
2382 if (!count
) return E_INVALIDARG
;
2384 *count
= This
->attr_count
;
2388 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
2390 xmlreader
*This
= impl_from_IXmlReader(iface
);
2391 TRACE("(%p)->(%p)\n", This
, depth
);
2392 *depth
= This
->depth
;
2396 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
2398 FIXME("(%p): stub\n", iface
);
2402 static const struct IXmlReaderVtbl xmlreader_vtbl
=
2404 xmlreader_QueryInterface
,
2408 xmlreader_GetProperty
,
2409 xmlreader_SetProperty
,
2411 xmlreader_GetNodeType
,
2412 xmlreader_MoveToFirstAttribute
,
2413 xmlreader_MoveToNextAttribute
,
2414 xmlreader_MoveToAttributeByName
,
2415 xmlreader_MoveToElement
,
2416 xmlreader_GetQualifiedName
,
2417 xmlreader_GetNamespaceUri
,
2418 xmlreader_GetLocalName
,
2419 xmlreader_GetPrefix
,
2421 xmlreader_ReadValueChunk
,
2422 xmlreader_GetBaseUri
,
2423 xmlreader_IsDefault
,
2424 xmlreader_IsEmptyElement
,
2425 xmlreader_GetLineNumber
,
2426 xmlreader_GetLinePosition
,
2427 xmlreader_GetAttributeCount
,
2432 /** IXmlReaderInput **/
2433 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
2435 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2437 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2439 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
2440 IsEqualGUID(riid
, &IID_IUnknown
))
2446 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2448 return E_NOINTERFACE
;
2451 IUnknown_AddRef(iface
);
2456 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
2458 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2459 ULONG ref
= InterlockedIncrement(&This
->ref
);
2460 TRACE("(%p)->(%d)\n", This
, ref
);
2464 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
2466 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2467 LONG ref
= InterlockedDecrement(&This
->ref
);
2469 TRACE("(%p)->(%d)\n", This
, ref
);
2473 IMalloc
*imalloc
= This
->imalloc
;
2474 if (This
->input
) IUnknown_Release(This
->input
);
2475 if (This
->stream
) ISequentialStream_Release(This
->stream
);
2476 if (This
->buffer
) free_input_buffer(This
->buffer
);
2477 readerinput_free(This
, This
->baseuri
);
2478 readerinput_free(This
, This
);
2479 if (imalloc
) IMalloc_Release(imalloc
);
2485 static const struct IUnknownVtbl xmlreaderinputvtbl
=
2487 xmlreaderinput_QueryInterface
,
2488 xmlreaderinput_AddRef
,
2489 xmlreaderinput_Release
2492 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
2497 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
2499 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
2501 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
2506 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
2508 reader
= heap_alloc(sizeof(*reader
));
2509 if(!reader
) return E_OUTOFMEMORY
;
2511 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
2513 reader
->input
= NULL
;
2514 reader
->state
= XmlReadState_Closed
;
2515 reader
->instate
= XmlReadInState_Initial
;
2516 reader
->resumestate
= XmlReadResumeState_Initial
;
2517 reader
->dtdmode
= DtdProcessing_Prohibit
;
2518 reader
->line
= reader
->pos
= 0;
2519 reader
->imalloc
= imalloc
;
2520 if (imalloc
) IMalloc_AddRef(imalloc
);
2521 reader
->nodetype
= XmlNodeType_None
;
2522 list_init(&reader
->attrs
);
2523 reader
->attr_count
= 0;
2524 reader
->attr
= NULL
;
2525 list_init(&reader
->elements
);
2527 memset(reader
->resume
, 0, sizeof(reader
->resume
));
2529 for (i
= 0; i
< StringValue_Last
; i
++)
2530 reader
->strvalues
[i
] = strval_empty
;
2532 *obj
= &reader
->IXmlReader_iface
;
2534 TRACE("returning iface %p\n", *obj
);
2539 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
2544 IXmlReaderInput
**ppInput
)
2546 xmlreaderinput
*readerinput
;
2549 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
2550 hint
, wine_dbgstr_w(base_uri
), ppInput
);
2552 if (!stream
|| !ppInput
) return E_INVALIDARG
;
2555 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
2557 readerinput
= heap_alloc(sizeof(*readerinput
));
2558 if(!readerinput
) return E_OUTOFMEMORY
;
2560 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinputvtbl
;
2561 readerinput
->ref
= 1;
2562 readerinput
->imalloc
= imalloc
;
2563 readerinput
->stream
= NULL
;
2564 if (imalloc
) IMalloc_AddRef(imalloc
);
2565 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
2566 readerinput
->hint
= hint
;
2567 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
2568 readerinput
->pending
= 0;
2570 hr
= alloc_input_buffer(readerinput
);
2573 readerinput_free(readerinput
, readerinput
->baseuri
);
2574 readerinput_free(readerinput
, readerinput
);
2575 if (imalloc
) IMalloc_Release(imalloc
);
2578 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
2580 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
2582 TRACE("returning iface %p\n", *ppInput
);