Module: wine Branch: master Commit: 53f72826a21b25df6ebf3b34a2dcbe0f3aabcba8 URL: http://source.winehq.org/git/wine.git/?a=commit;h=53f72826a21b25df6ebf3b34a2...
Author: Nikolay Sivov nsivov@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();