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