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