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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
33 #include "xmllite_private.h"
35 #include <wine/debug.h>
36 #include <wine/list.h>
37 #include <wine/unicode.h>
39 WINE_DEFAULT_DEBUG_CHANNEL(xmllite
);
41 /* not defined in public headers */
42 DEFINE_GUID(IID_IXmlReaderInput
, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
53 XmlReadInState_Initial
,
54 XmlReadInState_XmlDecl
,
55 XmlReadInState_Misc_DTD
,
57 XmlReadInState_DTD_Misc
,
58 XmlReadInState_Element
,
59 XmlReadInState_Content
,
60 XmlReadInState_MiscEnd
61 } XmlReaderInternalState
;
63 /* This state denotes where parsing was interrupted by input problem.
64 Reader resumes parsing using this information. */
67 XmlReadResumeState_Initial
,
68 XmlReadResumeState_PITarget
,
69 XmlReadResumeState_PIBody
,
70 XmlReadResumeState_CDATA
,
71 XmlReadResumeState_Comment
,
72 XmlReadResumeState_STag
73 } XmlReaderResumeState
;
75 /* saved pointer index to resume from particular input position */
78 XmlReadResume_Name
, /* PITarget, name for NCName, prefix for QName */
79 XmlReadResume_Local
, /* local for QName */
80 XmlReadResume_Body
, /* PI body, comment text, CDATA text */
86 StringValue_LocalName
,
87 StringValue_QualifiedName
,
90 } XmlReaderStringValue
;
92 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
93 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
95 static const WCHAR dblquoteW
[] = {'\"',0};
96 static const WCHAR quoteW
[] = {'\'',0};
97 static const WCHAR ltW
[] = {'<',0};
98 static const WCHAR gtW
[] = {'>',0};
99 static const WCHAR commentW
[] = {'<','!','-','-',0};
100 static const WCHAR piW
[] = {'<','?',0};
102 struct xml_encoding_data
109 static const struct xml_encoding_data xml_encoding_map
[] = {
110 { utf16W
, XmlEncoding_UTF16
, ~0 },
111 { utf8W
, XmlEncoding_UTF8
, CP_UTF8
}
118 unsigned int allocated
;
119 unsigned int written
;
122 typedef struct input_buffer input_buffer
;
126 IXmlReaderInput IXmlReaderInput_iface
;
128 /* reference passed on IXmlReaderInput creation, is kept when input is created */
131 xml_encoding encoding
;
134 /* stream reference set after SetInput() call from reader,
135 stored as sequential stream, cause currently
136 optimizations possible with IStream aren't implemented */
137 ISequentialStream
*stream
;
138 input_buffer
*buffer
;
139 unsigned int pending
: 1;
142 static const struct IUnknownVtbl xmlreaderinputvtbl
;
144 /* Structure to hold parsed string of specific length.
146 Reader stores node value as 'start' pointer, on request
147 a null-terminated version of it is allocated.
149 To init a strval variable use reader_init_strval(),
150 to set strval as a reader value use reader_set_strval().
154 WCHAR
*start
; /* input position where value starts */
155 UINT len
; /* length in WCHARs, altered after ReadValueChunk */
156 WCHAR
*str
; /* allocated null-terminated string */
159 static WCHAR emptyW
[] = {0};
160 static const strval strval_empty
= {emptyW
, 0, emptyW
};
177 IXmlReader IXmlReader_iface
;
179 xmlreaderinput
*input
;
182 XmlReaderInternalState instate
;
183 XmlReaderResumeState resumestate
;
184 XmlNodeType nodetype
;
185 DtdProcessing dtdmode
;
186 UINT line
, pos
; /* reader position in XML stream */
187 struct list attrs
; /* attributes list for current node */
188 struct attribute
*attr
; /* current attribute */
190 struct list elements
;
191 strval strvalues
[StringValue_Last
];
193 WCHAR
*resume
[XmlReadResume_Last
]; /* pointers used to resume reader */
198 encoded_buffer utf16
;
199 encoded_buffer encoded
;
201 xmlreaderinput
*input
;
204 static inline xmlreader
*impl_from_IXmlReader(IXmlReader
*iface
)
206 return CONTAINING_RECORD(iface
, xmlreader
, IXmlReader_iface
);
209 static inline xmlreaderinput
*impl_from_IXmlReaderInput(IXmlReaderInput
*iface
)
211 return CONTAINING_RECORD(iface
, xmlreaderinput
, IXmlReaderInput_iface
);
214 static inline void *m_alloc(IMalloc
*imalloc
, size_t len
)
217 return IMalloc_Alloc(imalloc
, len
);
219 return heap_alloc(len
);
222 static inline void *m_realloc(IMalloc
*imalloc
, void *mem
, size_t len
)
225 return IMalloc_Realloc(imalloc
, mem
, len
);
227 return heap_realloc(mem
, len
);
230 static inline void m_free(IMalloc
*imalloc
, void *mem
)
233 IMalloc_Free(imalloc
, mem
);
238 /* reader memory allocation functions */
239 static inline void *reader_alloc(xmlreader
*reader
, size_t len
)
241 return m_alloc(reader
->imalloc
, len
);
244 static inline void reader_free(xmlreader
*reader
, void *mem
)
246 m_free(reader
->imalloc
, mem
);
249 static HRESULT
reader_strvaldup(xmlreader
*reader
, const strval
*src
, strval
*dest
)
253 if (src
->str
!= strval_empty
.str
)
255 dest
->str
= reader_alloc(reader
, (dest
->len
+1)*sizeof(WCHAR
));
256 if (!dest
->str
) return E_OUTOFMEMORY
;
257 memcpy(dest
->str
, src
->str
, dest
->len
*sizeof(WCHAR
));
258 dest
->str
[dest
->len
] = 0;
264 /* reader input memory allocation functions */
265 static inline void *readerinput_alloc(xmlreaderinput
*input
, size_t len
)
267 return m_alloc(input
->imalloc
, len
);
270 static inline void *readerinput_realloc(xmlreaderinput
*input
, void *mem
, size_t len
)
272 return m_realloc(input
->imalloc
, mem
, len
);
275 static inline void readerinput_free(xmlreaderinput
*input
, void *mem
)
277 m_free(input
->imalloc
, mem
);
280 static inline WCHAR
*readerinput_strdupW(xmlreaderinput
*input
, const WCHAR
*str
)
287 size
= (strlenW(str
)+1)*sizeof(WCHAR
);
288 ret
= readerinput_alloc(input
, size
);
289 if (ret
) memcpy(ret
, str
, size
);
295 static void reader_clear_attrs(xmlreader
*reader
)
297 struct attribute
*attr
, *attr2
;
298 LIST_FOR_EACH_ENTRY_SAFE(attr
, attr2
, &reader
->attrs
, struct attribute
, entry
)
300 reader_free(reader
, attr
);
302 list_init(&reader
->attrs
);
303 reader
->attr_count
= 0;
306 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
307 while we are on a node with attributes */
308 static HRESULT
reader_add_attr(xmlreader
*reader
, strval
*localname
, strval
*value
)
310 struct attribute
*attr
;
312 attr
= reader_alloc(reader
, sizeof(*attr
));
313 if (!attr
) return E_OUTOFMEMORY
;
315 attr
->localname
= *localname
;
316 attr
->value
= *value
;
317 list_add_tail(&reader
->attrs
, &attr
->entry
);
318 reader
->attr_count
++;
323 /* This one frees stored string value if needed */
324 static void reader_free_strvalued(xmlreader
*reader
, strval
*v
)
326 if (v
->str
!= strval_empty
.str
)
328 reader_free(reader
, v
->str
);
333 static inline void reader_init_strvalue(WCHAR
*str
, UINT len
, strval
*v
)
335 v
->start
= v
->str
= str
;
339 static void reader_free_strvalue(xmlreader
*reader
, XmlReaderStringValue type
)
341 reader_free_strvalued(reader
, &reader
->strvalues
[type
]);
344 static void reader_free_strvalues(xmlreader
*reader
)
347 for (type
= 0; type
< StringValue_Last
; type
++)
348 reader_free_strvalue(reader
, type
);
351 /* This helper should only be used to test if strings are the same,
352 it doesn't try to sort. */
353 static inline int strval_eq(const strval
*str1
, const strval
*str2
)
355 if (str1
->len
!= str2
->len
) return 0;
356 return !memcmp(str1
->str
, str2
->str
, str1
->len
*sizeof(WCHAR
));
359 static void reader_clear_elements(xmlreader
*reader
)
361 struct element
*elem
, *elem2
;
362 LIST_FOR_EACH_ENTRY_SAFE(elem
, elem2
, &reader
->elements
, struct element
, entry
)
364 reader_free_strvalued(reader
, &elem
->qname
);
365 reader_free(reader
, elem
);
367 list_init(&reader
->elements
);
370 static HRESULT
reader_inc_depth(xmlreader
*reader
)
372 /* FIXME: handle XmlReaderProperty_MaxElementDepth property */
377 static HRESULT
reader_push_element(xmlreader
*reader
, strval
*qname
)
379 struct element
*elem
;
382 elem
= reader_alloc(reader
, sizeof(*elem
));
383 if (!elem
) return E_OUTOFMEMORY
;
385 hr
= reader_strvaldup(reader
, qname
, &elem
->qname
);
386 if (FAILED(hr
)) return hr
;
388 if (!list_empty(&reader
->elements
))
390 hr
= reader_inc_depth(reader
);
391 if (FAILED(hr
)) return hr
;
394 list_add_head(&reader
->elements
, &elem
->entry
);
398 static void reader_pop_element(xmlreader
*reader
)
400 struct element
*elem
= LIST_ENTRY(list_head(&reader
->elements
), struct element
, entry
);
404 list_remove(&elem
->entry
);
405 reader_free_strvalued(reader
, &elem
->qname
);
406 reader_free(reader
, elem
);
410 /* Always make a copy, cause strings are supposed to be null terminated. Null pointer for 'value'
411 means node value is to be determined. */
412 static void reader_set_strvalue(xmlreader
*reader
, XmlReaderStringValue type
, const strval
*value
)
414 strval
*v
= &reader
->strvalues
[type
];
416 reader_free_strvalue(reader
, type
);
425 if (value
->str
== strval_empty
.str
)
429 if (type
== StringValue_Value
)
431 /* defer allocation for value string */
433 v
->start
= value
->start
;
438 v
->str
= reader_alloc(reader
, (value
->len
+ 1)*sizeof(WCHAR
));
439 memcpy(v
->str
, value
->start
, value
->len
*sizeof(WCHAR
));
440 v
->str
[value
->len
] = 0;
446 static inline int is_reader_pending(xmlreader
*reader
)
448 return reader
->input
->pending
;
451 static HRESULT
init_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
453 const int initial_len
= 0x2000;
454 buffer
->data
= readerinput_alloc(input
, initial_len
);
455 if (!buffer
->data
) return E_OUTOFMEMORY
;
457 memset(buffer
->data
, 0, 4);
458 buffer
->cur
= buffer
->data
;
459 buffer
->allocated
= initial_len
;
465 static void free_encoded_buffer(xmlreaderinput
*input
, encoded_buffer
*buffer
)
467 readerinput_free(input
, buffer
->data
);
470 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
472 if (encoding
== XmlEncoding_Unknown
)
474 FIXME("unsupported encoding %d\n", encoding
);
478 *cp
= xml_encoding_map
[encoding
].cp
;
483 static xml_encoding
parse_encoding_name(const WCHAR
*name
, int len
)
487 if (!name
) return XmlEncoding_Unknown
;
490 max
= sizeof(xml_encoding_map
)/sizeof(struct xml_encoding_data
) - 1;
497 c
= strncmpiW(xml_encoding_map
[n
].name
, name
, len
);
499 c
= strcmpiW(xml_encoding_map
[n
].name
, name
);
501 return xml_encoding_map
[n
].enc
;
509 return XmlEncoding_Unknown
;
512 static HRESULT
alloc_input_buffer(xmlreaderinput
*input
)
514 input_buffer
*buffer
;
517 input
->buffer
= NULL
;
519 buffer
= readerinput_alloc(input
, sizeof(*buffer
));
520 if (!buffer
) return E_OUTOFMEMORY
;
522 buffer
->input
= input
;
523 buffer
->code_page
= ~0; /* code page is unknown at this point */
524 hr
= init_encoded_buffer(input
, &buffer
->utf16
);
526 readerinput_free(input
, buffer
);
530 hr
= init_encoded_buffer(input
, &buffer
->encoded
);
532 free_encoded_buffer(input
, &buffer
->utf16
);
533 readerinput_free(input
, buffer
);
537 input
->buffer
= buffer
;
541 static void free_input_buffer(input_buffer
*buffer
)
543 free_encoded_buffer(buffer
->input
, &buffer
->encoded
);
544 free_encoded_buffer(buffer
->input
, &buffer
->utf16
);
545 readerinput_free(buffer
->input
, buffer
);
548 static void readerinput_release_stream(xmlreaderinput
*readerinput
)
550 if (readerinput
->stream
) {
551 ISequentialStream_Release(readerinput
->stream
);
552 readerinput
->stream
= NULL
;
556 /* Queries already stored interface for IStream/ISequentialStream.
557 Interface supplied on creation will be overwritten */
558 static HRESULT
readerinput_query_for_stream(xmlreaderinput
*readerinput
)
562 readerinput_release_stream(readerinput
);
563 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_IStream
, (void**)&readerinput
->stream
);
565 hr
= IUnknown_QueryInterface(readerinput
->input
, &IID_ISequentialStream
, (void**)&readerinput
->stream
);
570 /* reads a chunk to raw buffer */
571 static HRESULT
readerinput_growraw(xmlreaderinput
*readerinput
)
573 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
574 /* to make sure aligned length won't exceed allocated length */
575 ULONG len
= buffer
->allocated
- buffer
->written
- 4;
579 /* always try to get aligned to 4 bytes, so the only case we can get partially read characters is
580 variable width encodings like UTF-8 */
581 len
= (len
+ 3) & ~3;
582 /* try to use allocated space or grow */
583 if (buffer
->allocated
- buffer
->written
< len
)
585 buffer
->allocated
*= 2;
586 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, buffer
->allocated
);
587 len
= buffer
->allocated
- buffer
->written
;
591 hr
= ISequentialStream_Read(readerinput
->stream
, buffer
->data
+ buffer
->written
, len
, &read
);
592 TRACE("requested %d, read %d, ret 0x%08x\n", len
, read
, hr
);
593 readerinput
->pending
= hr
== E_PENDING
;
594 if (FAILED(hr
)) return hr
;
595 buffer
->written
+= read
;
600 /* grows UTF-16 buffer so it has at least 'length' bytes free on return */
601 static void readerinput_grow(xmlreaderinput
*readerinput
, int length
)
603 encoded_buffer
*buffer
= &readerinput
->buffer
->utf16
;
605 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
606 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
608 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
609 buffer
->data
= readerinput_realloc(readerinput
, buffer
->data
, grown_size
);
610 buffer
->allocated
= grown_size
;
614 static inline int readerinput_is_utf8(xmlreaderinput
*readerinput
)
616 static char startA
[] = {'<','?'};
617 static char commentA
[] = {'<','!'};
618 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
619 unsigned char *ptr
= (unsigned char*)buffer
->data
;
621 return !memcmp(buffer
->data
, startA
, sizeof(startA
)) ||
622 !memcmp(buffer
->data
, commentA
, sizeof(commentA
)) ||
623 /* test start byte */
626 (ptr
[1] && (ptr
[1] <= 0x7f)) ||
627 (buffer
->data
[1] >> 5) == 0x6 || /* 2 bytes */
628 (buffer
->data
[1] >> 4) == 0xe || /* 3 bytes */
629 (buffer
->data
[1] >> 3) == 0x1e) /* 4 bytes */
633 static HRESULT
readerinput_detectencoding(xmlreaderinput
*readerinput
, xml_encoding
*enc
)
635 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
636 static WCHAR startW
[] = {'<','?'};
637 static WCHAR commentW
[] = {'<','!'};
638 static char utf8bom
[] = {0xef,0xbb,0xbf};
639 static char utf16lebom
[] = {0xff,0xfe};
641 *enc
= XmlEncoding_Unknown
;
643 if (buffer
->written
<= 3)
645 HRESULT hr
= readerinput_growraw(readerinput
);
646 if (FAILED(hr
)) return hr
;
647 if (buffer
->written
<= 3) return MX_E_INPUTEND
;
650 /* try start symbols if we have enough data to do that, input buffer should contain
651 first chunk already */
652 if (readerinput_is_utf8(readerinput
))
653 *enc
= XmlEncoding_UTF8
;
654 else if (!memcmp(buffer
->data
, startW
, sizeof(startW
)) ||
655 !memcmp(buffer
->data
, commentW
, sizeof(commentW
)))
656 *enc
= XmlEncoding_UTF16
;
657 /* try with BOM now */
658 else if (!memcmp(buffer
->data
, utf8bom
, sizeof(utf8bom
)))
660 buffer
->cur
+= sizeof(utf8bom
);
661 *enc
= XmlEncoding_UTF8
;
663 else if (!memcmp(buffer
->data
, utf16lebom
, sizeof(utf16lebom
)))
665 buffer
->cur
+= sizeof(utf16lebom
);
666 *enc
= XmlEncoding_UTF16
;
672 static int readerinput_get_utf8_convlen(xmlreaderinput
*readerinput
)
674 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
675 int len
= buffer
->written
;
677 /* complete single byte char */
678 if (!(buffer
->data
[len
-1] & 0x80)) return len
;
680 /* find start byte of multibyte char */
681 while (--len
&& !(buffer
->data
[len
] & 0xc0))
687 /* Returns byte length of complete char sequence for buffer code page,
688 it's relative to current buffer position which is currently used for BOM handling
690 static int readerinput_get_convlen(xmlreaderinput
*readerinput
)
692 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
695 if (readerinput
->buffer
->code_page
== CP_UTF8
)
696 len
= readerinput_get_utf8_convlen(readerinput
);
698 len
= buffer
->written
;
700 TRACE("%d\n", len
- (int)(buffer
->cur
- buffer
->data
));
701 return len
- (buffer
->cur
- buffer
->data
);
704 /* It's possible that raw buffer has some leftovers from last conversion - some char
705 sequence that doesn't represent a full code point. Length argument should be calculated with
706 readerinput_get_convlen(), if it's -1 it will be calculated here. */
707 static void readerinput_shrinkraw(xmlreaderinput
*readerinput
, int len
)
709 encoded_buffer
*buffer
= &readerinput
->buffer
->encoded
;
712 len
= readerinput_get_convlen(readerinput
);
714 memmove(buffer
->data
, buffer
->cur
+ (buffer
->written
- len
), len
);
715 /* everything below cur is lost too */
716 buffer
->written
-= len
+ (buffer
->cur
- buffer
->data
);
717 /* after this point we don't need cur pointer really,
718 it's used only to mark where actual data begins when first chunk is read */
719 buffer
->cur
= buffer
->data
;
722 /* note that raw buffer content is kept */
723 static void readerinput_switchencoding(xmlreaderinput
*readerinput
, xml_encoding enc
)
725 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
726 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
732 hr
= get_code_page(enc
, &cp
);
733 if (FAILED(hr
)) return;
735 readerinput
->buffer
->code_page
= cp
;
736 len
= readerinput_get_convlen(readerinput
);
738 TRACE("switching to cp %d\n", cp
);
740 /* just copy in this case */
741 if (enc
== XmlEncoding_UTF16
)
743 readerinput_grow(readerinput
, len
);
744 memcpy(dest
->data
, src
->cur
, len
);
745 dest
->written
+= len
*sizeof(WCHAR
);
749 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
750 readerinput_grow(readerinput
, dest_len
);
751 ptr
= (WCHAR
*)dest
->data
;
752 MultiByteToWideChar(cp
, 0, src
->cur
, len
, ptr
, dest_len
);
754 dest
->written
+= dest_len
*sizeof(WCHAR
);
757 /* shrinks parsed data a buffer begins with */
758 static void reader_shrink(xmlreader
*reader
)
760 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
762 /* avoid to move too often using threshold shrink length */
763 if (buffer
->cur
- buffer
->data
> buffer
->written
/ 2)
765 buffer
->written
-= buffer
->cur
- buffer
->data
;
766 memmove(buffer
->data
, buffer
->cur
, buffer
->written
);
767 buffer
->cur
= buffer
->data
;
768 *(WCHAR
*)&buffer
->cur
[buffer
->written
] = 0;
772 /* This is a normal way for reader to get new data converted from raw buffer to utf16 buffer.
773 It won't attempt to shrink but will grow destination buffer if needed */
774 static HRESULT
reader_more(xmlreader
*reader
)
776 xmlreaderinput
*readerinput
= reader
->input
;
777 encoded_buffer
*src
= &readerinput
->buffer
->encoded
;
778 encoded_buffer
*dest
= &readerinput
->buffer
->utf16
;
779 UINT cp
= readerinput
->buffer
->code_page
;
784 /* get some raw data from stream first */
785 hr
= readerinput_growraw(readerinput
);
786 len
= readerinput_get_convlen(readerinput
);
788 /* just copy for UTF-16 case */
791 readerinput_grow(readerinput
, len
);
792 memcpy(dest
->data
, src
->cur
, len
);
793 dest
->written
+= len
*sizeof(WCHAR
);
797 dest_len
= MultiByteToWideChar(cp
, 0, src
->cur
, len
, NULL
, 0);
798 readerinput_grow(readerinput
, dest_len
);
799 ptr
= (WCHAR
*)dest
->data
;
800 MultiByteToWideChar(cp
, 0, src
->cur
, len
, ptr
, dest_len
);
802 dest
->written
+= dest_len
*sizeof(WCHAR
);
803 /* get rid of processed data */
804 readerinput_shrinkraw(readerinput
, len
);
809 static inline WCHAR
*reader_get_cur(xmlreader
*reader
)
811 WCHAR
*ptr
= (WCHAR
*)reader
->input
->buffer
->utf16
.cur
;
812 if (!*ptr
) reader_more(reader
);
816 static int reader_cmp(xmlreader
*reader
, const WCHAR
*str
)
818 const WCHAR
*ptr
= reader_get_cur(reader
);
819 return strncmpW(str
, ptr
, strlenW(str
));
822 /* moves cursor n WCHARs forward */
823 static void reader_skipn(xmlreader
*reader
, int n
)
825 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
826 const WCHAR
*ptr
= reader_get_cur(reader
);
828 while (*ptr
++ && n
--)
830 buffer
->cur
+= sizeof(WCHAR
);
835 static inline int is_wchar_space(WCHAR ch
)
837 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
840 /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
841 static int reader_skipspaces(xmlreader
*reader
)
843 encoded_buffer
*buffer
= &reader
->input
->buffer
->utf16
;
844 const WCHAR
*ptr
= reader_get_cur(reader
), *start
= ptr
;
846 while (is_wchar_space(*ptr
))
848 buffer
->cur
+= sizeof(WCHAR
);
851 else if (*ptr
== '\n')
864 /* [26] VersionNum ::= '1.' [0-9]+ */
865 static HRESULT
reader_parse_versionnum(xmlreader
*reader
, strval
*val
)
867 WCHAR
*ptr
, *ptr2
, *start
= reader_get_cur(reader
);
868 static const WCHAR onedotW
[] = {'1','.',0};
870 if (reader_cmp(reader
, onedotW
)) return WC_E_XMLDECL
;
872 reader_skipn(reader
, 2);
874 ptr2
= ptr
= reader_get_cur(reader
);
875 while (*ptr
>= '0' && *ptr
<= '9')
878 if (ptr2
== ptr
) return WC_E_DIGIT
;
879 TRACE("version=%s\n", debugstr_wn(start
, ptr
-start
));
880 reader_init_strvalue(start
, ptr
-start
, val
);
881 reader_skipn(reader
, ptr
-ptr2
);
885 /* [25] Eq ::= S? '=' S? */
886 static HRESULT
reader_parse_eq(xmlreader
*reader
)
888 static const WCHAR eqW
[] = {'=',0};
889 reader_skipspaces(reader
);
890 if (reader_cmp(reader
, eqW
)) return WC_E_EQUAL
;
892 reader_skipn(reader
, 1);
893 reader_skipspaces(reader
);
897 /* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */
898 static HRESULT
reader_parse_versioninfo(xmlreader
*reader
)
900 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
904 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
906 if (reader_cmp(reader
, versionW
)) return WC_E_XMLDECL
;
907 reader_init_strvalue(reader_get_cur(reader
), 7, &name
);
909 reader_skipn(reader
, 7);
911 hr
= reader_parse_eq(reader
);
912 if (FAILED(hr
)) return hr
;
914 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
917 reader_skipn(reader
, 1);
919 hr
= reader_parse_versionnum(reader
, &val
);
920 if (FAILED(hr
)) return hr
;
922 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
926 reader_skipn(reader
, 1);
928 return reader_add_attr(reader
, &name
, &val
);
931 /* ([A-Za-z0-9._] | '-') */
932 static inline int is_wchar_encname(WCHAR ch
)
934 return ((ch
>= 'A' && ch
<= 'Z') ||
935 (ch
>= 'a' && ch
<= 'z') ||
936 (ch
>= '0' && ch
<= '9') ||
937 (ch
== '.') || (ch
== '_') ||
941 /* [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* */
942 static HRESULT
reader_parse_encname(xmlreader
*reader
, strval
*val
)
944 WCHAR
*start
= reader_get_cur(reader
), *ptr
;
948 if ((*start
< 'A' || *start
> 'Z') && (*start
< 'a' || *start
> 'z'))
952 while (is_wchar_encname(*++ptr
))
956 enc
= parse_encoding_name(start
, len
);
957 TRACE("encoding name %s\n", debugstr_wn(start
, len
));
961 if (enc
== XmlEncoding_Unknown
)
964 /* skip encoding name */
965 reader_skipn(reader
, len
);
969 /* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */
970 static HRESULT
reader_parse_encdecl(xmlreader
*reader
)
972 static const WCHAR encodingW
[] = {'e','n','c','o','d','i','n','g',0};
976 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
978 if (reader_cmp(reader
, encodingW
)) return S_FALSE
;
979 name
.str
= reader_get_cur(reader
);
981 /* skip 'encoding' */
982 reader_skipn(reader
, 8);
984 hr
= reader_parse_eq(reader
);
985 if (FAILED(hr
)) return hr
;
987 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
990 reader_skipn(reader
, 1);
992 hr
= reader_parse_encname(reader
, &val
);
993 if (FAILED(hr
)) return hr
;
995 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
999 reader_skipn(reader
, 1);
1001 return reader_add_attr(reader
, &name
, &val
);
1004 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
1005 static HRESULT
reader_parse_sddecl(xmlreader
*reader
)
1007 static const WCHAR standaloneW
[] = {'s','t','a','n','d','a','l','o','n','e',0};
1008 static const WCHAR yesW
[] = {'y','e','s',0};
1009 static const WCHAR noW
[] = {'n','o',0};
1014 if (!reader_skipspaces(reader
)) return WC_E_WHITESPACE
;
1016 if (reader_cmp(reader
, standaloneW
)) return S_FALSE
;
1017 reader_init_strvalue(reader_get_cur(reader
), 10, &name
);
1018 /* skip 'standalone' */
1019 reader_skipn(reader
, 10);
1021 hr
= reader_parse_eq(reader
);
1022 if (FAILED(hr
)) return hr
;
1024 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1027 reader_skipn(reader
, 1);
1029 if (reader_cmp(reader
, yesW
) && reader_cmp(reader
, noW
))
1030 return WC_E_XMLDECL
;
1032 start
= reader_get_cur(reader
);
1033 /* skip 'yes'|'no' */
1034 reader_skipn(reader
, reader_cmp(reader
, yesW
) ? 2 : 3);
1035 ptr
= reader_get_cur(reader
);
1036 TRACE("standalone=%s\n", debugstr_wn(start
, ptr
-start
));
1038 val
.len
= ptr
-start
;
1040 if (reader_cmp(reader
, quoteW
) && reader_cmp(reader
, dblquoteW
))
1043 reader_skipn(reader
, 1);
1045 return reader_add_attr(reader
, &name
, &val
);
1048 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
1049 static HRESULT
reader_parse_xmldecl(xmlreader
*reader
)
1051 static const WCHAR xmldeclW
[] = {'<','?','x','m','l',' ',0};
1052 static const WCHAR declcloseW
[] = {'?','>',0};
1055 /* check if we have "<?xml " */
1056 if (reader_cmp(reader
, xmldeclW
)) return S_FALSE
;
1058 reader_skipn(reader
, 5);
1059 hr
= reader_parse_versioninfo(reader
);
1063 hr
= reader_parse_encdecl(reader
);
1067 hr
= reader_parse_sddecl(reader
);
1071 reader_skipspaces(reader
);
1072 if (reader_cmp(reader
, declcloseW
)) return WC_E_XMLDECL
;
1073 reader_skipn(reader
, 2);
1075 reader
->nodetype
= XmlNodeType_XmlDeclaration
;
1076 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1077 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1078 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1083 /* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */
1084 static HRESULT
reader_parse_comment(xmlreader
*reader
)
1088 if (reader
->resume
[XmlReadResume_Body
])
1090 start
= reader
->resume
[XmlReadResume_Body
];
1091 ptr
= reader_get_cur(reader
);
1096 reader_skipn(reader
, 4);
1097 reader_shrink(reader
);
1098 ptr
= start
= reader_get_cur(reader
);
1099 reader
->nodetype
= XmlNodeType_Comment
;
1100 reader
->resume
[XmlReadResume_Body
] = start
;
1101 reader
->resumestate
= XmlReadResumeState_Comment
;
1102 reader_set_strvalue(reader
, StringValue_LocalName
, NULL
);
1103 reader_set_strvalue(reader
, StringValue_QualifiedName
, NULL
);
1104 reader_set_strvalue(reader
, StringValue_Value
, NULL
);
1107 /* will exit when there's no more data, it won't attempt to
1108 read more from stream */
1119 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1121 reader_skipn(reader
, 3);
1122 reader_init_strvalue(start
, ptr
-start
, &value
);
1123 reader_set_strvalue(reader
, StringValue_LocalName
, &strval_empty
);
1124 reader_set_strvalue(reader
, StringValue_QualifiedName
, &strval_empty
);
1125 reader_set_strvalue(reader
, StringValue_Value
, &value
);
1126 reader
->resume
[XmlReadResume_Body
] = NULL
;
1127 reader
->resumestate
= XmlReadResumeState_Initial
;
1131 return WC_E_COMMENT
;
1138 reader_skipn(reader
, 1);
1146 /* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
1147 static inline int is_char(WCHAR ch
)
1149 return (ch
== '\t') || (ch
== '\r') || (ch
== '\n') ||
1150 (ch
>= 0x20 && ch
<= 0xd7ff) ||
1151 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1152 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1153 (ch
>= 0xe000 && ch
<= 0xfffd);
1156 /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
1157 static inline int is_pubchar(WCHAR ch
)
1159 return (ch
== ' ') ||
1160 (ch
>= 'a' && ch
<= 'z') ||
1161 (ch
>= 'A' && ch
<= 'Z') ||
1162 (ch
>= '0' && ch
<= '9') ||
1163 (ch
>= '-' && ch
<= ';') || /* '()*+,-./:; */
1164 (ch
== '=') || (ch
== '?') ||
1165 (ch
== '@') || (ch
== '!') ||
1166 (ch
>= '#' && ch
<= '%') || /* #$% */
1167 (ch
== '_') || (ch
== '\r') || (ch
== '\n');
1170 static inline int is_namestartchar(WCHAR ch
)
1172 return (ch
== ':') || (ch
>= 'A' && ch
<= 'Z') ||
1173 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1174 (ch
>= 0xc0 && ch
<= 0xd6) ||
1175 (ch
>= 0xd8 && ch
<= 0xf6) ||
1176 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1177 (ch
>= 0x370 && ch
<= 0x37d) ||
1178 (ch
>= 0x37f && ch
<= 0x1fff) ||
1179 (ch
>= 0x200c && ch
<= 0x200d) ||
1180 (ch
>= 0x2070 && ch
<= 0x218f) ||
1181 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1182 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1183 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1184 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1185 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1186 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1189 /* [4 NS] NCName ::= Name - (Char* ':' Char*) */
1190 static inline int is_ncnamechar(WCHAR ch
)
1192 return (ch
>= 'A' && ch
<= 'Z') ||
1193 (ch
== '_') || (ch
>= 'a' && ch
<= 'z') ||
1194 (ch
== '-') || (ch
== '.') ||
1195 (ch
>= '0' && ch
<= '9') ||
1197 (ch
>= 0xc0 && ch
<= 0xd6) ||
1198 (ch
>= 0xd8 && ch
<= 0xf6) ||
1199 (ch
>= 0xf8 && ch
<= 0x2ff) ||
1200 (ch
>= 0x300 && ch
<= 0x36f) ||
1201 (ch
>= 0x370 && ch
<= 0x37d) ||
1202 (ch
>= 0x37f && ch
<= 0x1fff) ||
1203 (ch
>= 0x200c && ch
<= 0x200d) ||
1204 (ch
>= 0x203f && ch
<= 0x2040) ||
1205 (ch
>= 0x2070 && ch
<= 0x218f) ||
1206 (ch
>= 0x2c00 && ch
<= 0x2fef) ||
1207 (ch
>= 0x3001 && ch
<= 0xd7ff) ||
1208 (ch
>= 0xd800 && ch
<= 0xdbff) || /* high surrogate */
1209 (ch
>= 0xdc00 && ch
<= 0xdfff) || /* low surrogate */
1210 (ch
>= 0xf900 && ch
<= 0xfdcf) ||
1211 (ch
>= 0xfdf0 && ch
<= 0xfffd);
1214 static inline int is_namechar(WCHAR ch
)
1216 return (ch
== ':') || is_ncnamechar(ch
);
1219 /* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
1220 [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
1221 [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
1222 [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
1223 [5] Name ::= NameStartChar (NameChar)* */
1224 static HRESULT
reader_parse_name(xmlreader
*reader
, strval
*name
)
1228 if (reader
->resume
[XmlReadResume_Name
])
1230 start
= reader
->resume
[XmlReadResume_Name
];
1231 ptr
= reader_get_cur(reader
);
1235 ptr
= start
= reader_get_cur(reader
);
1236 if (!is_namestartchar(*ptr
)) return WC_E_NAMECHARACTER
;
1239 while (is_namechar(*ptr
))
1241 reader_skipn(reader
, 1);
1242 ptr
= reader_get_cur(reader
);
1245 if (is_reader_pending(reader
))
1247 reader
->resume
[XmlReadResume_Name
] = start
;
1251 reader
->resume
[XmlReadResume_Name
] = NULL
;
1253 TRACE("name %s:%d\n", debugstr_wn(start
, ptr
-start
), (int)(ptr
-start
));
1254 reader_init_strvalue(start
, ptr
-start
, name
);
1259 /* [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */
1260 static HRESULT
reader_parse_pitarget(xmlreader
*reader
, strval
*target
)
1262 static const WCHAR xmlW
[] = {'x','m','l'};
1267 hr
= reader_parse_name(reader
, &name
);
1268 if (FAILED(hr
)) return is_reader_pending(reader
) ? E_PENDING
: WC_E_PI
;
1270 /* now that we got name check for illegal content */
1271 if (name
.len
== 3 && !strncmpiW(name
.str
, xmlW
, 3))
1272 return WC_E_LEADINGXML
;
1274 /* PITarget can't be a qualified name */
1275 for (i
= 0; i
< name
.len
; i
++)
1276 if (name
.str
[i
] == ':')
1277 return i
? NC_E_NAMECOLON
: WC_E_PI
;
1279 TRACE("pitarget %s:%d\n", debugstr_wn(name
.str
, name
.len
), name
.len
);
1284 /* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' */
1285 static HRESULT
reader_parse_pi(xmlreader
*reader
)
1291 switch (reader
->resumestate
)
1293 case XmlReadResumeState_Initial
:
1295 reader_skipn(reader
, 2);
1296 reader_shrink(reader
);
1297 reader
->resumestate
= XmlReadResumeState_PITarget
;
1298 case XmlReadResumeState_PITarget
:
1299 hr
= reader_parse_pitarget(reader
, &target
);
1300 if (FAILED(hr
)) return hr
;
1301 reader
->resumestate
= XmlReadResumeState_PIBody
;
1306 ptr
= reader_get_cur(reader
);
1307 /* exit earlier if there's no content */
1308 if (ptr
[0] == '?' && ptr
[1] == '>')
1311 reader_skipn(reader
, 2);
1312 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1313 reader
->resumestate
= XmlReadResumeState_Initial
;
1314 reader_set_strvalue(reader
, StringValue_LocalName
, &target
);
1315 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
1316 reader_set_strvalue(reader
, StringValue_Value
, &strval_empty
);
1320 if (!reader
->resume
[XmlReadResume_Body
])
1322 /* now at least a single space char should be there */
1323 if (!is_wchar_space(*ptr
)) return WC_E_WHITESPACE
;
1324 reader_skipspaces(reader
);
1325 ptr
= start
= reader_get_cur(reader
);
1326 reader
->resume
[XmlReadResume_Body
] = start
;
1330 start
= reader
->resume
[XmlReadResume_Body
];
1331 ptr
= reader_get_cur(reader
);
1342 TRACE("%s\n", debugstr_wn(start
, ptr
-start
));
1344 reader_skipn(reader
, 2);
1345 reader
->nodetype
= XmlNodeType_ProcessingInstruction
;
1346 reader
->resumestate
= XmlReadResumeState_Initial
;
1347 reader
->resume
[XmlReadResume_Body
] = NULL
;
1348 reader_init_strvalue(start
, ptr
-start
, &value
);
1349 reader_set_strvalue(reader
, StringValue_LocalName
, &target
);
1350 reader_set_strvalue(reader
, StringValue_QualifiedName
, &target
);
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 reader_skipn(reader
, 1);
1850 /* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1851 [67] Reference ::= EntityRef | CharRef
1852 [68] EntityRef ::= '&' Name ';' */
1853 static HRESULT
reader_parse_reference(xmlreader
*reader
)
1855 FIXME("References not supported\n");
1859 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
1860 static HRESULT
reader_parse_chardata(xmlreader
*reader
)
1862 FIXME("CharData not supported\n");
1866 /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
1867 static HRESULT
reader_parse_content(xmlreader
*reader
)
1869 static const WCHAR cdstartW
[] = {'<','!','[','C','D','A','T','A','[',0};
1870 static const WCHAR etagW
[] = {'<','/',0};
1871 static const WCHAR ampW
[] = {'&',0};
1873 if (reader
->resumestate
!= XmlReadResumeState_Initial
)
1875 switch (reader
->resumestate
)
1877 case XmlReadResumeState_CDATA
:
1878 return reader_parse_cdata(reader
);
1879 case XmlReadResumeState_Comment
:
1880 return reader_parse_comment(reader
);
1881 case XmlReadResumeState_PIBody
:
1882 case XmlReadResumeState_PITarget
:
1883 return reader_parse_pi(reader
);
1885 ERR("unknown resume state %d\n", reader
->resumestate
);
1889 reader_shrink(reader
);
1891 /* handle end tag here, it indicates end of content as well */
1892 if (!reader_cmp(reader
, etagW
))
1893 return reader_parse_endtag(reader
);
1895 if (!reader_cmp(reader
, commentW
))
1896 return reader_parse_comment(reader
);
1898 if (!reader_cmp(reader
, piW
))
1899 return reader_parse_pi(reader
);
1901 if (!reader_cmp(reader
, cdstartW
))
1902 return reader_parse_cdata(reader
);
1904 if (!reader_cmp(reader
, ampW
))
1905 return reader_parse_reference(reader
);
1907 if (!reader_cmp(reader
, ltW
))
1908 return reader_parse_element(reader
);
1910 /* what's left must be CharData */
1911 return reader_parse_chardata(reader
);
1914 static HRESULT
reader_parse_nextnode(xmlreader
*reader
)
1920 switch (reader
->instate
)
1922 /* if it's a first call for a new input we need to detect stream encoding */
1923 case XmlReadInState_Initial
:
1927 hr
= readerinput_growraw(reader
->input
);
1928 if (FAILED(hr
)) return hr
;
1930 /* try to detect encoding by BOM or data and set input code page */
1931 hr
= readerinput_detectencoding(reader
->input
, &enc
);
1932 TRACE("detected encoding %s, 0x%08x\n", debugstr_w(xml_encoding_map
[enc
].name
), hr
);
1933 if (FAILED(hr
)) return hr
;
1935 /* always switch first time cause we have to put something in */
1936 readerinput_switchencoding(reader
->input
, enc
);
1938 /* parse xml declaration */
1939 hr
= reader_parse_xmldecl(reader
);
1940 if (FAILED(hr
)) return hr
;
1942 readerinput_shrinkraw(reader
->input
, -1);
1943 reader
->instate
= XmlReadInState_Misc_DTD
;
1944 if (hr
== S_OK
) return hr
;
1947 case XmlReadInState_Misc_DTD
:
1948 hr
= reader_parse_misc(reader
);
1949 if (FAILED(hr
)) return hr
;
1952 reader
->instate
= XmlReadInState_DTD
;
1956 case XmlReadInState_DTD
:
1957 hr
= reader_parse_dtd(reader
);
1958 if (FAILED(hr
)) return hr
;
1962 reader
->instate
= XmlReadInState_DTD_Misc
;
1966 reader
->instate
= XmlReadInState_Element
;
1968 case XmlReadInState_DTD_Misc
:
1969 hr
= reader_parse_misc(reader
);
1970 if (FAILED(hr
)) return hr
;
1973 reader
->instate
= XmlReadInState_Element
;
1977 case XmlReadInState_Element
:
1978 return reader_parse_element(reader
);
1979 case XmlReadInState_Content
:
1980 return reader_parse_content(reader
);
1982 FIXME("internal state %d not handled\n", reader
->instate
);
1990 static HRESULT WINAPI
xmlreader_QueryInterface(IXmlReader
*iface
, REFIID riid
, void** ppvObject
)
1992 xmlreader
*This
= impl_from_IXmlReader(iface
);
1994 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1996 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1997 IsEqualGUID(riid
, &IID_IXmlReader
))
2003 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
2005 return E_NOINTERFACE
;
2008 IXmlReader_AddRef(iface
);
2013 static ULONG WINAPI
xmlreader_AddRef(IXmlReader
*iface
)
2015 xmlreader
*This
= impl_from_IXmlReader(iface
);
2016 ULONG ref
= InterlockedIncrement(&This
->ref
);
2017 TRACE("(%p)->(%d)\n", This
, ref
);
2021 static ULONG WINAPI
xmlreader_Release(IXmlReader
*iface
)
2023 xmlreader
*This
= impl_from_IXmlReader(iface
);
2024 LONG ref
= InterlockedDecrement(&This
->ref
);
2026 TRACE("(%p)->(%d)\n", This
, ref
);
2030 IMalloc
*imalloc
= This
->imalloc
;
2031 if (This
->input
) IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2032 reader_clear_attrs(This
);
2033 reader_clear_elements(This
);
2034 reader_free_strvalues(This
);
2035 reader_free(This
, This
);
2036 if (imalloc
) IMalloc_Release(imalloc
);
2042 static HRESULT WINAPI
xmlreader_SetInput(IXmlReader
* iface
, IUnknown
*input
)
2044 xmlreader
*This
= impl_from_IXmlReader(iface
);
2045 IXmlReaderInput
*readerinput
;
2048 TRACE("(%p)->(%p)\n", This
, input
);
2052 readerinput_release_stream(This
->input
);
2053 IUnknown_Release(&This
->input
->IXmlReaderInput_iface
);
2057 This
->line
= This
->pos
= 0;
2058 reader_clear_elements(This
);
2060 This
->resumestate
= XmlReadResumeState_Initial
;
2061 memset(This
->resume
, 0, sizeof(This
->resume
));
2063 /* just reset current input */
2066 This
->state
= XmlReadState_Initial
;
2070 /* now try IXmlReaderInput, ISequentialStream, IStream */
2071 hr
= IUnknown_QueryInterface(input
, &IID_IXmlReaderInput
, (void**)&readerinput
);
2074 if (readerinput
->lpVtbl
== &xmlreaderinputvtbl
)
2075 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2078 ERR("got external IXmlReaderInput implementation: %p, vtbl=%p\n",
2079 readerinput
, readerinput
->lpVtbl
);
2080 IUnknown_Release(readerinput
);
2086 if (hr
!= S_OK
|| !readerinput
)
2088 /* create IXmlReaderInput basing on supplied interface */
2089 hr
= CreateXmlReaderInputWithEncodingName(input
,
2090 NULL
, NULL
, FALSE
, NULL
, &readerinput
);
2091 if (hr
!= S_OK
) return hr
;
2092 This
->input
= impl_from_IXmlReaderInput(readerinput
);
2095 /* set stream for supplied IXmlReaderInput */
2096 hr
= readerinput_query_for_stream(This
->input
);
2099 This
->state
= XmlReadState_Initial
;
2100 This
->instate
= XmlReadInState_Initial
;
2106 static HRESULT WINAPI
xmlreader_GetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR
*value
)
2108 xmlreader
*This
= impl_from_IXmlReader(iface
);
2110 TRACE("(%p %u %p)\n", This
, property
, value
);
2112 if (!value
) return E_INVALIDARG
;
2116 case XmlReaderProperty_DtdProcessing
:
2117 *value
= This
->dtdmode
;
2119 case XmlReaderProperty_ReadState
:
2120 *value
= This
->state
;
2123 FIXME("Unimplemented property (%u)\n", property
);
2130 static HRESULT WINAPI
xmlreader_SetProperty(IXmlReader
* iface
, UINT property
, LONG_PTR value
)
2132 xmlreader
*This
= impl_from_IXmlReader(iface
);
2134 TRACE("(%p %u %lu)\n", iface
, property
, value
);
2138 case XmlReaderProperty_DtdProcessing
:
2139 if (value
< 0 || value
> _DtdProcessing_Last
) return E_INVALIDARG
;
2140 This
->dtdmode
= value
;
2143 FIXME("Unimplemented property (%u)\n", property
);
2150 static HRESULT WINAPI
xmlreader_Read(IXmlReader
* iface
, XmlNodeType
*nodetype
)
2152 xmlreader
*This
= impl_from_IXmlReader(iface
);
2153 XmlNodeType oldtype
= This
->nodetype
;
2156 TRACE("(%p)->(%p)\n", This
, nodetype
);
2158 if (This
->state
== XmlReadState_Closed
) return S_FALSE
;
2160 hr
= reader_parse_nextnode(This
);
2161 if (oldtype
== XmlNodeType_None
&& This
->nodetype
!= oldtype
)
2162 This
->state
= XmlReadState_Interactive
;
2163 if (hr
== S_OK
) *nodetype
= This
->nodetype
;
2168 static HRESULT WINAPI
xmlreader_GetNodeType(IXmlReader
* iface
, XmlNodeType
*node_type
)
2170 xmlreader
*This
= impl_from_IXmlReader(iface
);
2171 TRACE("(%p)->(%p)\n", This
, node_type
);
2173 /* When we're on attribute always return attribute type, container node type is kept.
2174 Note that container is not necessarily an element, and attribute doesn't mean it's
2175 an attribute in XML spec terms. */
2176 *node_type
= This
->attr
? XmlNodeType_Attribute
: This
->nodetype
;
2177 return This
->state
== XmlReadState_Closed
? S_FALSE
: S_OK
;
2180 static HRESULT WINAPI
xmlreader_MoveToFirstAttribute(IXmlReader
* iface
)
2182 xmlreader
*This
= impl_from_IXmlReader(iface
);
2184 TRACE("(%p)\n", This
);
2186 if (!This
->attr_count
) return S_FALSE
;
2187 This
->attr
= LIST_ENTRY(list_head(&This
->attrs
), struct attribute
, entry
);
2191 static HRESULT WINAPI
xmlreader_MoveToNextAttribute(IXmlReader
* iface
)
2193 xmlreader
*This
= impl_from_IXmlReader(iface
);
2194 const struct list
*next
;
2196 TRACE("(%p)\n", This
);
2198 if (!This
->attr_count
) return S_FALSE
;
2201 return IXmlReader_MoveToFirstAttribute(iface
);
2203 next
= list_next(&This
->attrs
, &This
->attr
->entry
);
2205 This
->attr
= LIST_ENTRY(next
, struct attribute
, entry
);
2207 return next
? S_OK
: S_FALSE
;
2210 static HRESULT WINAPI
xmlreader_MoveToAttributeByName(IXmlReader
* iface
,
2212 LPCWSTR namespaceUri
)
2214 FIXME("(%p %p %p): stub\n", iface
, local_name
, namespaceUri
);
2218 static HRESULT WINAPI
xmlreader_MoveToElement(IXmlReader
* iface
)
2220 xmlreader
*This
= impl_from_IXmlReader(iface
);
2222 TRACE("(%p)\n", This
);
2224 if (!This
->attr_count
) return S_FALSE
;
2229 static HRESULT WINAPI
xmlreader_GetQualifiedName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2231 xmlreader
*This
= impl_from_IXmlReader(iface
);
2233 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2234 *name
= This
->strvalues
[StringValue_QualifiedName
].str
;
2235 *len
= This
->strvalues
[StringValue_QualifiedName
].len
;
2239 static HRESULT WINAPI
xmlreader_GetNamespaceUri(IXmlReader
* iface
,
2240 LPCWSTR
*namespaceUri
,
2241 UINT
*namespaceUri_length
)
2243 FIXME("(%p %p %p): stub\n", iface
, namespaceUri
, namespaceUri_length
);
2247 static HRESULT WINAPI
xmlreader_GetLocalName(IXmlReader
* iface
, LPCWSTR
*name
, UINT
*len
)
2249 xmlreader
*This
= impl_from_IXmlReader(iface
);
2251 TRACE("(%p)->(%p %p)\n", This
, name
, len
);
2252 *name
= This
->strvalues
[StringValue_LocalName
].str
;
2253 *len
= This
->strvalues
[StringValue_LocalName
].len
;
2257 static HRESULT WINAPI
xmlreader_GetPrefix(IXmlReader
* iface
,
2259 UINT
*prefix_length
)
2261 FIXME("(%p %p %p): stub\n", iface
, prefix
, prefix_length
);
2265 static HRESULT WINAPI
xmlreader_GetValue(IXmlReader
* iface
, const WCHAR
**value
, UINT
*len
)
2267 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2268 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2270 TRACE("(%p)->(%p %p)\n", reader
, value
, len
);
2274 if ((reader
->nodetype
== XmlNodeType_Comment
&& !val
->str
) || is_reader_pending(reader
))
2279 hr
= IXmlReader_Read(iface
, &type
);
2280 if (FAILED(hr
)) return hr
;
2282 /* return if still pending, partially read values are not reported */
2283 if (is_reader_pending(reader
)) return E_PENDING
;
2288 val
->str
= reader_alloc(reader
, (val
->len
+1)*sizeof(WCHAR
));
2289 if (!val
->str
) return E_OUTOFMEMORY
;
2290 memcpy(val
->str
, val
->start
, val
->len
*sizeof(WCHAR
));
2291 val
->str
[val
->len
] = 0;
2295 if (len
) *len
= val
->len
;
2299 static HRESULT WINAPI
xmlreader_ReadValueChunk(IXmlReader
* iface
, WCHAR
*buffer
, UINT chunk_size
, UINT
*read
)
2301 xmlreader
*reader
= impl_from_IXmlReader(iface
);
2302 strval
*val
= &reader
->strvalues
[StringValue_Value
];
2305 TRACE("(%p)->(%p %u %p)\n", reader
, buffer
, chunk_size
, read
);
2307 /* Value is already allocated, chunked reads are not possible. */
2308 if (val
->str
) return S_FALSE
;
2312 len
= min(chunk_size
, val
->len
);
2313 memcpy(buffer
, val
->start
, len
);
2316 if (read
) *read
= len
;
2322 static HRESULT WINAPI
xmlreader_GetBaseUri(IXmlReader
* iface
,
2324 UINT
*baseUri_length
)
2326 FIXME("(%p %p %p): stub\n", iface
, baseUri
, baseUri_length
);
2330 static BOOL WINAPI
xmlreader_IsDefault(IXmlReader
* iface
)
2332 FIXME("(%p): stub\n", iface
);
2336 static BOOL WINAPI
xmlreader_IsEmptyElement(IXmlReader
* iface
)
2338 FIXME("(%p): stub\n", iface
);
2342 static HRESULT WINAPI
xmlreader_GetLineNumber(IXmlReader
* iface
, UINT
*lineNumber
)
2344 xmlreader
*This
= impl_from_IXmlReader(iface
);
2346 TRACE("(%p %p)\n", This
, lineNumber
);
2348 if (!lineNumber
) return E_INVALIDARG
;
2350 *lineNumber
= This
->line
;
2355 static HRESULT WINAPI
xmlreader_GetLinePosition(IXmlReader
* iface
, UINT
*linePosition
)
2357 xmlreader
*This
= impl_from_IXmlReader(iface
);
2359 TRACE("(%p %p)\n", This
, linePosition
);
2361 if (!linePosition
) return E_INVALIDARG
;
2363 *linePosition
= This
->pos
;
2368 static HRESULT WINAPI
xmlreader_GetAttributeCount(IXmlReader
* iface
, UINT
*count
)
2370 xmlreader
*This
= impl_from_IXmlReader(iface
);
2372 TRACE("(%p)->(%p)\n", This
, count
);
2374 if (!count
) return E_INVALIDARG
;
2376 *count
= This
->attr_count
;
2380 static HRESULT WINAPI
xmlreader_GetDepth(IXmlReader
* iface
, UINT
*depth
)
2382 xmlreader
*This
= impl_from_IXmlReader(iface
);
2383 TRACE("(%p)->(%p)\n", This
, depth
);
2384 *depth
= This
->depth
;
2388 static BOOL WINAPI
xmlreader_IsEOF(IXmlReader
* iface
)
2390 FIXME("(%p): stub\n", iface
);
2394 static const struct IXmlReaderVtbl xmlreader_vtbl
=
2396 xmlreader_QueryInterface
,
2400 xmlreader_GetProperty
,
2401 xmlreader_SetProperty
,
2403 xmlreader_GetNodeType
,
2404 xmlreader_MoveToFirstAttribute
,
2405 xmlreader_MoveToNextAttribute
,
2406 xmlreader_MoveToAttributeByName
,
2407 xmlreader_MoveToElement
,
2408 xmlreader_GetQualifiedName
,
2409 xmlreader_GetNamespaceUri
,
2410 xmlreader_GetLocalName
,
2411 xmlreader_GetPrefix
,
2413 xmlreader_ReadValueChunk
,
2414 xmlreader_GetBaseUri
,
2415 xmlreader_IsDefault
,
2416 xmlreader_IsEmptyElement
,
2417 xmlreader_GetLineNumber
,
2418 xmlreader_GetLinePosition
,
2419 xmlreader_GetAttributeCount
,
2424 /** IXmlReaderInput **/
2425 static HRESULT WINAPI
xmlreaderinput_QueryInterface(IXmlReaderInput
*iface
, REFIID riid
, void** ppvObject
)
2427 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2429 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
2431 if (IsEqualGUID(riid
, &IID_IXmlReaderInput
) ||
2432 IsEqualGUID(riid
, &IID_IUnknown
))
2438 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2440 return E_NOINTERFACE
;
2443 IUnknown_AddRef(iface
);
2448 static ULONG WINAPI
xmlreaderinput_AddRef(IXmlReaderInput
*iface
)
2450 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2451 ULONG ref
= InterlockedIncrement(&This
->ref
);
2452 TRACE("(%p)->(%d)\n", This
, ref
);
2456 static ULONG WINAPI
xmlreaderinput_Release(IXmlReaderInput
*iface
)
2458 xmlreaderinput
*This
= impl_from_IXmlReaderInput(iface
);
2459 LONG ref
= InterlockedDecrement(&This
->ref
);
2461 TRACE("(%p)->(%d)\n", This
, ref
);
2465 IMalloc
*imalloc
= This
->imalloc
;
2466 if (This
->input
) IUnknown_Release(This
->input
);
2467 if (This
->stream
) ISequentialStream_Release(This
->stream
);
2468 if (This
->buffer
) free_input_buffer(This
->buffer
);
2469 readerinput_free(This
, This
->baseuri
);
2470 readerinput_free(This
, This
);
2471 if (imalloc
) IMalloc_Release(imalloc
);
2477 static const struct IUnknownVtbl xmlreaderinputvtbl
=
2479 xmlreaderinput_QueryInterface
,
2480 xmlreaderinput_AddRef
,
2481 xmlreaderinput_Release
2484 HRESULT WINAPI
CreateXmlReader(REFIID riid
, void **obj
, IMalloc
*imalloc
)
2489 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
2491 if (!IsEqualGUID(riid
, &IID_IXmlReader
))
2493 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
2498 reader
= IMalloc_Alloc(imalloc
, sizeof(*reader
));
2500 reader
= heap_alloc(sizeof(*reader
));
2501 if(!reader
) return E_OUTOFMEMORY
;
2503 reader
->IXmlReader_iface
.lpVtbl
= &xmlreader_vtbl
;
2505 reader
->input
= NULL
;
2506 reader
->state
= XmlReadState_Closed
;
2507 reader
->instate
= XmlReadInState_Initial
;
2508 reader
->resumestate
= XmlReadResumeState_Initial
;
2509 reader
->dtdmode
= DtdProcessing_Prohibit
;
2510 reader
->line
= reader
->pos
= 0;
2511 reader
->imalloc
= imalloc
;
2512 if (imalloc
) IMalloc_AddRef(imalloc
);
2513 reader
->nodetype
= XmlNodeType_None
;
2514 list_init(&reader
->attrs
);
2515 reader
->attr_count
= 0;
2516 reader
->attr
= NULL
;
2517 list_init(&reader
->elements
);
2519 memset(reader
->resume
, 0, sizeof(reader
->resume
));
2521 for (i
= 0; i
< StringValue_Last
; i
++)
2522 reader
->strvalues
[i
] = strval_empty
;
2524 *obj
= &reader
->IXmlReader_iface
;
2526 TRACE("returning iface %p\n", *obj
);
2531 HRESULT WINAPI
CreateXmlReaderInputWithEncodingName(IUnknown
*stream
,
2536 IXmlReaderInput
**ppInput
)
2538 xmlreaderinput
*readerinput
;
2541 TRACE("%p %p %s %d %s %p\n", stream
, imalloc
, wine_dbgstr_w(encoding
),
2542 hint
, wine_dbgstr_w(base_uri
), ppInput
);
2544 if (!stream
|| !ppInput
) return E_INVALIDARG
;
2547 readerinput
= IMalloc_Alloc(imalloc
, sizeof(*readerinput
));
2549 readerinput
= heap_alloc(sizeof(*readerinput
));
2550 if(!readerinput
) return E_OUTOFMEMORY
;
2552 readerinput
->IXmlReaderInput_iface
.lpVtbl
= &xmlreaderinputvtbl
;
2553 readerinput
->ref
= 1;
2554 readerinput
->imalloc
= imalloc
;
2555 readerinput
->stream
= NULL
;
2556 if (imalloc
) IMalloc_AddRef(imalloc
);
2557 readerinput
->encoding
= parse_encoding_name(encoding
, -1);
2558 readerinput
->hint
= hint
;
2559 readerinput
->baseuri
= readerinput_strdupW(readerinput
, base_uri
);
2560 readerinput
->pending
= 0;
2562 hr
= alloc_input_buffer(readerinput
);
2565 readerinput_free(readerinput
, readerinput
->baseuri
);
2566 readerinput_free(readerinput
, readerinput
);
2567 if (imalloc
) IMalloc_Release(imalloc
);
2570 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&readerinput
->input
);
2572 *ppInput
= &readerinput
->IXmlReaderInput_iface
;
2574 TRACE("returning iface %p\n", *ppInput
);