[PATCH 4/5] xmllite/reader: Improve returned reader position for elements and attributes

Nikolay Sivov nsivov at codeweavers.com
Wed Mar 8 22:14:09 CST 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/xmllite/reader.c       | 124 ++++++++++++++++++++++++++++++++++----------
 dlls/xmllite/tests/reader.c |  29 +++++------
 2 files changed, 109 insertions(+), 44 deletions(-)

diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index 6a22cc5603..07330f5aec 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -224,6 +224,12 @@ static const strval strval_empty = { emptyW };
 static const strval strval_xml = { xmlW, 3 };
 static const strval strval_xmlns = { xmlnsW, 5 };
 
+struct reader_position
+{
+    UINT line_number;
+    UINT line_position;
+};
+
 struct attribute
 {
     struct list entry;
@@ -231,6 +237,7 @@ struct attribute
     strval localname;
     strval qname;
     strval value;
+    struct reader_position position;
 };
 
 struct element
@@ -239,6 +246,7 @@ struct element
     strval prefix;
     strval localname;
     strval qname;
+    struct reader_position position;
 };
 
 struct ns
@@ -262,7 +270,7 @@ typedef struct
     DtdProcessing dtdmode;
     IXmlResolver *resolver;
     IUnknown *mlang;
-    UINT line, pos;           /* reader position in XML stream */
+    struct reader_position position;
     struct list attrs; /* attributes list for current node */
     struct attribute *attr; /* current attribute */
     UINT attr_count;
@@ -388,7 +396,7 @@ static void reader_clear_attrs(xmlreader *reader)
 /* attribute data holds pointers to buffer data, so buffer shrink is not possible
    while we are on a node with attributes */
 static HRESULT reader_add_attr(xmlreader *reader, strval *prefix, strval *localname, strval *qname,
-    strval *value)
+    strval *value, const struct reader_position *position)
 {
     struct attribute *attr;
 
@@ -402,6 +410,7 @@ static HRESULT reader_add_attr(xmlreader *reader, strval *prefix, strval *localn
     attr->localname = *localname;
     attr->qname = qname ? *qname : *localname;
     attr->value = *value;
+    attr->position = *position;
     list_add_tail(&reader->attrs, &attr->entry);
     reader->attr_count++;
 
@@ -539,7 +548,7 @@ static void reader_mark_ns_nodes(xmlreader *reader, struct element *element)
 }
 
 static HRESULT reader_push_element(xmlreader *reader, strval *prefix, strval *localname,
-    strval *qname)
+    strval *qname, const struct reader_position *position)
 {
     struct element *element;
     HRESULT hr;
@@ -555,6 +564,7 @@ static HRESULT reader_push_element(xmlreader *reader, strval *prefix, strval *lo
         list_add_head(&reader->elements, &element->entry);
         reader_mark_ns_nodes(reader, element);
         reader->is_empty_element = FALSE;
+        element->position = *position;
     }
     else
         reader_free_element(reader, element);
@@ -1048,7 +1058,7 @@ static void reader_skipn(xmlreader *reader, int n)
     while (*ptr++ && n--)
     {
         buffer->cur++;
-        reader->pos++;
+        reader->position.line_position++;
     }
 }
 
@@ -1067,14 +1077,14 @@ static int reader_skipspaces(xmlreader *reader)
     while (is_wchar_space(*ptr))
     {
         if (*ptr == '\r')
-            reader->pos = 0;
+            reader->position.line_position = 0;
         else if (*ptr == '\n')
         {
-            reader->line++;
-            reader->pos = 0;
+            reader->position.line_number++;
+            reader->position.line_position = 0;
         }
         else
-            reader->pos++;
+            reader->position.line_position++;
 
         buffer->cur++;
         ptr = reader_get_ptr(reader);
@@ -1125,11 +1135,13 @@ static HRESULT reader_parse_eq(xmlreader *reader)
 static HRESULT reader_parse_versioninfo(xmlreader *reader)
 {
     static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
+    struct reader_position position;
     strval val, name;
     HRESULT hr;
 
     if (!reader_skipspaces(reader)) return WC_E_WHITESPACE;
 
+    position = reader->position;
     if (reader_cmp(reader, versionW)) return WC_E_XMLDECL;
     reader_init_strvalue(reader_get_cur(reader), 7, &name);
     /* skip 'version' */
@@ -1152,7 +1164,7 @@ static HRESULT reader_parse_versioninfo(xmlreader *reader)
     /* skip "'"|'"' */
     reader_skipn(reader, 1);
 
-    return reader_add_attr(reader, NULL, &name, NULL, &val);
+    return reader_add_attr(reader, NULL, &name, NULL, &val, &position);
 }
 
 /* ([A-Za-z0-9._] | '-') */
@@ -1199,11 +1211,13 @@ static HRESULT reader_parse_encname(xmlreader *reader, strval *val)
 static HRESULT reader_parse_encdecl(xmlreader *reader)
 {
     static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
+    struct reader_position position;
     strval name, val;
     HRESULT hr;
 
     if (!reader_skipspaces(reader)) return S_FALSE;
 
+    position = reader->position;
     if (reader_cmp(reader, encodingW)) return S_FALSE;
     name.str = reader_get_ptr(reader);
     name.start = reader_get_cur(reader);
@@ -1228,7 +1242,7 @@ static HRESULT reader_parse_encdecl(xmlreader *reader)
     /* skip "'"|'"' */
     reader_skipn(reader, 1);
 
-    return reader_add_attr(reader, NULL, &name, NULL, &val);
+    return reader_add_attr(reader, NULL, &name, NULL, &val, &position);
 }
 
 /* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */
@@ -1237,12 +1251,14 @@ static HRESULT reader_parse_sddecl(xmlreader *reader)
     static const WCHAR standaloneW[] = {'s','t','a','n','d','a','l','o','n','e',0};
     static const WCHAR yesW[] = {'y','e','s',0};
     static const WCHAR noW[] = {'n','o',0};
+    struct reader_position position;
     strval name, val;
     UINT start;
     HRESULT hr;
 
     if (!reader_skipspaces(reader)) return S_FALSE;
 
+    position = reader->position;
     if (reader_cmp(reader, standaloneW)) return S_FALSE;
     reader_init_strvalue(reader_get_cur(reader), 10, &name);
     /* skip 'standalone' */
@@ -1270,7 +1286,7 @@ static HRESULT reader_parse_sddecl(xmlreader *reader)
     /* skip "'"|'"' */
     reader_skipn(reader, 1);
 
-    return reader_add_attr(reader, NULL, &name, NULL, &val);
+    return reader_add_attr(reader, NULL, &name, NULL, &val, &position);
 }
 
 /* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
@@ -1723,6 +1739,7 @@ static HRESULT reader_parse_externalid(xmlreader *reader)
 {
     static WCHAR systemW[] = {'S','Y','S','T','E','M',0};
     static WCHAR publicW[] = {'P','U','B','L','I','C',0};
+    struct reader_position position = reader->position;
     strval name, sys;
     HRESULT hr;
     int cnt;
@@ -1739,7 +1756,7 @@ static HRESULT reader_parse_externalid(xmlreader *reader)
         if (FAILED(hr)) return hr;
 
         reader_init_cstrvalue(publicW, strlenW(publicW), &name);
-        hr = reader_add_attr(reader, NULL, &name, NULL, &pub);
+        hr = reader_add_attr(reader, NULL, &name, NULL, &pub, &position);
         if (FAILED(hr)) return hr;
 
         cnt = reader_skipspaces(reader);
@@ -1750,7 +1767,7 @@ static HRESULT reader_parse_externalid(xmlreader *reader)
         if (FAILED(hr)) return S_OK;
 
         reader_init_cstrvalue(systemW, strlenW(systemW), &name);
-        hr = reader_add_attr(reader, NULL, &name, NULL, &sys);
+        hr = reader_add_attr(reader, NULL, &name, NULL, &sys, &position);
         if (FAILED(hr)) return hr;
 
         return S_OK;
@@ -1764,7 +1781,7 @@ static HRESULT reader_parse_externalid(xmlreader *reader)
         if (FAILED(hr)) return hr;
 
         reader_init_cstrvalue(systemW, strlenW(systemW), &name);
-        return reader_add_attr(reader, NULL, &name, NULL, &sys);
+        return reader_add_attr(reader, NULL, &name, NULL, &sys, &position);
     }
 
     return S_FALSE;
@@ -2139,6 +2156,7 @@ static HRESULT reader_parse_attvalue(xmlreader *reader, strval *value)
    [15 NS] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue */
 static HRESULT reader_parse_attribute(xmlreader *reader)
 {
+    struct reader_position position = reader->position;
     strval prefix, local, qname, value;
     BOOL ns = FALSE, nsdef = FALSE;
     HRESULT hr;
@@ -2162,19 +2180,20 @@ static HRESULT reader_parse_attribute(xmlreader *reader)
         reader_push_ns(reader, nsdef ? &strval_xmlns : &local, &value, nsdef);
 
     TRACE("%s=%s\n", debug_strval(reader, &local), debug_strval(reader, &value));
-    return reader_add_attr(reader, &prefix, &local, &qname, &value);
+    return reader_add_attr(reader, &prefix, &local, &qname, &value, &position);
 }
 
 /* [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)
 {
+    struct reader_position position = reader->position;
     HRESULT hr;
 
     hr = reader_parse_qname(reader, prefix, local, qname);
     if (FAILED(hr)) return hr;
 
-    while (1)
+    for (;;)
     {
         static const WCHAR endW[] = {'/','>',0};
 
@@ -2188,6 +2207,7 @@ static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *loca
             reader->empty_element.prefix = *prefix;
             reader->empty_element.localname = *local;
             reader->empty_element.qname = *qname;
+            reader->empty_element.position = position;
             reader_mark_ns_nodes(reader, &reader->empty_element);
             return S_OK;
         }
@@ -2197,7 +2217,7 @@ static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *loca
         {
             /* skip '>' */
             reader_skipn(reader, 1);
-            return reader_push_element(reader, prefix, local, qname);
+            return reader_push_element(reader, prefix, local, qname, &position);
         }
 
         hr = reader_parse_attribute(reader);
@@ -2257,6 +2277,7 @@ static HRESULT reader_parse_element(xmlreader *reader)
 /* [13 NS] ETag ::= '</' QName S? '>' */
 static HRESULT reader_parse_endtag(xmlreader *reader)
 {
+    struct reader_position position;
     strval prefix, local, qname;
     struct element *element;
     HRESULT hr;
@@ -2264,6 +2285,7 @@ static HRESULT reader_parse_endtag(xmlreader *reader)
     /* skip '</' */
     reader_skipn(reader, 2);
 
+    position = reader->position;
     hr = reader_parse_qname(reader, &prefix, &local, &qname);
     if (FAILED(hr)) return hr;
 
@@ -2279,6 +2301,9 @@ static HRESULT reader_parse_endtag(xmlreader *reader)
     element = LIST_ENTRY(list_head(&reader->elements), struct element, entry);
     if (!strval_eq(reader, &element->qname, &qname)) return WC_E_ELEMENTMATCH;
 
+    /* update position stored for start tag, we won't be using it */
+    element->position = position;
+
     reader->nodetype = XmlNodeType_EndElement;
     reader->is_empty_element = FALSE;
     reader_set_strvalue(reader, StringValue_Prefix, &prefix);
@@ -2484,7 +2509,7 @@ static HRESULT reader_parse_nextnode(xmlreader *reader)
         ;
     }
 
-    while (1)
+    for (;;)
     {
         switch (reader->instate)
         {
@@ -2496,6 +2521,9 @@ static HRESULT reader_parse_nextnode(xmlreader *reader)
                 hr = readerinput_growraw(reader->input);
                 if (FAILED(hr)) return hr;
 
+                reader->position.line_number = 1;
+                reader->position.line_position = 1;
+
                 /* try to detect encoding by BOM or data and set input code page */
                 hr = readerinput_detectencoding(reader->input, &enc);
                 TRACE("detected encoding %s, 0x%08x\n", enc == XmlEncoding_Unknown ? "(unknown)" :
@@ -2656,7 +2684,8 @@ static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
         This->input = NULL;
     }
 
-    This->line = This->pos = 0;
+    This->position.line_number = 0;
+    This->position.line_position = 0;
     reader_clear_elements(This);
     This->depth = 0;
     This->nodetype = XmlNodeType_None;
@@ -3238,28 +3267,66 @@ static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
     return (reader_get_nodetype(This) == XmlNodeType_Element) ? This->is_empty_element : FALSE;
 }
 
-static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
+static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *line_number)
 {
     xmlreader *This = impl_from_IXmlReader(iface);
+    const struct element *element;
 
-    TRACE("(%p %p)\n", This, lineNumber);
+    TRACE("(%p %p)\n", This, line_number);
 
-    if (!lineNumber) return E_INVALIDARG;
+    if (!line_number)
+        return E_INVALIDARG;
 
-    *lineNumber = This->line;
+    switch (reader_get_nodetype(This))
+    {
+    case XmlNodeType_Element:
+    case XmlNodeType_EndElement:
+        if (This->is_empty_element)
+            element = &This->empty_element;
+        else
+            element = LIST_ENTRY(list_head(&This->elements), struct element, entry);
+
+        *line_number = element->position.line_number;
+        break;
+    case XmlNodeType_Attribute:
+        *line_number = This->attr->position.line_number;
+        break;
+    default:
+        *line_number = This->position.line_number;
+        break;
+    }
 
     return S_OK;
 }
 
-static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
+static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *line_position)
 {
     xmlreader *This = impl_from_IXmlReader(iface);
+    const struct element *element;
+
+    TRACE("(%p %p)\n", This, line_position);
 
-    TRACE("(%p %p)\n", This, linePosition);
+    if (!line_position)
+        return E_INVALIDARG;
 
-    if (!linePosition) return E_INVALIDARG;
+    switch (reader_get_nodetype(This))
+    {
+    case XmlNodeType_Element:
+    case XmlNodeType_EndElement:
+        if (This->is_empty_element)
+            element = &This->empty_element;
+        else
+            element = LIST_ENTRY(list_head(&This->elements), struct element, entry);
 
-    *linePosition = This->pos;
+        *line_position = element->position.line_position;
+        break;
+    case XmlNodeType_Attribute:
+        *line_position = This->attr->position.line_position;
+        break;
+    default:
+        *line_position = This->position.line_position;
+        break;
+    }
 
     return S_OK;
 }
@@ -3409,7 +3476,8 @@ HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
     reader->dtdmode = DtdProcessing_Prohibit;
     reader->resolver = NULL;
     reader->mlang = NULL;
-    reader->line  = reader->pos = 0;
+    reader->position.line_number = 0;
+    reader->position.line_position = 0;
     reader->imalloc = imalloc;
     if (imalloc) IMalloc_AddRef(imalloc);
     reader->nodetype = XmlNodeType_None;
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c
index b0713a6616..d09316aaaf 100644
--- a/dlls/xmllite/tests/reader.c
+++ b/dlls/xmllite/tests/reader.c
@@ -781,7 +781,6 @@ todo_wine
     ok(hr == S_OK, "got %08x\n", hr);
     ok(type == XmlNodeType_Attribute, "got %d\n", type);
 
-todo_wine
     TEST_READER_POSITION2(reader, 1, 7, ~0u, 55);
 
     /* try to move from last attribute */
@@ -799,7 +798,6 @@ todo_wine
 
     hr = IXmlReader_MoveToFirstAttribute(reader);
     ok(hr == S_OK, "got %08x\n", hr);
-todo_wine
     TEST_READER_POSITION2(reader, 1, 7, ~0u, 55);
 
     hr = IXmlReader_GetAttributeCount(reader, NULL);
@@ -890,7 +888,6 @@ todo_wine
     hr = IXmlReader_GetNodeType(reader, &type);
     ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
     ok(type == XmlNodeType_Attribute, "got %d\n", type);
-todo_wine
     TEST_READER_POSITION2(reader, 1, 7, ~0u, 21);
 
     /* try to move from last attribute */
@@ -901,7 +898,6 @@ todo_wine
     hr = IXmlReader_Read(reader, &type);
     ok(hr == S_OK, "expected S_OK, got %08x\n", hr);
     ok(type == XmlNodeType_Element, "expected Element, got %s\n", type_to_str(type));
-todo_wine
     TEST_READER_POSITION2(reader, 1, 23, ~0u, 40);
     TEST_READER_STATE(reader, XmlReadState_Interactive);
 
@@ -925,10 +921,10 @@ todo_wine
 todo_wine
     ok(hr == WC_E_SYNTAX || hr == WC_E_XMLCHARACTER /* XP */, "expected WC_E_SYNTAX, got %08x\n", hr);
     ok(type == XmlNodeType_None, "expected XmlNodeType_None, got %s\n", type_to_str(type));
-todo_wine {
     TEST_READER_POSITION(reader, 1, 41);
+todo_wine
     TEST_READER_STATE(reader, XmlReadState_Error);
-}
+
     IStream_Release(stream);
     IXmlReader_Release(reader);
 }
@@ -2473,12 +2469,12 @@ todo_wine {
 
 static void test_reader_position(void)
 {
-    static const char *xml = "<c:a xmlns:c=\"nsdef c\" b=\"attr b\" />";
+    static const char *xml = "<c:a xmlns:c=\"nsdef c\" b=\"attr b\"></c:a>";
     IXmlReader *reader;
     XmlNodeType type;
     IStream *stream;
-    HRESULT hr;
     UINT position;
+    HRESULT hr;
 
     hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL);
     ok(hr == S_OK, "S_OK, got %08x\n", hr);
@@ -2511,23 +2507,24 @@ todo_wine
     hr = IXmlReader_Read(reader, &type);
     ok(hr == S_OK, "got %08x\n", hr);
     ok(type == XmlNodeType_Element, "got type %d\n", type);
-todo_wine
-    TEST_READER_POSITION2(reader, 1, 2, ~0u, 36);
+    TEST_READER_POSITION2(reader, 1, 2, ~0u, 34);
 
     hr = IXmlReader_MoveToNextAttribute(reader);
     ok(hr == S_OK, "got %08x\n", hr);
-todo_wine
-    TEST_READER_POSITION2(reader, 1, 6, ~0u, 36);
+    TEST_READER_POSITION2(reader, 1, 6, ~0u, 34);
 
     hr = IXmlReader_MoveToNextAttribute(reader);
     ok(hr == S_OK, "got %08x\n", hr);
-todo_wine
-    TEST_READER_POSITION2(reader, 1, 24, ~0u, 36);
+    TEST_READER_POSITION2(reader, 1, 24, ~0u, 34);
 
     hr = IXmlReader_MoveToElement(reader);
     ok(hr == S_OK, "got %08x\n", hr);
-todo_wine
-    TEST_READER_POSITION2(reader, 1, 2, ~0u, 36);
+    TEST_READER_POSITION2(reader, 1, 2, ~0u, 34);
+
+    hr = IXmlReader_Read(reader, &type);
+    ok(hr == S_OK, "got %08x\n", hr);
+    ok(type == XmlNodeType_EndElement, "got type %d\n", type);
+    TEST_READER_POSITION2(reader, 1, 37, ~0u, 40);
 
     IXmlReader_SetInput(reader, NULL);
     TEST_READER_POSITION(reader, 0, 0);
-- 
2.11.0




More information about the wine-patches mailing list