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_set_strvalue(reader
, StringValue_LocalName
, &target
);
1304 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
1305 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1306 reader
->resumestate
= XmlReadResumeState_PIBody
;
1311 ptr
= reader_get_cur(reader
);
1312 /* exit earlier if there's no content */
1313 if (ptr
[0] == '?' && ptr
[1] == '>')
1316 reader_skipn(reader
, 2);
1317 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1318 reader
->resumestate
= XmlReadResumeState_Initial
;
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_Value
, &value
);
1357 reader_more(reader
);
1362 reader_skipn(reader
, 1);
1363 ptr
= reader_get_cur(reader
);
1370 /* This one is used to parse significant whitespace nodes, like in Misc production */
1371 static HRESULT
reader_parse_whitespace(xmlreader
*reader
)
1375 reader_shrink(reader
);
1376 start
= reader_get_cur(reader
);
1378 reader_skipspaces(reader
);
1379 ptr
= reader_get_cur(reader
);
1380 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1382 reader
->nodetype
= XmlNodeType_Whitespace
;
1383 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1384 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1385 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1389 /* [27] Misc ::= Comment | PI | S */
1390 static HRESULT
reader_parse_misc(xmlreader
*reader
)
1392 HRESULT hr
= S_FALSE
;
1394 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1396 hr
= reader_more(reader
);
1397 if (FAILED(hr
)) return hr
;
1399 /* finish current node */
1400 switch (reader
->resumestate
)
1402 case XmlReadResumeState_PITarget
:
1403 case XmlReadResumeState_PIBody
:
1404 return reader_parse_pi(reader
);
1405 case XmlReadResumeState_Comment
:
1406 return reader_parse_comment(reader
);
1408 ERR("unknown resume state %d\n", reader
->resumestate
);
1414 const WCHAR
*cur
= reader_get_cur(reader
);
1416 if (is_wchar_space(*cur
))
1417 hr
= reader_parse_whitespace(reader
);
1418 else if (!reader_cmp(reader
, commentW
))
1419 hr
= reader_parse_comment(reader
);
1420 else if (!reader_cmp(reader
, piW
))
1421 hr
= reader_parse_pi(reader
);
1425 if (hr
!= S_FALSE
) return hr
;
1431 /* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */
1432 static HRESULT
reader_parse_sys_literal(xmlreader
*reader
, strval
*literal
)
1434 WCHAR
*start
= reader_get_cur(reader
), *cur
, quote
;
1436 if (*start
!= '"' && *start
!= '\'') return WC_E_QUOTE
;
1439 reader_skipn(reader
, 1);
1441 cur
= start
= reader_get_cur(reader
);
1442 while (is_char(*cur
) && *cur
!= quote
)
1444 reader_skipn(reader
, 1);
1445 cur
= reader_get_cur(reader
);
1447 if (*cur
== quote
) reader_skipn(reader
, 1);
1449 literal
->str
= start
;
1450 literal
->len
= cur
-start
;
1451 TRACE("%s\n", debugstr_wn(start
, cur
-start
));
1455 /* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1456 [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1457 static HRESULT
reader_parse_pub_literal(xmlreader
*reader
, strval
*literal
)
1459 WCHAR
*start
= reader_get_cur(reader
), *cur
, quote
;
1461 if (*start
!= '"' && *start
!= '\'') return WC_E_QUOTE
;
1464 reader_skipn(reader
, 1);
1467 while (is_pubchar(*cur
) && *cur
!= quote
)
1469 reader_skipn(reader
, 1);
1470 cur
= reader_get_cur(reader
);
1473 reader_init_strvalue(start
, cur
-start
, literal
);
1474 TRACE("%s\n", debugstr_wn(start
, cur
-start
));
1478 /* [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral */
1479 static HRESULT
reader_parse_externalid(xmlreader
*reader
)
1481 static WCHAR systemW
[] = {'S','Y','S','T','E','M',0};
1482 static WCHAR publicW
[] = {'P','U','B','L','I','C',0};
1487 if (reader_cmp(reader
, systemW
))
1489 if (reader_cmp(reader
, publicW
))
1496 reader_skipn(reader
, 6);
1497 cnt
= reader_skipspaces(reader
);
1498 if (!cnt
) return WC_E_WHITESPACE
;
1500 hr
= reader_parse_pub_literal(reader
, &pub
);
1501 if (FAILED(hr
)) return hr
;
1503 reader_init_strvalue(publicW
, strlenW(publicW
), &name
);
1504 return reader_add_attr(reader
, &name
, &pub
);
1512 reader_skipn(reader
, 6);
1513 cnt
= reader_skipspaces(reader
);
1514 if (!cnt
) return WC_E_WHITESPACE
;
1516 hr
= reader_parse_sys_literal(reader
, &sys
);
1517 if (FAILED(hr
)) return hr
;
1519 reader_init_strvalue(systemW
, strlenW(systemW
), &name
);
1520 return reader_add_attr(reader
, &name
, &sys
);
1526 /* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */
1527 static HRESULT
reader_parse_dtd(xmlreader
*reader
)
1529 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',0};
1534 /* check if we have "<!DOCTYPE" */
1535 if (reader_cmp(reader
, doctypeW
)) return S_FALSE
;
1536 reader_shrink(reader
);
1538 /* DTD processing is not allowed by default */
1539 if (reader
->dtdmode
== DtdProcessing_Prohibit
) return WC_E_DTDPROHIBITED
;
1541 reader_skipn(reader
, 9);
1542 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1545 hr
= reader_parse_name(reader
, &name
);
1546 if (FAILED(hr
)) return WC_E_DECLDOCTYPE
;
1548 reader_skipspaces(reader
);
1550 hr
= reader_parse_externalid(reader
);
1551 if (FAILED(hr
)) return hr
;
1553 reader_skipspaces(reader
);
1555 cur
= reader_get_cur(reader
);
1558 FIXME("internal subset parsing not implemented\n");
1563 reader_skipn(reader
, 1);
1565 reader
->nodetype
= XmlNodeType_DocumentType
;
1566 reader_set_strvalue(reader
, StringValue_LocalName
, &name
);
1567 reader_set_strvalue(reader
, StringValue_QualifiedName
, &name
);
1572 /* [11 NS] LocalPart ::= NCName */
1573 static HRESULT
reader_parse_local(xmlreader
*reader
, strval
*local
)
1577 if (reader
->resume
[XmlReadResume_Local
])
1579 start
= reader
->resume
[XmlReadResume_Local
];
1580 ptr
= reader_get_cur(reader
);
1584 ptr
= start
= reader_get_cur(reader
);
1587 while (is_ncnamechar(*ptr
))
1589 reader_skipn(reader
, 1);
1590 ptr
= reader_get_cur(reader
);
1593 if (is_reader_pending(reader
))
1595 reader
->resume
[XmlReadResume_Local
] = start
;
1599 reader
->resume
[XmlReadResume_Local
] = NULL
;
1601 reader_init_strvalue(start
, ptr
-start
, local
);
1606 /* [7 NS] QName ::= PrefixedName | UnprefixedName
1607 [8 NS] PrefixedName ::= Prefix ':' LocalPart
1608 [9 NS] UnprefixedName ::= LocalPart
1609 [10 NS] Prefix ::= NCName */
1610 static HRESULT
reader_parse_qname(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
)
1615 if (reader
->resume
[XmlReadResume_Name
])
1617 start
= reader
->resume
[XmlReadResume_Name
];
1618 ptr
= reader_get_cur(reader
);
1622 ptr
= start
= reader_get_cur(reader
);
1623 reader
->resume
[XmlReadResume_Name
] = start
;
1624 if (!is_ncnamechar(*ptr
)) return NC_E_QNAMECHARACTER
;
1627 if (reader
->resume
[XmlReadResume_Local
])
1629 hr
= reader_parse_local(reader
, local
);
1630 if (FAILED(hr
)) return hr
;
1632 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
],
1633 local
->start
- reader
->resume
[XmlReadResume_Name
] - 1,
1638 /* skip prefix part */
1639 while (is_ncnamechar(*ptr
))
1641 reader_skipn(reader
, 1);
1642 ptr
= reader_get_cur(reader
);
1645 if (is_reader_pending(reader
)) return E_PENDING
;
1647 /* got a qualified name */
1650 reader_init_strvalue(start
, ptr
-start
, prefix
);
1653 reader_skipn(reader
, 1);
1654 hr
= reader_parse_local(reader
, local
);
1655 if (FAILED(hr
)) return hr
;
1659 reader_init_strvalue(reader
->resume
[XmlReadResume_Name
], ptr
-reader
->resume
[XmlReadResume_Name
], local
);
1660 reader_init_strvalue(NULL
, 0, prefix
);
1664 reader_init_strvalue(start
, ptr
-start
, local
);
1667 TRACE("qname %s:%s\n", debugstr_wn(prefix
->start
, prefix
->len
), debugstr_wn(local
->start
, local
->len
));
1669 TRACE("ncname %s\n", debugstr_wn(local
->start
, local
->len
));
1671 reader_init_strvalue(prefix
->start
? prefix
->start
: local
->start
,
1673 (prefix
->len
? prefix
->len
+ 1 : 0) + local
->len
,
1676 reader
->resume
[XmlReadResume_Name
] = NULL
;
1677 reader
->resume
[XmlReadResume_Local
] = NULL
;
1682 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
1683 [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
1684 static HRESULT
reader_parse_stag(xmlreader
*reader
, strval
*prefix
, strval
*local
, strval
*qname
, int *empty
)
1686 static const WCHAR endW
[] = {'/','>',0};
1689 hr
= reader_parse_qname(reader
, prefix
, local
, qname
);
1690 if (FAILED(hr
)) return hr
;
1692 reader_skipspaces(reader
);
1695 if ((*empty
= !reader_cmp(reader
, endW
)))
1698 reader_skipn(reader
, 2);
1702 /* got a start tag */
1703 if (!reader_cmp(reader
, gtW
))
1706 reader_skipn(reader
, 1);
1707 return reader_push_element(reader
, qname
);
1710 FIXME("only empty elements/start tags without attribute list supported\n");
1714 /* [39] element ::= EmptyElemTag | STag content ETag */
1715 static HRESULT
reader_parse_element(xmlreader
*reader
)
1719 switch (reader
->resumestate
)
1721 case XmlReadResumeState_Initial
:
1722 /* check if we are really on element */
1723 if (reader_cmp(reader
, ltW
)) return S_FALSE
;
1726 reader_skipn(reader
, 1);
1728 reader_shrink(reader
);
1729 reader
->resumestate
= XmlReadResumeState_STag
;
1730 case XmlReadResumeState_STag
:
1732 strval qname
, prefix
, local
;
1735 /* this handles empty elements too */
1736 hr
= reader_parse_stag(reader
, &prefix
, &local
, &qname
, &empty
);
1737 if (FAILED(hr
)) return hr
;
1739 /* FIXME: need to check for defined namespace to reject invalid prefix,
1740 currently reject all prefixes */
1741 if (prefix
.len
) return NC_E_UNDECLAREDPREFIX
;
1743 /* if we got empty element and stack is empty go straight to Misc */
1744 if (empty
&& list_empty(&reader
->elements
))
1745 reader
->instate
= XmlReadInState_MiscEnd
;
1747 reader
->instate
= XmlReadInState_Content
;
1749 reader
->nodetype
= XmlNodeType_Element
;
1750 reader
->resumestate
= XmlReadResumeState_Initial
;
1751 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
1752 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
1762 /* [13 NS] ETag ::= '</' QName S? '>' */
1763 static HRESULT
reader_parse_endtag(xmlreader
*reader
)
1765 strval prefix
, local
, qname
;
1766 struct element
*elem
;
1770 reader_skipn(reader
, 2);
1772 hr
= reader_parse_qname(reader
, &prefix
, &local
, &qname
);
1773 if (FAILED(hr
)) return hr
;
1775 reader_skipspaces(reader
);
1777 if (reader_cmp(reader
, gtW
)) return WC_E_GREATERTHAN
;
1780 reader_skipn(reader
, 1);
1782 /* Element stack should never be empty at this point, cause we shouldn't get to
1783 content parsing if it's empty. */
1784 elem
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
1785 if (!strval_eq(&elem
->qname
, &qname
)) return WC_E_ELEMENTMATCH
;
1787 reader_pop_element(reader
);
1789 reader
->nodetype
= XmlNodeType_EndElement
;
1790 reader_set_strvalue(reader
, StringValue_LocalName
, &local
);
1791 reader_set_strvalue(reader
, StringValue_QualifiedName
, &qname
);
1796 /* [18] CDSect ::= CDStart CData CDEnd
1797 [19] CDStart ::= '<![CDATA['
1798 [20] CData ::= (Char* - (Char* ']]>' Char*))
1799 [21] CDEnd ::= ']]>' */
1800 static HRESULT
reader_parse_cdata(xmlreader
*reader
)
1804 if (reader
->resume
[XmlReadResume_Body
])
1806 start
= reader
->resume
[XmlReadResume_Body
];
1807 ptr
= reader_get_cur(reader
);
1811 /* skip markup '<![CDATA[' */
1812 reader_skipn(reader
, 9);
1813 reader_shrink(reader
);
1814 ptr
= start
= reader_get_cur(reader
);
1815 reader
->nodetype
= XmlNodeType_CDATA
;
1816 reader
->resume
[XmlReadResume_Body
] = start
;
1817 reader
->resumestate
= XmlReadResumeState_CDATA
;
1818 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
1819 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
1820 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
1825 if (*ptr
== ']' && *(ptr
+1) == ']' && *(ptr
+2) == '>')
1829 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1831 reader_skipn(reader
, 3);
1832 reader_init_strvalue(start
, ptr
-start
, &value
);
1833 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1834 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1835 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1836 reader
->resume
[XmlReadResume_Body
] = NULL
;
1837 reader
->resumestate
= XmlReadResumeState_Initial
;
1842 /* Value normalization is not fully implemented, rules are:
1844 - single '\r' -> '\n';
1845 - sequence '\r\n' -> '\n', in this case value length changes;
1847 if (*ptr
== '\r') *ptr
= '\n';
1848 reader_skipn(reader
, 1);
1856 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1857 [67] Reference ::= EntityRef | CharRef
1858 [68] EntityRef ::= '&' Name ';' */
1859 static HRESULT
reader_parse_reference(xmlreader
*reader
)
1861 FIXME("References not supported\n");
1865 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1866 static HRESULT
reader_parse_chardata(xmlreader
*reader
)
1868 FIXME("CharData not supported\n");
1872 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1873 static HRESULT
reader_parse_content(xmlreader
*reader
)
1875 static const WCHAR cdstartW
[] = {'<','!','[','C','D','A','T','A','[',0};
1876 static const WCHAR etagW
[] = {'<','/',0};
1877 static const WCHAR ampW
[] = {'&',0};
1879 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1881 switch (reader
->resumestate
)
1883 case XmlReadResumeState_CDATA
:
1884 return reader_parse_cdata(reader
);
1885 case XmlReadResumeState_Comment
:
1886 return reader_parse_comment(reader
);
1887 case XmlReadResumeState_PIBody
:
1888 case XmlReadResumeState_PITarget
:
1889 return reader_parse_pi(reader
);
1891 ERR("unknown resume state %d\n", reader
->resumestate
);
1895 reader_shrink(reader
);
1897 /* handle end tag here, it indicates end of content as well */
1898 if (!reader_cmp(reader
, etagW
))
1899 return reader_parse_endtag(reader
);
1901 if (!reader_cmp(reader
, commentW
))
1902 return reader_parse_comment(reader
);
1904 if (!reader_cmp(reader
, piW
))
1905 return reader_parse_pi(reader
);
1907 if (!reader_cmp(reader
, cdstartW
))
1908 return reader_parse_cdata(reader
);
1910 if (!reader_cmp(reader
, ampW
))
1911 return reader_parse_reference(reader
);
1913 if (!reader_cmp(reader
, ltW
))
1914 return reader_parse_element(reader
);
1916 /* what's left must be CharData */
1917 return reader_parse_chardata(reader
);
1920 static HRESULT
reader_parse_nextnode(xmlreader
*reader
)
1926 switch (reader
->instate
)
1928 /* if it's a first call for a new input we need to detect stream encoding */
1929 case XmlReadInState_Initial
:
1933 hr
= readerinput_growraw(reader
->input
);
1934 if (FAILED(hr
)) return hr
;
1936 /* try to detect encoding by BOM or data and set input code page */
1937 hr
= readerinput_detectencoding(reader
->input
, &enc
);
1938 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
1939 if (FAILED(hr
)) return hr
;
1941 /* always switch first time cause we have to put something in */
1942 readerinput_switchencoding(reader
->input
, enc
);
1944 /* parse xml declaration */
1945 hr
= reader_parse_xmldecl(reader
);
1946 if (FAILED(hr
)) return hr
;
1948 readerinput_shrinkraw(reader
->input
, -1);
1949 reader
->instate
= XmlReadInState_Misc_DTD
;
1950 if (hr
== S_OK
) return hr
;
1953 case XmlReadInState_Misc_DTD
:
1954 hr
= reader_parse_misc(reader
);
1955 if (FAILED(hr
)) return hr
;
1958 reader
->instate
= XmlReadInState_DTD
;
1962 case XmlReadInState_DTD
:
1963 hr
= reader_parse_dtd(reader
);
1964 if (FAILED(hr
)) return hr
;
1968 reader
->instate
= XmlReadInState_DTD_Misc
;
1972 reader
->instate
= XmlReadInState_Element
;
1974 case XmlReadInState_DTD_Misc
:
1975 hr
= reader_parse_misc(reader
);
1976 if (FAILED(hr
)) return hr
;
1979 reader
->instate
= XmlReadInState_Element
;
1983 case XmlReadInState_Element
:
1984 return reader_parse_element(reader
);
1985 case XmlReadInState_Content
:
1986 return reader_parse_content(reader
);
1988 FIXME("internal state %d not handled\n", reader
->instate
);
1996 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
1998 xmlreader
*This
= impl_from_IXmlReader(iface
);
2000 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2002 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
2003 IsEqualGUID(riid
, &IID_IXmlReader
))
2009 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
2011 return E_NOINTERFACE
;
2014 IXmlReader_AddRef(iface
);
2019 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
2021 xmlreader
*This
= impl_from_IXmlReader(iface
);
2022 ULONG ref
= InterlockedIncrement(&This
->ref
);
2023 TRACE("(%p)->(%d)\n", This
, ref
);
2027 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
2029 xmlreader
*This
= impl_from_IXmlReader(iface
);
2030 LONG ref
= InterlockedDecrement(&This
->ref
);
2032 TRACE("(%p)->(%d)\n", This
, ref
);
2036 IMalloc
*imalloc
= This
->imalloc
;
2037 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2038 reader_clear_attrs(This
);
2039 reader_clear_elements(This
);
2040 reader_free_strvalues(This
);
2041 reader_free(This
, This
);
2042 if (imalloc
) IMalloc_Release(imalloc
);
2048 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
2050 xmlreader
*This
= impl_from_IXmlReader(iface
);
2051 IXmlReaderInput
*readerinput
;
2054 TRACE("(%p)->(%p)\n", This
, input
);
2058 readerinput_release_stream(This
->input
);
2059 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2063 This
->line
= This
->pos
= 0;
2064 reader_clear_elements(This
);
2066 This
->resumestate
= XmlReadResumeState_Initial
;
2067 memset(This
->resume
, 0, sizeof(This
->resume
));
2069 /* just reset current input */
2072 This
->state
= XmlReadState_Initial
;
2076 /* now try IXmlReaderInput, ISequentialStream, IStream */
2077 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&readerinput
);
2080 if (readerinput
->lpVtbl
== &xmlreaderinputvtbl
)
2081 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2084 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2085 readerinput
, readerinput
->lpVtbl
);
2086 IUnknown_Release(readerinput
);
2092 if (hr
!= S_OK
|| !readerinput
)
2094 /* create IXmlReaderInput basing on supplied interface */
2095 hr
= CreateXmlReaderInputWithEncodingName(input
,
2096 NULL
, NULL
, FALSE
, NULL
, &readerinput
);
2097 if (hr
!= S_OK
) return hr
;
2098 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2101 /* set stream for supplied IXmlReaderInput */
2102 hr
= readerinput_query_for_stream(This
->input
);
2105 This
->state
= XmlReadState_Initial
;
2106 This
->instate
= XmlReadInState_Initial
;
2112 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
2114 xmlreader
*This
= impl_from_IXmlReader(iface
);
2116 TRACE("(%p %u %p)\n", This
, property
, value
);
2118 if (!value
) return E_INVALIDARG
;
2122 case XmlReaderProperty_DtdProcessing
:
2123 *value
= This
->dtdmode
;
2125 case XmlReaderProperty_ReadState
:
2126 *value
= This
->state
;
2129 FIXME("Unimplemented property (%u)\n", property
);
2136 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
2138 xmlreader
*This
= impl_from_IXmlReader(iface
);
2140 TRACE("(%p %u %lu)\n", iface
, property
, value
);
2144 case XmlReaderProperty_DtdProcessing
:
2145 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
2146 This
->dtdmode
= value
;
2149 FIXME("Unimplemented property (%u)\n", property
);
2156 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*nodetype
)
2158 xmlreader
*This
= impl_from_IXmlReader(iface
);
2159 XmlNodeType oldtype
= This
->nodetype
;
2162 TRACE("(%p)->(%p)\n", This
, nodetype
);
2164 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
2166 hr
= reader_parse_nextnode(This
);
2167 if (oldtype
== XmlNodeType_None
&& This
->nodetype
!= oldtype
)
2168 This
->state
= XmlReadState_Interactive
;
2169 if (hr
== S_OK
) *nodetype
= This
->nodetype
;
2174 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
2176 xmlreader
*This
= impl_from_IXmlReader(iface
);
2177 TRACE("(%p)->(%p)\n", This
, node_type
);
2179 /* When we're on attribute always return attribute type, container node type is kept.
2180 Note that container is not necessarily an element, and attribute doesn't mean it's
2181 an attribute in XML spec terms. */
2182 *node_type
= This
->attr
? XmlNodeType_Attribute
: This
->nodetype
;
2183 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
2186 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
2188 xmlreader
*This
= impl_from_IXmlReader(iface
);
2190 TRACE("(%p)\n", This
);
2192 if (!This
->attr_count
) return S_FALSE
;
2193 This
->attr
= LIST_ENTRY(list_head(&This
->attrs
), struct attribute
, entry
);
2197 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
2199 xmlreader
*This
= impl_from_IXmlReader(iface
);
2200 const struct list
*next
;
2202 TRACE("(%p)\n", This
);
2204 if (!This
->attr_count
) return S_FALSE
;
2207 return IXmlReader_MoveToFirstAttribute(iface
);
2209 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
2211 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
2213 return next
? S_OK
: S_FALSE
;
2216 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
2218 LPCWSTR namespaceUri
)
2220 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
2224 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
2226 xmlreader
*This
= impl_from_IXmlReader(iface
);
2228 TRACE("(%p)\n", This
);
2230 if (!This
->attr_count
) return S_FALSE
;
2235 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2237 xmlreader
*This
= impl_from_IXmlReader(iface
);
2239 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2240 *name
= This
->strvalues
[StringValue_QualifiedName
].str
;
2241 *len
= This
->strvalues
[StringValue_QualifiedName
].len
;
2245 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
,
2246 LPCWSTR
*namespaceUri
,
2247 UINT
*namespaceUri_length
)
2249 FIXME("(%p %p %p): stub\n", iface
, namespaceUri
, namespaceUri_length
);
2253 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2255 xmlreader
*This
= impl_from_IXmlReader(iface
);
2257 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2258 *name
= This
->strvalues
[StringValue_LocalName
].str
;
2259 if (len
) *len
= This
->strvalues
[StringValue_LocalName
].len
;
2263 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
,
2265 UINT
*prefix_length
)
2267 FIXME("(%p %p %p): stub\n", iface
, prefix
, prefix_length
);
2271 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
, const WCHAR
**value
, UINT
*len
)
2273 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2274 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2276 TRACE("(%p)->(%p %p)\n", reader
, value
, len
);
2280 if ((reader
->nodetype
== XmlNodeType_Comment
&& !val
->str
) || is_reader_pending(reader
))
2285 hr
= IXmlReader_Read(iface
, &type
);
2286 if (FAILED(hr
)) return hr
;
2288 /* return if still pending, partially read values are not reported */
2289 if (is_reader_pending(reader
)) return E_PENDING
;
2294 val
->str
= reader_alloc(reader
, (val
->len
+1)*sizeof(WCHAR
));
2295 if (!val
->str
) return E_OUTOFMEMORY
;
2296 memcpy(val
->str
, val
->start
, val
->len
*sizeof(WCHAR
));
2297 val
->str
[val
->len
] = 0;
2301 if (len
) *len
= val
->len
;
2305 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
, WCHAR
*buffer
, UINT chunk_size
, UINT
*read
)
2307 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2308 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2311 TRACE("(%p)->(%p %u %p)\n", reader
, buffer
, chunk_size
, read
);
2313 /* Value is already allocated, chunked reads are not possible. */
2314 if (val
->str
) return S_FALSE
;
2318 len
= min(chunk_size
, val
->len
);
2319 memcpy(buffer
, val
->start
, len
);
2322 if (read
) *read
= len
;
2328 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
2330 UINT
*baseUri_length
)
2332 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
2336 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
2338 FIXME("(%p): stub\n", iface
);
2342 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
2344 FIXME("(%p): stub\n", iface
);
2348 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
2350 xmlreader
*This
= impl_from_IXmlReader(iface
);
2352 TRACE("(%p %p)\n", This
, lineNumber
);
2354 if (!lineNumber
) return E_INVALIDARG
;
2356 *lineNumber
= This
->line
;
2361 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
2363 xmlreader
*This
= impl_from_IXmlReader(iface
);
2365 TRACE("(%p %p)\n", This
, linePosition
);
2367 if (!linePosition
) return E_INVALIDARG
;
2369 *linePosition
= This
->pos
;
2374 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
2376 xmlreader
*This
= impl_from_IXmlReader(iface
);
2378 TRACE("(%p)->(%p)\n", This
, count
);
2380 if (!count
) return E_INVALIDARG
;
2382 *count
= This
->attr_count
;
2386 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
2388 xmlreader
*This
= impl_from_IXmlReader(iface
);
2389 TRACE("(%p)->(%p)\n", This
, depth
);
2390 *depth
= This
->depth
;
2394 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
2396 FIXME("(%p): stub\n", iface
);
2400 static const struct IXmlReaderVtbl xmlreader_vtbl
=
2402 xmlreader_QueryInterface
,
2406 xmlreader_GetProperty
,
2407 xmlreader_SetProperty
,
2409 xmlreader_GetNodeType
,
2410 xmlreader_MoveToFirstAttribute
,
2411 xmlreader_MoveToNextAttribute
,
2412 xmlreader_MoveToAttributeByName
,
2413 xmlreader_MoveToElement
,
2414 xmlreader_GetQualifiedName
,
2415 xmlreader_GetNamespaceUri
,
2416 xmlreader_GetLocalName
,
2417 xmlreader_GetPrefix
,
2419 xmlreader_ReadValueChunk
,
2420 xmlreader_GetBaseUri
,
2421 xmlreader_IsDefault
,
2422 xmlreader_IsEmptyElement
,
2423 xmlreader_GetLineNumber
,
2424 xmlreader_GetLinePosition
,
2425 xmlreader_GetAttributeCount
,
2430 /** IXmlReaderInput **/
2431 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
2433 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2435 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2437 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
2438 IsEqualGUID(riid
, &IID_IUnknown
))
2444 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2446 return E_NOINTERFACE
;
2449 IUnknown_AddRef(iface
);
2454 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
2456 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2457 ULONG ref
= InterlockedIncrement(&This
->ref
);
2458 TRACE("(%p)->(%d)\n", This
, ref
);
2462 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
2464 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2465 LONG ref
= InterlockedDecrement(&This
->ref
);
2467 TRACE("(%p)->(%d)\n", This
, ref
);
2471 IMalloc
*imalloc
= This
->imalloc
;
2472 if (This
->input
) IUnknown_Release(This
->input
);
2473 if (This
->stream
) ISequentialStream_Release(This
->stream
);
2474 if (This
->buffer
) free_input_buffer(This
->buffer
);
2475 readerinput_free(This
, This
->baseuri
);
2476 readerinput_free(This
, This
);
2477 if (imalloc
) IMalloc_Release(imalloc
);
2483 static const struct IUnknownVtbl xmlreaderinputvtbl
=
2485 xmlreaderinput_QueryInterface
,
2486 xmlreaderinput_AddRef
,
2487 xmlreaderinput_Release
2490 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
2495 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
2497 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
2499 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
2504 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
2506 reader
= heap_alloc(sizeof(*reader
));
2507 if(!reader
) return E_OUTOFMEMORY
;
2509 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
2511 reader
->input
= NULL
;
2512 reader
->state
= XmlReadState_Closed
;
2513 reader
->instate
= XmlReadInState_Initial
;
2514 reader
->resumestate
= XmlReadResumeState_Initial
;
2515 reader
->dtdmode
= DtdProcessing_Prohibit
;
2516 reader
->line
= reader
->pos
= 0;
2517 reader
->imalloc
= imalloc
;
2518 if (imalloc
) IMalloc_AddRef(imalloc
);
2519 reader
->nodetype
= XmlNodeType_None
;
2520 list_init(&reader
->attrs
);
2521 reader
->attr_count
= 0;
2522 reader
->attr
= NULL
;
2523 list_init(&reader
->elements
);
2525 memset(reader
->resume
, 0, sizeof(reader
->resume
));
2527 for (i
= 0; i
< StringValue_Last
; i
++)
2528 reader
->strvalues
[i
] = strval_empty
;
2530 *obj
= &reader
->IXmlReader_iface
;
2532 TRACE("returning iface %p\n", *obj
);
2537 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
2542 IXmlReaderInput
**ppInput
)
2544 xmlreaderinput
*readerinput
;
2547 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
2548 hint
, wine_dbgstr_w(base_uri
), ppInput
);
2550 if (!stream
|| !ppInput
) return E_INVALIDARG
;
2553 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
2555 readerinput
= heap_alloc(sizeof(*readerinput
));
2556 if(!readerinput
) return E_OUTOFMEMORY
;
2558 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinputvtbl
;
2559 readerinput
->ref
= 1;
2560 readerinput
->imalloc
= imalloc
;
2561 readerinput
->stream
= NULL
;
2562 if (imalloc
) IMalloc_AddRef(imalloc
);
2563 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
2564 readerinput
->hint
= hint
;
2565 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
2566 readerinput
->pending
= 0;
2568 hr
= alloc_input_buffer(readerinput
);
2571 readerinput_free(readerinput
, readerinput
->baseuri
);
2572 readerinput_free(readerinput
, readerinput
);
2573 if (imalloc
) IMalloc_Release(imalloc
);
2576 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
2578 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
2580 TRACE("returning iface %p\n", *ppInput
);