Nikolay Sivov : xmllite: Implement end tag parsing.
Alexandre Julliard
julliard at winehq.org
Tue Jan 22 14:52:21 CST 2013
Module: wine
Branch: master
Commit: fad7e7a011c187ee48f59372bdc4e6475c60531b
URL: http://source.winehq.org/git/wine.git/?a=commit;h=fad7e7a011c187ee48f59372bdc4e6475c60531b
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue Jan 22 13:11:51 2013 +0400
xmllite: Implement end tag parsing.
---
dlls/xmllite/reader.c | 60 ++++++++++++++++++++++++++++++++++++++++---
dlls/xmllite/tests/reader.c | 52 +++++++++++++++++++++++++++++++++++-
2 files changed, 106 insertions(+), 6 deletions(-)
diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index e0e6542..647af24 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -69,6 +69,7 @@ static const WCHAR utf8W[] = {'U','T','F','-','8',0};
static const WCHAR dblquoteW[] = {'\"',0};
static const WCHAR quoteW[] = {'\'',0};
+static const WCHAR gtW[] = {'>',0};
struct xml_encoding_data
{
@@ -299,6 +300,14 @@ static void reader_free_strvalues(xmlreader *reader)
reader_free_strvalue(reader, type);
}
+/* This helper should only be used to test if strings are the same,
+ it doesn't try to sort. */
+static inline int strval_eq(const strval *str1, const strval *str2)
+{
+ if (str1->len != str2->len) return 0;
+ return !memcmp(str1->str, str2->str, str1->len*sizeof(WCHAR));
+}
+
static void reader_clear_elements(xmlreader *reader)
{
struct element *elem, *elem2;
@@ -338,6 +347,18 @@ static HRESULT reader_push_element(xmlreader *reader, strval *qname)
return hr;
}
+static void reader_pop_element(xmlreader *reader)
+{
+ struct element *elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
+
+ if (elem)
+ {
+ list_remove(&elem->entry);
+ reader_free_strvalued(reader, &elem->qname);
+ reader_free(reader, elem);
+ }
+}
+
/* always make a copy, cause strings are supposed to be null terminated */
static void reader_set_strvalue(xmlreader *reader, XmlReaderStringValue type, const strval *value)
{
@@ -1465,7 +1486,6 @@ static HRESULT reader_parse_qname(xmlreader *reader, strval *prefix, strval *loc
static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *local, strval *qname, int *empty)
{
static const WCHAR endW[] = {'/','>',0};
- static const WCHAR gtW[] = {'>',0};
HRESULT hr;
/* skip '<' */
@@ -1477,7 +1497,12 @@ static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *loca
reader_skipspaces(reader);
/* empty element */
- if ((*empty = !reader_cmp(reader, endW))) return S_OK;
+ if ((*empty = !reader_cmp(reader, endW)))
+ {
+ /* skip '/>' */
+ reader_skipn(reader, 2);
+ return S_OK;
+ }
/* got a start tag */
if (!reader_cmp(reader, gtW))
@@ -1528,8 +1553,35 @@ static HRESULT reader_parse_element(xmlreader *reader)
/* [13 NS] ETag ::= '</' QName S? '>' */
static HRESULT reader_parse_endtag(xmlreader *reader)
{
- FIXME("ETag parsing not implemented\n");
- return E_NOTIMPL;
+ strval prefix, local, qname;
+ struct element *elem;
+ HRESULT hr;
+
+ /* skip '</' */
+ reader_skipn(reader, 2);
+
+ hr = reader_parse_qname(reader, &prefix, &local, &qname);
+ if (FAILED(hr)) return hr;
+
+ reader_skipspaces(reader);
+
+ if (reader_cmp(reader, gtW)) return WC_E_GREATERTHAN;
+
+ /* skip '>' */
+ reader_skipn(reader, 1);
+
+ /* Element stack should never be empty at this point, cause we shouldn't get to
+ content parsing if it's empty. */
+ elem = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
+ if (!strval_eq(&elem->qname, &qname)) return WC_E_ELEMENTMATCH;
+
+ reader_pop_element(reader);
+
+ reader->nodetype = XmlNodeType_EndElement;
+ reader_set_strvalue(reader, StringValue_LocalName, &local);
+ reader_set_strvalue(reader, StringValue_QualifiedName, &qname);
+
+ return S_OK;
}
/* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c
index 8a1f3f7..babb1c9 100644
--- a/dlls/xmllite/tests/reader.c
+++ b/dlls/xmllite/tests/reader.c
@@ -888,6 +888,8 @@ static const char misc_test_xml[] =
" \t \r \n"
"<!-- comment4 -->"
"<a>"
+ "<b/>"
+ "</a>"
;
static struct nodes_test misc_test = {
@@ -900,6 +902,8 @@ static struct nodes_test misc_test = {
XmlNodeType_Whitespace,
XmlNodeType_Comment,
XmlNodeType_Element,
+ XmlNodeType_Element,
+ XmlNodeType_EndElement,
XmlNodeType_None
}
};
@@ -1032,13 +1036,15 @@ static struct test_entry element_tests[] = {
{ "<a>", "a", "", S_OK },
{ "<a >", "a", "", S_OK },
{ "<a \r \t\n>", "a", "", S_OK },
+ { "</a>", NULL, NULL, NC_E_QNAMECHARACTER },
{ NULL }
};
static void test_read_element(void)
{
struct test_entry *test = element_tests;
- static const char stag[] = "<a><b>";
+ static const char stag[] = "<a><b></b></a>";
+ static const char mismatch[] = "<a></b>";
IXmlReader *reader;
XmlNodeType type;
IStream *stream;
@@ -1090,7 +1096,8 @@ static void test_read_element(void)
test++;
}
- stream = create_stream_on_data(stag, strlen(stag)+1);
+ /* test reader depth increment */
+ stream = create_stream_on_data(stag, sizeof(stag));
hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
ok(hr == S_OK, "got %08x\n", hr);
@@ -1115,6 +1122,47 @@ static void test_read_element(void)
ok(hr == S_OK, "got %08x\n", hr);
ok(depth == 1, "got %d\n", depth);
+ /* read end tag for inner element */
+ type = XmlNodeType_None;
+ hr = IXmlReader_Read(reader, &type);
+ ok(hr == S_OK, "got %08x\n", hr);
+ ok(type == XmlNodeType_EndElement, "got %d\n", type);
+
+ depth = 0;
+ hr = IXmlReader_GetDepth(reader, &depth);
+ ok(hr == S_OK, "got %08x\n", hr);
+todo_wine
+ ok(depth == 2, "got %d\n", depth);
+
+ /* read end tag for container element */
+ type = XmlNodeType_None;
+ hr = IXmlReader_Read(reader, &type);
+ ok(hr == S_OK, "got %08x\n", hr);
+ ok(type == XmlNodeType_EndElement, "got %d\n", type);
+
+ depth = 0;
+ hr = IXmlReader_GetDepth(reader, &depth);
+ ok(hr == S_OK, "got %08x\n", hr);
+ ok(depth == 1, "got %d\n", depth);
+
+ IStream_Release(stream);
+
+ /* start/end tag mismatch */
+ stream = create_stream_on_data(mismatch, sizeof(mismatch));
+ hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
+ ok(hr == S_OK, "got %08x\n", hr);
+
+ type = XmlNodeType_None;
+ hr = IXmlReader_Read(reader, &type);
+ ok(hr == S_OK, "got %08x\n", hr);
+ ok(type == XmlNodeType_Element, "got %d\n", type);
+
+ type = XmlNodeType_Element;
+ hr = IXmlReader_Read(reader, &type);
+ ok(hr == WC_E_ELEMENTMATCH, "got %08x\n", hr);
+todo_wine
+ ok(type == XmlNodeType_None, "got %d\n", type);
+
IStream_Release(stream);
IXmlReader_Release(reader);
More information about the wine-cvs
mailing list