Nikolay Sivov : xmllite: Initial implementation of attribute parsing.

Alexandre Julliard julliard at winehq.org
Tue Jul 30 14:14:22 CDT 2013


Module: wine
Branch: master
Commit: 53f72826a21b25df6ebf3b34a2dcbe0f3aabcba8
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=53f72826a21b25df6ebf3b34a2dcbe0f3aabcba8

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Tue Jul 30 14:59:28 2013 +0400

xmllite: Initial implementation of attribute parsing.

---

 dlls/xmllite/reader.c       |  137 ++++++++++++++++++++++++++++++++++---------
 dlls/xmllite/tests/reader.c |   88 +++++++++++++++++++++++++++
 2 files changed, 198 insertions(+), 27 deletions(-)

diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index b556d7d..38d539d 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -1757,37 +1757,129 @@ static HRESULT reader_parse_qname(xmlreader *reader, strval *prefix, strval *loc
     return S_OK;
 }
 
+/* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+   [67] Reference ::= EntityRef | CharRef
+   [68] EntityRef ::= '&' Name ';' */
+static HRESULT reader_parse_reference(xmlreader *reader)
+{
+    FIXME("References not supported\n");
+    return E_NOTIMPL;
+}
+
+/* [10 NS] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" */
+static HRESULT reader_parse_attvalue(xmlreader *reader, strval *value)
+{
+    WCHAR *ptr, *start;
+    WCHAR quote;
+
+    ptr = reader_get_cur(reader);
+
+    /* skip opening quote */
+    quote = *ptr;
+    if (quote != '\"' && quote != '\'') return WC_E_QUOTE;
+    reader_skipn(reader, 1);
+
+    start = ptr = reader_get_cur(reader);
+    while (*ptr)
+    {
+        if (*ptr == '<') return WC_E_LESSTHAN;
+
+        if (*ptr == quote)
+        {
+            /* skip closing quote */
+            reader_skipn(reader, 1);
+            break;
+        }
+
+        if (*ptr == '&')
+        {
+            HRESULT hr = reader_parse_reference(reader);
+            if (FAILED(hr)) return hr;
+        }
+        else
+            reader_skipn(reader, 1);
+        ptr = reader_get_cur(reader);
+    }
+
+    reader_init_strvalue(start, ptr-start, value);
+
+    return S_OK;
+}
+
+/* [1  NS] NSAttName ::= PrefixedAttName | DefaultAttName
+   [2  NS] PrefixedAttName ::= 'xmlns:' NCName
+   [3  NS] DefaultAttName  ::= 'xmlns'
+   [15 NS] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue */
+static HRESULT reader_parse_attribute(xmlreader *reader)
+{
+    static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
+    strval prefix, local, qname, xmlns, value;
+    HRESULT hr;
+
+    hr = reader_parse_qname(reader, &prefix, &local, &qname);
+    if (FAILED(hr)) return hr;
+
+    reader_init_strvalue((WCHAR*)xmlnsW, 5, &xmlns);
+
+    if (strval_eq(&prefix, &xmlns))
+    {
+        FIXME("namespace definitions not supported\n");
+        return E_NOTIMPL;
+    }
+
+    if (strval_eq(&qname, &xmlns))
+    {
+        FIXME("default namespace definitions not supported\n");
+        return E_NOTIMPL;
+    }
+
+    hr = reader_parse_eq(reader);
+    if (FAILED(hr)) return hr;
+
+    hr = reader_parse_attvalue(reader, &value);
+    if (FAILED(hr)) return hr;
+
+    TRACE("%s=\"%s\"\n", debugstr_wn(local.str, local.len), debugstr_wn(value.str, value.len));
+    return reader_add_attr(reader, &local, &value);
+}
+
 /* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
    [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
 static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *local, strval *qname, int *empty)
 {
-    static const WCHAR endW[] = {'/','>',0};
     HRESULT hr;
 
     hr = reader_parse_qname(reader, prefix, local, qname);
     if (FAILED(hr)) return hr;
 
-    reader_skipspaces(reader);
-
-    /* empty element */
-    if ((*empty = !reader_cmp(reader, endW)))
+    while (1)
     {
-        /* skip '/>' */
-        reader_skipn(reader, 2);
-        reader->empty_element = TRUE;
-        return S_OK;
-    }
+        static const WCHAR endW[] = {'/','>',0};
 
-    /* got a start tag */
-    if (!reader_cmp(reader, gtW))
-    {
-        /* skip '>' */
-        reader_skipn(reader, 1);
-        return reader_push_element(reader, qname);
+        reader_skipspaces(reader);
+
+        /* empty element */
+        if ((*empty = !reader_cmp(reader, endW)))
+        {
+            /* skip '/>' */
+            reader_skipn(reader, 2);
+            reader->empty_element = TRUE;
+            return S_OK;
+        }
+
+        /* got a start tag */
+        if (!reader_cmp(reader, gtW))
+        {
+            /* skip '>' */
+            reader_skipn(reader, 1);
+            return reader_push_element(reader, qname);
+        }
+
+        hr = reader_parse_attribute(reader);
+        if (FAILED(hr)) return hr;
     }
 
-    FIXME("only empty elements/start tags without attribute list supported\n");
-    return E_NOTIMPL;
+    return S_OK;
 }
 
 /* [39] element ::= EmptyElemTag | STag content ETag */
@@ -1937,15 +2029,6 @@ static HRESULT reader_parse_cdata(xmlreader *reader)
     return S_OK;
 }
 
-/* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
-   [67]	Reference ::= EntityRef | CharRef
-   [68]	EntityRef ::= '&' Name ';' */
-static HRESULT reader_parse_reference(xmlreader *reader)
-{
-    FIXME("References not supported\n");
-    return E_NOTIMPL;
-}
-
 /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
 static HRESULT reader_parse_chardata(xmlreader *reader)
 {
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c
index 86bdf69..548abb1 100644
--- a/dlls/xmllite/tests/reader.c
+++ b/dlls/xmllite/tests/reader.c
@@ -1566,6 +1566,93 @@ static void test_isemptyelement(void)
     IXmlReader_Release(reader);
 }
 
+static struct test_entry attributes_tests[] = {
+    { "<a attr1=\"attrvalue\"/>", "attr1", "attrvalue", S_OK },
+    { "<a attr1=\"a\'\'ttrvalue\"/>", "attr1", "a\'\'ttrvalue", S_OK },
+    { "<a attr1=\'a\"ttrvalue\'/>", "attr1", "a\"ttrvalue", S_OK },
+    { "<a attr1=\' \'/>", "attr1", " ", S_OK },
+    { "<a attr1=\" \"/>", "attr1", " ", S_OK },
+    { "<a attr1=attrvalue/>", NULL, NULL, WC_E_QUOTE },
+    { "<a attr1=\"attr<value\"/>", NULL, NULL, WC_E_LESSTHAN },
+    { NULL }
+};
+
+static void test_read_attribute(void)
+{
+    struct test_entry *test = attributes_tests;
+    IXmlReader *reader;
+    HRESULT hr;
+
+    hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
+    ok(hr == S_OK, "S_OK, got %08x\n", hr);
+
+    while (test->xml)
+    {
+        XmlNodeType type;
+        IStream *stream;
+
+        stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
+        hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
+        ok(hr == S_OK, "got %08x\n", hr);
+
+        type = XmlNodeType_None;
+        hr = IXmlReader_Read(reader, &type);
+
+        if (test->hr_broken)
+            ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
+        else
+            ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
+        if (hr == S_OK)
+        {
+            const WCHAR *str;
+            WCHAR *str_exp;
+            UINT len;
+
+            ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
+
+            hr = IXmlReader_MoveToFirstAttribute(reader);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+
+            len = 1;
+            str = NULL;
+            hr = IXmlReader_GetLocalName(reader, &str, &len);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+        todo_wine {
+            ok(len == strlen(test->name), "got %u\n", len);
+            str_exp = a2w(test->name);
+            ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
+            free_str(str_exp);
+        }
+            len = 1;
+            str = NULL;
+            hr = IXmlReader_GetQualifiedName(reader, &str, &len);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+        todo_wine {
+            ok(len == strlen(test->name), "got %u\n", len);
+            str_exp = a2w(test->name);
+            ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
+            free_str(str_exp);
+        }
+            /* value */
+            len = 1;
+            str = NULL;
+            hr = IXmlReader_GetValue(reader, &str, &len);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+        todo_wine {
+            ok(len == strlen(test->value), "got %u\n", len);
+            str_exp = a2w(test->value);
+            ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
+            free_str(str_exp);
+        }
+        }
+
+        IStream_Release(stream);
+        test++;
+    }
+
+    IXmlReader_Release(reader);
+}
+
 START_TEST(reader)
 {
     HRESULT r;
@@ -1582,6 +1669,7 @@ START_TEST(reader)
     test_reader_create();
     test_readerinput();
     test_reader_state();
+    test_read_attribute();
     test_read_cdata();
     test_read_comment();
     test_read_pi();




More information about the wine-cvs mailing list