Jacek Caban : xmllite: Allow reading from allocated strings in ReadValueChunk.

Alexandre Julliard julliard at winehq.org
Fri Mar 31 14:26:29 CDT 2017


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Fri Mar 31 15:58:06 2017 +0200

xmllite: Allow reading from allocated strings in ReadValueChunk.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/xmllite/reader.c       | 118 ++++++++++++++++++++++++++------------------
 dlls/xmllite/tests/reader.c |   2 -
 2 files changed, 70 insertions(+), 50 deletions(-)

diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index 660d2cd..a11ec7a 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -22,6 +22,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <assert.h>
 #include "windef.h"
 #include "winbase.h"
 #include "initguid.h"
@@ -286,6 +287,7 @@ typedef struct
     struct list nsdef;
     struct list ns;
     struct list elements;
+    int chunk_read_off;
     strval strvalues[StringValue_Last];
     UINT depth;
     UINT max_depth;
@@ -2536,7 +2538,10 @@ static HRESULT reader_parse_nextnode(xmlreader *reader)
     HRESULT hr;
 
     if (!is_reader_pending(reader))
+    {
+        reader->chunk_read_off = 0;
         reader_clear_attrs(reader);
+    }
 
     /* When moving from EndElement or empty element, pop its own namespace definitions */
     switch (nodetype)
@@ -2934,6 +2939,7 @@ static HRESULT reader_move_to_first_attribute(xmlreader *reader)
         reader_inc_depth(reader);
 
     reader->attr = LIST_ENTRY(list_head(&reader->attrs), struct attribute, entry);
+    reader->chunk_read_off = 0;
     reader_set_strvalue(reader, StringValue_Prefix, &reader->attr->prefix);
     reader_set_strvalue(reader, StringValue_QualifiedName, &reader->attr->qname);
     reader_set_strvalue(reader, StringValue_Value, &reader->attr->value);
@@ -2966,6 +2972,7 @@ static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
     if (next)
     {
         This->attr = LIST_ENTRY(next, struct attribute, entry);
+        This->chunk_read_off = 0;
         reader_set_strvalue(This, StringValue_Prefix, &This->attr->prefix);
         reader_set_strvalue(This, StringValue_QualifiedName, &This->attr->qname);
         reader_set_strvalue(This, StringValue_Value, &This->attr->value);
@@ -3007,6 +3014,7 @@ static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
             reader_set_strvalue(This, StringValue_QualifiedName, &element->qname);
         }
     }
+    This->chunk_read_off = 0;
     reader_set_strvalue(This, StringValue_Value, &strval_empty);
 
     return S_OK;
@@ -3274,17 +3282,54 @@ static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface, const WCHAR **ret,
     return S_OK;
 }
 
+static const strval *reader_get_value(xmlreader *reader, BOOL ensure_allocated)
+{
+    strval *val;
+
+    switch (reader_get_nodetype(reader))
+    {
+    case XmlNodeType_XmlDeclaration:
+    case XmlNodeType_EndElement:
+    case XmlNodeType_None:
+        return &strval_empty;
+    case XmlNodeType_Attribute:
+        /* For namespace definition attributes return values from namespace list */
+        if (reader->attr->flags & (ATTRIBUTE_NS_DEFINITION | ATTRIBUTE_DEFAULT_NS_DEFINITION))
+        {
+            struct ns *ns;
+
+            if (!(ns = reader_lookup_ns(reader, &reader->attr->localname)))
+                ns = reader_lookup_nsdef(reader);
+
+            return &ns->uri;
+        }
+        break;
+    default:
+        break;
+    }
+
+    val = &reader->strvalues[StringValue_Value];
+    if (!val->str && ensure_allocated)
+    {
+        WCHAR *ptr = reader_alloc(reader, (val->len+1)*sizeof(WCHAR));
+        if (!ptr) return NULL;
+        memcpy(ptr, reader_get_strptr(reader, val), val->len*sizeof(WCHAR));
+        ptr[val->len] = 0;
+        val->str = ptr;
+    }
+
+    return val;
+}
+
 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, const WCHAR **value, UINT *len)
 {
     xmlreader *reader = impl_from_IXmlReader(iface);
-    strval *val = &reader->strvalues[StringValue_Value];
-    UINT length;
+    const strval *val = &reader->strvalues[StringValue_Value];
+    UINT off;
 
     TRACE("(%p)->(%p %p)\n", reader, value, len);
 
     *value = NULL;
-    if (!len)
-        len = &length;
 
     if ((reader->nodetype == XmlNodeType_Comment && !val->str && !val->len) || is_reader_pending(reader))
     {
@@ -3298,64 +3343,40 @@ static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface, const WCHAR **value,
         if (is_reader_pending(reader)) return E_PENDING;
     }
 
-    switch (reader_get_nodetype(reader))
-    {
-    case XmlNodeType_XmlDeclaration:
-    case XmlNodeType_EndElement:
-    case XmlNodeType_None:
-        *value = emptyW;
-        *len = 0;
-        break;
-    case XmlNodeType_Attribute:
-        {
-            /* For namespace definition attributes return values from namespace list */
-            if (reader->attr->flags & (ATTRIBUTE_NS_DEFINITION | ATTRIBUTE_DEFAULT_NS_DEFINITION))
-            {
-                struct ns *ns;
-
-                if (!(ns = reader_lookup_ns(reader, &reader->attr->localname)))
-                    ns = reader_lookup_nsdef(reader);
-
-                *value = ns->uri.str;
-                *len = ns->uri.len;
-                break;
-            }
-        }
-        /* fallthrough */
-    default:
-        if (!val->str)
-        {
-            WCHAR *ptr = reader_alloc(reader, (val->len+1)*sizeof(WCHAR));
-            if (!ptr) return E_OUTOFMEMORY;
-            memcpy(ptr, reader_get_strptr(reader, val), val->len*sizeof(WCHAR));
-            ptr[val->len] = 0;
-            val->str = ptr;
-        }
-        *value = val->str;
-        *len = val->len;
-        break;
-    }
+    val = reader_get_value(reader, TRUE);
+    if (!val)
+        return E_OUTOFMEMORY;
 
+    off = abs(reader->chunk_read_off);
+    assert(off <= val->len);
+    *value = val->str + off;
+    if (len) *len = val->len - off;
+    reader->chunk_read_off = -off;
     return S_OK;
 }
 
 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface, WCHAR *buffer, UINT chunk_size, UINT *read)
 {
     xmlreader *reader = impl_from_IXmlReader(iface);
-    strval *val = &reader->strvalues[StringValue_Value];
-    UINT len;
+    const strval *val;
+    UINT len = 0;
 
     TRACE("(%p)->(%p %u %p)\n", reader, buffer, chunk_size, read);
 
-    /* Value is already allocated, chunked reads are not possible. */
-    len = !val->str && val->len ? min(chunk_size, val->len) : 0;
+    val = reader_get_value(reader, FALSE);
+
+    /* If value is already read by GetValue, chunk_read_off is negative and chunked reads are not possible. */
+    if (reader->chunk_read_off >= 0)
+    {
+        assert(reader->chunk_read_off <= val->len);
+        len = min(val->len - reader->chunk_read_off, chunk_size);
+    }
     if (read) *read = len;
 
     if (len)
     {
-        memcpy(buffer, reader_get_ptr2(reader, val->start), len*sizeof(WCHAR));
-        val->start += len;
-        val->len -= len;
+        memcpy(buffer, reader_get_strptr(reader, val) + reader->chunk_read_off, len*sizeof(WCHAR));
+        reader->chunk_read_off += len;
     }
 
     return len || !chunk_size ? S_OK : S_FALSE;
@@ -3601,6 +3622,7 @@ HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
     list_init(&reader->elements);
     reader->max_depth = 256;
 
+    reader->chunk_read_off = 0;
     for (i = 0; i < StringValue_Last; i++)
         reader->strvalues[i] = strval_empty;
 
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c
index 20d8240..fd83569 100644
--- a/dlls/xmllite/tests/reader.c
+++ b/dlls/xmllite/tests/reader.c
@@ -2581,12 +2581,10 @@ static void test_string_pointers(void)
     next_attribute(reader);
     read_value_char(reader, 'm');
     IXmlReader_GetValue(reader, &p, NULL);
-    todo_wine
     ok(!strcmp_wa(p, "yns"), "value = %s\n", wine_dbgstr_w(p));
 
     read_node(reader, XmlNodeType_Element);
     ns = reader_namespace(reader, "myns");
-    todo_wine
     ok(ns+1 == p, "ns+1 != p\n");
 
     set_input_string(reader, "<elem attr=\"value\"></elem>");




More information about the wine-cvs mailing list