[6/7] webservices: Store all text in native format in binary mode.

Hans Leidekker hans at codeweavers.com
Mon Jul 10 04:02:33 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c              | 517 ++++++++++++++++++++++++---------
 dlls/webservices/webservices_private.h |  24 +-
 dlls/webservices/writer.c              | 245 ++++++++++++++--
 3 files changed, 614 insertions(+), 172 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index bf05352..5bc862e 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -787,7 +787,19 @@ WS_XML_UTF8_TEXT *alloc_utf8_text( const BYTE *data, ULONG len )
     return ret;
 }
 
-static WS_XML_BASE64_TEXT *alloc_base64_text( const BYTE *data, ULONG len )
+WS_XML_UTF16_TEXT *alloc_utf16_text( const BYTE *data, ULONG len )
+{
+    WS_XML_UTF16_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_UTF16;
+    ret->byteCount     = len;
+    ret->bytes         = len ? (BYTE *)(ret + 1) : NULL;
+    if (data) memcpy( ret->bytes, data, len );
+    return ret;
+}
+
+WS_XML_BASE64_TEXT *alloc_base64_text( const BYTE *data, ULONG len )
 {
     WS_XML_BASE64_TEXT *ret;
 
@@ -799,6 +811,86 @@ static WS_XML_BASE64_TEXT *alloc_base64_text( const BYTE *data, ULONG len )
     return ret;
 }
 
+WS_XML_BOOL_TEXT *alloc_bool_text( BOOL value )
+{
+    WS_XML_BOOL_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_BOOL;
+    ret->value         = value;
+    return ret;
+}
+
+WS_XML_INT32_TEXT *alloc_int32_text( INT32 value )
+{
+    WS_XML_INT32_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_INT32;
+    ret->value         = value;
+    return ret;
+}
+
+WS_XML_INT64_TEXT *alloc_int64_text( INT64 value )
+{
+    WS_XML_INT64_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_INT64;
+    ret->value         = value;
+    return ret;
+}
+
+WS_XML_UINT64_TEXT *alloc_uint64_text( UINT64 value )
+{
+    WS_XML_UINT64_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_UINT64;
+    ret->value         = value;
+    return ret;
+}
+
+WS_XML_DOUBLE_TEXT *alloc_double_text( double value )
+{
+    WS_XML_DOUBLE_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_DOUBLE;
+    ret->value         = value;
+    return ret;
+}
+
+WS_XML_GUID_TEXT *alloc_guid_text( const GUID *value )
+{
+    WS_XML_GUID_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_GUID;
+    ret->value         = *value;
+    return ret;
+}
+
+WS_XML_UNIQUE_ID_TEXT *alloc_unique_id_text( const GUID *value )
+{
+    WS_XML_UNIQUE_ID_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
+    ret->value         = *value;
+    return ret;
+}
+
+WS_XML_DATETIME_TEXT *alloc_datetime_text( const WS_DATETIME *value )
+{
+    WS_XML_DATETIME_TEXT *ret;
+
+    if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
+    ret->text.textType = WS_XML_TEXT_TYPE_DATETIME;
+    ret->value         = *value;
+    return ret;
+}
+
 static inline BOOL read_end_of_data( struct reader *reader )
 {
     return reader->read_pos >= reader->read_size;
@@ -1300,24 +1392,18 @@ static HRESULT lookup_string( struct reader *reader, ULONG id, const WS_XML_STRI
 
 static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE *attr )
 {
-    static const unsigned char zero[] = {'0'}, one[] = {'1'};
-    static const unsigned char false[] = {'f','a','l','s','e'}, true[] = {'t','r','u','e'};
-    WS_XML_UTF8_TEXT *utf8 = NULL;
-    WS_XML_BASE64_TEXT *base64;
+    WS_XML_UTF8_TEXT *text_utf8 = NULL;
+    WS_XML_BASE64_TEXT *text_base64 = NULL;
+    WS_XML_INT32_TEXT *text_int32;
+    WS_XML_INT64_TEXT *text_int64;
+    WS_XML_BOOL_TEXT *text_bool;
     const WS_XML_STRING *str;
-    unsigned char type, buf[46];
-    BOOL val_bool;
-    INT8 val_int8;
-    INT16 val_int16;
-    INT32 val_int32;
-    INT64 val_int64;
-    double val_double;
+    unsigned char type;
     UINT8 val_uint8;
     UINT16 val_uint16;
-    UINT64 val_uint64;
-    WS_DATETIME datetime;
-    ULONG len, id;
-    GUID uuid;
+    INT32 val_int32;
+    ULONG len = 0, id;
+    GUID guid;
     HRESULT hr;
 
     if ((hr = read_byte( reader, &type )) != S_OK) return hr;
@@ -1326,57 +1412,79 @@ static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE
     switch (type)
     {
     case RECORD_ZERO_TEXT:
-        if (!(utf8 = alloc_utf8_text( zero, sizeof(zero) ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        if (!(text_int32 = alloc_int32_text( 0 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int32->text;
+        return S_OK;
+    }
     case RECORD_ONE_TEXT:
-        if (!(utf8 = alloc_utf8_text( one, sizeof(one) ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        if (!(text_int32 = alloc_int32_text( 1 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int32->text;
+        return S_OK;
+    }
     case RECORD_FALSE_TEXT:
-        if (!(utf8 = alloc_utf8_text( false, sizeof(false) ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        if (!(text_bool = alloc_bool_text( FALSE ))) return E_OUTOFMEMORY;
+        attr->value = &text_bool->text;
+        return S_OK;
+    }
     case RECORD_TRUE_TEXT:
-        if (!(utf8 = alloc_utf8_text( true, sizeof(true) ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        if (!(text_bool = alloc_bool_text( TRUE ))) return E_OUTOFMEMORY;
+        attr->value = &text_bool->text;
+        return S_OK;
+    }
     case RECORD_INT8_TEXT:
+    {
+        INT8 val_int8;
         if ((hr = read_byte( reader, (unsigned char *)&val_int8 )) != S_OK) return hr;
-        len = format_int8( &val_int8, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
-
+        if (!(text_int64 = alloc_int64_text( val_int8 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int64->text;
+        return S_OK;
+    }
     case RECORD_INT16_TEXT:
+    {
+        INT16 val_int16;
         if ((hr = read_bytes( reader, (unsigned char *)&val_int16, sizeof(val_int16) )) != S_OK) return hr;
-        len = format_int16( &val_int16, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
-
+        if (!(text_int64 = alloc_int64_text( val_int16 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int64->text;
+        return S_OK;
+    }
     case RECORD_INT32_TEXT:
         if ((hr = read_bytes( reader, (unsigned char *)&val_int32, sizeof(val_int32) )) != S_OK) return hr;
-        len = format_int32( &val_int32, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
+        if (!(text_int64 = alloc_int64_text( val_int32 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int64->text;
+        return S_OK;
 
     case RECORD_INT64_TEXT:
+    {
+        INT64 val_int64;
         if ((hr = read_bytes( reader, (unsigned char *)&val_int64, sizeof(val_int64) )) != S_OK) return hr;
-        len = format_int64( &val_int64, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
-
+        if (!(text_int64 = alloc_int64_text( val_int64 ))) return E_OUTOFMEMORY;
+        attr->value = &text_int64->text;
+        return S_OK;
+    }
     case RECORD_DOUBLE_TEXT:
-        if ((hr = read_bytes( reader, (unsigned char *)&val_double, sizeof(val_double) )) != S_OK) return hr;
-        len = format_double( &val_double, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
+    {
+        WS_XML_DOUBLE_TEXT *text_double;
+        double val_double;
 
+        if ((hr = read_bytes( reader, (unsigned char *)&val_double, sizeof(val_double) )) != S_OK) return hr;
+        if (!(text_double = alloc_double_text( val_double ))) return E_OUTOFMEMORY;
+        attr->value = &text_double->text;
+        return S_OK;
+    }
     case RECORD_DATETIME_TEXT:
-        if ((hr = read_datetime( reader, &datetime )) != S_OK) return hr;
-        len = format_datetime( &datetime, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
+    {
+        WS_XML_DATETIME_TEXT *text_datetime;
+        WS_DATETIME datetime;
 
+        if ((hr = read_datetime( reader, &datetime )) != S_OK) return hr;
+        if (!(text_datetime = alloc_datetime_text( &datetime ))) return E_OUTOFMEMORY;
+        attr->value = &text_datetime->text;
+        return S_OK;
+    }
     case RECORD_CHARS8_TEXT:
         if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr;
         len = val_uint8;
@@ -1395,20 +1503,20 @@ static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE
 
     case RECORD_BYTES8_TEXT:
         if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr;
-        if (!(base64 = alloc_base64_text( NULL, val_uint8 ))) return E_OUTOFMEMORY;
-        if ((hr = read_bytes( reader, base64->bytes, val_uint8 )) != S_OK)
+        if (!(text_base64 = alloc_base64_text( NULL, val_uint8 ))) return E_OUTOFMEMORY;
+        if ((hr = read_bytes( reader, text_base64->bytes, val_uint8 )) != S_OK)
         {
-            heap_free( base64 );
+            heap_free( text_base64 );
             return hr;
         }
         break;
 
     case RECORD_BYTES16_TEXT:
         if ((hr = read_bytes( reader, (unsigned char *)&val_uint16, sizeof(val_uint16) )) != S_OK) return hr;
-        if (!(base64 = alloc_base64_text( NULL, val_uint16 ))) return E_OUTOFMEMORY;
-        if ((hr = read_bytes( reader, base64->bytes, val_uint16 )) != S_OK)
+        if (!(text_base64 = alloc_base64_text( NULL, val_uint16 ))) return E_OUTOFMEMORY;
+        if ((hr = read_bytes( reader, text_base64->bytes, val_uint16 )) != S_OK)
         {
-            heap_free( base64 );
+            heap_free( text_base64 );
             return hr;
         }
         break;
@@ -1416,71 +1524,87 @@ static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE
     case RECORD_BYTES32_TEXT:
         if ((hr = read_bytes( reader, (unsigned char *)&val_int32, sizeof(val_int32) )) != S_OK) return hr;
         if (val_int32 < 0) return WS_E_INVALID_FORMAT;
-        if (!(base64 = alloc_base64_text( NULL, val_int32 ))) return E_OUTOFMEMORY;
-        if ((hr = read_bytes( reader, base64->bytes, val_int32 )) != S_OK)
+        if (!(text_base64 = alloc_base64_text( NULL, val_int32 ))) return E_OUTOFMEMORY;
+        if ((hr = read_bytes( reader, text_base64->bytes, val_int32 )) != S_OK)
         {
-            heap_free( base64 );
+            heap_free( text_base64 );
             return hr;
         }
         break;
 
     case RECORD_EMPTY_TEXT:
-        len = 0;
         break;
 
     case RECORD_DICTIONARY_TEXT:
         if ((hr = read_int31( reader, &id )) != S_OK) return hr;
         if ((hr = lookup_string( reader, id, &str )) != S_OK) return hr;
-        if (!(utf8 = alloc_utf8_text( str->bytes, str->length ))) return E_OUTOFMEMORY;
+        if (!(text_utf8 = alloc_utf8_text( str->bytes, str->length ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_UNIQUEID_TEXT:
-        if ((hr = read_bytes( reader, (unsigned char *)&uuid, sizeof(uuid) )) != S_OK) return hr;
-        len = format_urn( &uuid, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        WS_XML_UNIQUE_ID_TEXT *text_unique_id;
+        if ((hr = read_bytes( reader, (unsigned char *)&guid, sizeof(guid) )) != S_OK) return hr;
+        if (!(text_unique_id = alloc_unique_id_text( &guid ))) return E_OUTOFMEMORY;
+        attr->value = &text_unique_id->text;
+        return S_OK;
+    }
     case RECORD_UUID_TEXT:
-        if ((hr = read_bytes( reader, (unsigned char *)&uuid, sizeof(uuid) )) != S_OK) return hr;
-        len = format_guid( &uuid, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
-
+    {
+        WS_XML_GUID_TEXT *guid_text;
+        if ((hr = read_bytes( reader, (unsigned char *)&guid, sizeof(guid) )) != S_OK) return hr;
+        if (!(guid_text = alloc_guid_text( &guid ))) return E_OUTOFMEMORY;
+        attr->value = &guid_text->text;
+        return S_OK;
+    }
     case RECORD_UINT64_TEXT:
-        if ((hr = read_bytes( reader, (unsigned char *)&val_uint64, sizeof(val_uint64) )) != S_OK) return hr;
-        len = format_uint64( &val_uint64, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
+    {
+        WS_XML_UINT64_TEXT *text_uint64;
+        UINT64 val_uint64;
 
+        if ((hr = read_bytes( reader, (unsigned char *)&val_uint64, sizeof(val_uint64) )) != S_OK) return hr;
+        if (!(text_uint64 = alloc_uint64_text( val_uint64 ))) return E_OUTOFMEMORY;
+        attr->value = &text_uint64->text;
+        return S_OK;
+    }
     case RECORD_BOOL_TEXT:
-        if ((hr = read_bytes( reader, (unsigned char *)&val_bool, sizeof(val_bool) )) != S_OK) return hr;
-        len = format_bool( &val_bool, buf );
-        if (!(utf8 = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
-        break;
+    {
+        WS_XML_BOOL_TEXT *text_bool;
+        BOOL val_bool;
 
+        if ((hr = read_bytes( reader, (unsigned char *)&val_bool, sizeof(val_bool) )) != S_OK) return hr;
+        if (!(text_bool = alloc_bool_text( !!val_bool ))) return E_OUTOFMEMORY;
+        attr->value = &text_bool->text;
+        return S_OK;
+    }
     default:
         ERR( "unhandled record type %02x\n", type );
         return WS_E_NOT_SUPPORTED;
     }
 
+    if (type >= RECORD_INT8_TEXT && type <= RECORD_INT64_TEXT)
+    {
+        attr->value = &text_int64->text;
+        return S_OK;
+    }
     if (type >= RECORD_BYTES8_TEXT && type <= RECORD_BYTES32_TEXT)
     {
-        attr->value = &base64->text;
+        attr->value = &text_base64->text;
         return S_OK;
     }
 
-    if (!utf8)
+    if (!text_utf8)
     {
-        if (!(utf8 = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY;
-        if (!len) utf8->value.bytes = (BYTE *)(utf8 + 1); /* quirk */
-        if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK)
+        if (!(text_utf8 = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY;
+        if (!len) text_utf8->value.bytes = (BYTE *)(text_utf8 + 1); /* quirk */
+        if ((hr = read_bytes( reader, text_utf8->value.bytes, len )) != S_OK)
         {
-            heap_free( utf8 );
+            heap_free( text_utf8 );
             return hr;
         }
     }
 
-    attr->value = &utf8->text;
+    attr->value = &text_utf8->text;
     return S_OK;
 }
 
@@ -1975,6 +2099,142 @@ static struct node *alloc_base64_text_node( const BYTE *data, ULONG len, WS_XML_
     return node;
 }
 
+static struct node *alloc_bool_text_node( BOOL value )
+{
+    struct node *node;
+    WS_XML_BOOL_TEXT *text_bool;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_bool = alloc_bool_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_bool->text;
+    return node;
+}
+
+static struct node *alloc_int32_text_node( INT32 value )
+{
+    struct node *node;
+    WS_XML_INT32_TEXT *text_int32;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_int32 = alloc_int32_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_int32->text;
+    return node;
+}
+
+static struct node *alloc_int64_text_node( INT64 value )
+{
+    struct node *node;
+    WS_XML_INT64_TEXT *text_int64;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_int64 = alloc_int64_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_int64->text;
+    return node;
+}
+
+static struct node *alloc_double_text_node( double value )
+{
+    struct node *node;
+    WS_XML_DOUBLE_TEXT *text_double;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_double = alloc_double_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_double->text;
+    return node;
+}
+
+static struct node *alloc_datetime_text_node( const WS_DATETIME *value )
+{
+    struct node *node;
+    WS_XML_DATETIME_TEXT *text_datetime;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_datetime = alloc_datetime_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_datetime->text;
+    return node;
+}
+
+static struct node *alloc_unique_id_text_node( const GUID *value )
+{
+    struct node *node;
+    WS_XML_UNIQUE_ID_TEXT *text_unique_id;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_unique_id = alloc_unique_id_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_unique_id->text;
+    return node;
+}
+
+static struct node *alloc_guid_text_node( const GUID *value )
+{
+    struct node *node;
+    WS_XML_GUID_TEXT *text_guid;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_guid = alloc_guid_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_guid->text;
+    return node;
+}
+
+static struct node *alloc_uint64_text_node( UINT64 value )
+{
+    struct node *node;
+    WS_XML_UINT64_TEXT *text_uint64;
+    WS_XML_TEXT_NODE *text;
+
+    if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
+    if (!(text_uint64 = alloc_uint64_text( value )))
+    {
+        heap_free( node );
+        return NULL;
+    }
+    text = (WS_XML_TEXT_NODE *)node;
+    text->text = &text_uint64->text;
+    return node;
+}
+
 static HRESULT append_text_bytes( struct reader *reader, WS_XML_TEXT_NODE *node, ULONG len )
 {
     WS_XML_BASE64_TEXT *new, *old = (WS_XML_BASE64_TEXT *)node->text;
@@ -2064,22 +2324,12 @@ error:
 
 static HRESULT read_text_bin( struct reader *reader )
 {
-    static const unsigned char zero[] = {'0'}, one[] = {'1'};
-    static const unsigned char false[] = {'f','a','l','s','e'}, true[] = {'t','r','u','e'};
-    unsigned char type, buf[46];
     struct node *node = NULL, *parent;
+    unsigned char type;
     WS_XML_UTF8_TEXT *utf8;
-    const WS_XML_STRING *str;
-    BOOL val_bool;
-    INT8 val_int8;
-    INT16 val_int16;
     INT32 val_int32;
-    INT64 val_int64;
-    double val_double;
     UINT8 val_uint8;
     UINT16 val_uint16;
-    UINT64 val_uint64;
-    WS_DATETIME datetime;
     ULONG len, id;
     GUID uuid;
     HRESULT hr;
@@ -2091,66 +2341,70 @@ static HRESULT read_text_bin( struct reader *reader )
     {
     case RECORD_ZERO_TEXT:
     case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
-        if (!(node = alloc_utf8_text_node( zero, sizeof(zero), NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int32_text_node( 0 ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_ONE_TEXT:
     case RECORD_ONE_TEXT_WITH_ENDELEMENT:
-        if (!(node = alloc_utf8_text_node( one, sizeof(one), NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int32_text_node( 1 ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_FALSE_TEXT:
     case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
-        if (!(node = alloc_utf8_text_node( false, sizeof(false), NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_bool_text_node( FALSE ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_TRUE_TEXT:
     case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
-        if (!(node = alloc_utf8_text_node( true, sizeof(true), NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_bool_text_node( TRUE ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_INT8_TEXT:
     case RECORD_INT8_TEXT_WITH_ENDELEMENT:
+    {
+        INT8 val_int8;
         if ((hr = read_byte( reader, (unsigned char *)&val_int8 )) != S_OK) return hr;
-        len = format_int8( &val_int8, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int32_text_node( val_int8 ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_INT16_TEXT:
     case RECORD_INT16_TEXT_WITH_ENDELEMENT:
+    {
+        INT16 val_int16;
         if ((hr = read_bytes( reader, (unsigned char *)&val_int16, sizeof(val_int16) )) != S_OK) return hr;
-        len = format_int16( &val_int16, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int32_text_node( val_int16 ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_INT32_TEXT:
     case RECORD_INT32_TEXT_WITH_ENDELEMENT:
         if ((hr = read_bytes( reader, (unsigned char *)&val_int32, sizeof(val_int32) )) != S_OK) return hr;
-        len = format_int32( &val_int32, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int32_text_node( val_int32 ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_INT64_TEXT:
     case RECORD_INT64_TEXT_WITH_ENDELEMENT:
+    {
+        INT64 val_int64;
         if ((hr = read_bytes( reader, (unsigned char *)&val_int64, sizeof(val_int64) )) != S_OK) return hr;
-        len = format_int64( &val_int64, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_int64_text_node( val_int64 ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_DOUBLE_TEXT:
     case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
+    {
+        double val_double;
         if ((hr = read_bytes( reader, (unsigned char *)&val_double, sizeof(val_double) )) != S_OK) return hr;
-        len = format_double( &val_double, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_double_text_node( val_double ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_DATETIME_TEXT:
     case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
+    {
+        WS_DATETIME datetime;
         if ((hr = read_datetime( reader, &datetime )) != S_OK) return hr;
-        len = format_datetime( &datetime, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_datetime_text_node( &datetime ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_CHARS8_TEXT:
     case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
         if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr;
@@ -2185,39 +2439,41 @@ static HRESULT read_text_bin( struct reader *reader )
 
     case RECORD_DICTIONARY_TEXT:
     case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
+    {
+        const WS_XML_STRING *str;
         if ((hr = read_int31( reader, &id )) != S_OK) return hr;
         if ((hr = lookup_string( reader, id, &str )) != S_OK) return hr;
         if (!(node = alloc_utf8_text_node( str->bytes, str->length, NULL ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_UNIQUEID_TEXT:
     case RECORD_UNIQUEID_TEXT_WITH_ENDELEMENT:
         if ((hr = read_bytes( reader, (unsigned char *)&uuid, sizeof(uuid) )) != S_OK) return hr;
-        len = format_urn( &uuid, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_unique_id_text_node( &uuid ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_UUID_TEXT:
     case RECORD_UUID_TEXT_WITH_ENDELEMENT:
         if ((hr = read_bytes( reader, (unsigned char *)&uuid, sizeof(uuid) )) != S_OK) return hr;
-        len = format_guid( &uuid, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_guid_text_node( &uuid ))) return E_OUTOFMEMORY;
         break;
 
     case RECORD_UINT64_TEXT:
     case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
+    {
+        UINT64 val_uint64;
         if ((hr = read_bytes( reader, (unsigned char *)&val_uint64, sizeof(val_uint64) )) != S_OK) return hr;
-        len = format_uint64( &val_uint64, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_uint64_text_node( val_uint64 ))) return E_OUTOFMEMORY;
         break;
-
+    }
     case RECORD_BOOL_TEXT:
     case RECORD_BOOL_TEXT_WITH_ENDELEMENT:
+    {
+        BOOL val_bool;
         if ((hr = read_bytes( reader, (unsigned char *)&val_bool, sizeof(val_bool) )) != S_OK) return hr;
-        len = format_bool( &val_bool, buf );
-        if (!(node = alloc_utf8_text_node( buf, len, NULL ))) return E_OUTOFMEMORY;
+        if (!(node = alloc_bool_text_node( !!val_bool ))) return E_OUTOFMEMORY;
         break;
-
+    }
     default:
         ERR( "unhandled record type %02x\n", type );
         return WS_E_NOT_SUPPORTED;
@@ -2226,6 +2482,7 @@ static HRESULT read_text_bin( struct reader *reader )
     if (!node)
     {
         if (!(node = alloc_utf8_text_node( NULL, len, &utf8 ))) return E_OUTOFMEMORY;
+        if (!len) utf8->value.bytes = (BYTE *)(utf8 + 1); /* quirk */
         if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK)
         {
             free_node( node );
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 68837db..38d5786 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -44,23 +44,11 @@ struct dictionary
 struct dictionary dict_builtin DECLSPEC_HIDDEN;
 const struct dictionary dict_builtin_static DECLSPEC_HIDDEN;
 
-ULONG format_bool( const BOOL *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_int8( const INT8 *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_int16( const INT16 *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_int32( const INT32 *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_int64( const INT64 *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_uint64( const UINT64 *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_double( const double *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_datetime( const WS_DATETIME *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_guid( const GUID *, unsigned char * ) DECLSPEC_HIDDEN;
-ULONG format_urn( const GUID *, unsigned char * ) DECLSPEC_HIDDEN;
-
 const char *debugstr_xmlstr( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
 WS_XML_STRING *alloc_xml_string( const unsigned char *, ULONG ) DECLSPEC_HIDDEN;
 WS_XML_STRING *dup_xml_string( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
 HRESULT add_xml_string( WS_XML_STRING * ) DECLSPEC_HIDDEN;
 void free_xml_string( WS_XML_STRING * ) DECLSPEC_HIDDEN;
-WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *, ULONG ) DECLSPEC_HIDDEN;
 HRESULT append_attribute( WS_XML_ELEMENT_NODE *, WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
 void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
 WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN;
@@ -71,6 +59,18 @@ ULONG get_type_size( WS_TYPE, const void * ) DECLSPEC_HIDDEN;
 HRESULT read_header( WS_XML_READER *, const WS_XML_STRING *, const WS_XML_STRING *, WS_TYPE,
                      const void *, WS_READ_OPTION, WS_HEAP *, void *, ULONG ) DECLSPEC_HIDDEN;
 
+WS_XML_UTF8_TEXT *alloc_utf8_text( const BYTE *, ULONG ) DECLSPEC_HIDDEN;
+WS_XML_UTF16_TEXT *alloc_utf16_text( const BYTE *, ULONG ) DECLSPEC_HIDDEN;
+WS_XML_BASE64_TEXT *alloc_base64_text( const BYTE *, ULONG ) DECLSPEC_HIDDEN;
+WS_XML_BOOL_TEXT *alloc_bool_text( BOOL ) DECLSPEC_HIDDEN;
+WS_XML_INT32_TEXT *alloc_int32_text( INT32 ) DECLSPEC_HIDDEN;
+WS_XML_INT64_TEXT *alloc_int64_text( INT64 ) DECLSPEC_HIDDEN;
+WS_XML_UINT64_TEXT *alloc_uint64_text( UINT64 ) DECLSPEC_HIDDEN;
+WS_XML_DOUBLE_TEXT *alloc_double_text( double ) DECLSPEC_HIDDEN;
+WS_XML_GUID_TEXT *alloc_guid_text( const GUID * ) DECLSPEC_HIDDEN;
+WS_XML_UNIQUE_ID_TEXT *alloc_unique_id_text( const GUID * ) DECLSPEC_HIDDEN;
+WS_XML_DATETIME_TEXT *alloc_datetime_text( const WS_DATETIME * ) DECLSPEC_HIDDEN;
+
 #define INVALID_PARAMETER_INDEX 0xffff
 HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *, USHORT, const WS_FIELD_DESCRIPTION ** ) DECLSPEC_HIDDEN;
 HRESULT write_input_params( WS_XML_WRITER *, const WS_ELEMENT_DESCRIPTION *,
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index b4793f9..8ce59a1 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -1609,7 +1609,7 @@ HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *
     return hr;
 }
 
-ULONG format_bool( const BOOL *ptr, unsigned char *buf )
+static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
 {
     static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
     if (*ptr)
@@ -1621,22 +1621,22 @@ ULONG format_bool( const BOOL *ptr, unsigned char *buf )
     return sizeof(bool_false);
 }
 
-ULONG format_int8( const INT8 *ptr, unsigned char *buf )
+static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
 {
     return wsprintfA( (char *)buf, "%d", *ptr );
 }
 
-ULONG format_int16( const INT16 *ptr, unsigned char *buf )
+static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
 {
     return wsprintfA( (char *)buf, "%d", *ptr );
 }
 
-ULONG format_int32( const INT32 *ptr, unsigned char *buf )
+static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
 {
     return wsprintfA( (char *)buf, "%d", *ptr );
 }
 
-ULONG format_int64( const INT64 *ptr, unsigned char *buf )
+static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
 {
     return wsprintfA( (char *)buf, "%I64d", *ptr );
 }
@@ -1656,12 +1656,12 @@ static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
     return wsprintfA( (char *)buf, "%u", *ptr );
 }
 
-ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
+static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
 {
     return wsprintfA( (char *)buf, "%I64u", *ptr );
 }
 
-ULONG format_double( const double *ptr, unsigned char *buf )
+static ULONG format_double( const double *ptr, unsigned char *buf )
 {
 #ifdef HAVE_POWL
     static const long double precision = 0.0000000000000001;
@@ -1758,7 +1758,7 @@ static inline int year_size( int year )
 }
 
 #define TZ_OFFSET 8
-ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
+static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
 {
     static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
     int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
@@ -1814,7 +1814,7 @@ ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
     return len;
 }
 
-ULONG format_guid( const GUID *ptr, unsigned char *buf )
+static ULONG format_guid( const GUID *ptr, unsigned char *buf )
 {
     static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
     return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
@@ -1822,7 +1822,7 @@ ULONG format_guid( const GUID *ptr, unsigned char *buf )
                     ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
 }
 
-ULONG format_urn( const GUID *ptr, unsigned char *buf )
+static ULONG format_urn( const GUID *ptr, unsigned char *buf )
 {
     static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
     return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
@@ -1875,9 +1875,11 @@ static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *
     return i;
 }
 
-static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, WS_XML_UTF8_TEXT **ret )
+static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
+                                 WS_XML_UTF8_TEXT **ret )
 {
     ULONG len_old = old ? old->value.length : 0;
+    if (offset) *offset = len_old;
 
     switch (text->textType)
     {
@@ -2016,10 +2018,136 @@ static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT
     }
 }
 
+static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
+{
+    if (offset) *offset = 0;
+    switch (text->textType)
+    {
+    case WS_XML_TEXT_TYPE_UTF8:
+    {
+        const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
+        const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
+        WS_XML_UTF8_TEXT *new;
+        ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
+
+        if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+        if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
+        memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
+        if (offset) *offset = len_old;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_UTF16:
+    {
+        const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
+        const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
+        WS_XML_UTF16_TEXT *new;
+        ULONG len = utf16->byteCount / sizeof(WCHAR);
+        ULONG len_old = utf16_old ? utf16_old->byteCount / sizeof(WCHAR) : 0;
+
+        if (len % sizeof(WCHAR)) return E_INVALIDARG;
+        if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+        if (old) memcpy( new->bytes, utf16_old->bytes, len_old );
+        memcpy( new->bytes + len_old, utf16->bytes, len );
+        if (offset) *offset = len_old;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_BASE64:
+    {
+        const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
+        const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
+        WS_XML_BASE64_TEXT *new;
+        ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
+
+        if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+        if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
+        memcpy( new->bytes + len_old, base64->bytes, len );
+        if (offset) *offset = len_old;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_BOOL:
+    {
+        const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
+        WS_XML_BOOL_TEXT *new;
+
+        if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_INT32:
+    {
+        const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
+        WS_XML_INT32_TEXT *new;
+
+        if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_INT64:
+    {
+        const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
+        WS_XML_INT64_TEXT *new;
+
+        if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_UINT64:
+    {
+        const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
+        WS_XML_UINT64_TEXT *new;
+
+        if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_DOUBLE:
+    {
+        const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
+        WS_XML_DOUBLE_TEXT *new;
+
+        if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_GUID:
+    {
+        const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
+        WS_XML_GUID_TEXT *new;
+
+        if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_UNIQUE_ID:
+    {
+        const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
+        WS_XML_UNIQUE_ID_TEXT *new;
+
+        if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    case WS_XML_TEXT_TYPE_DATETIME:
+    {
+        const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
+        WS_XML_DATETIME_TEXT *new;
+
+        if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
+        *ret = &new->text;
+        return S_OK;
+    }
+    default:
+        FIXME( "unhandled text type %u\n", text->textType );
+        return E_NOTIMPL;
+    }
+}
+
 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
 {
     WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
-    WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
     HRESULT hr;
 
     switch (value->textType)
@@ -2037,7 +2165,7 @@ static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TE
     case WS_XML_TEXT_TYPE_GUID:
     case WS_XML_TEXT_TYPE_UNIQUE_ID:
     case WS_XML_TEXT_TYPE_DATETIME:
-        if (old) return WS_E_INVALID_OPERATION;
+        if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
         break;
 
     default:
@@ -2045,10 +2173,28 @@ static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TE
         return E_NOTIMPL;
     }
 
-    if ((hr = text_to_utf8text( value, old, &new )) != S_OK) return hr;
-
-    heap_free( old );
-    elem->attributes[elem->attributeCount - 1]->value = &new->text;
+    switch (writer->output_enc)
+    {
+    case WS_XML_WRITER_ENCODING_TYPE_TEXT:
+    {
+        WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
+        if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
+        heap_free( old );
+        elem->attributes[elem->attributeCount - 1]->value = &new->text;
+        break;
+    }
+    case WS_XML_WRITER_ENCODING_TYPE_BINARY:
+    {
+        WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
+        if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
+        heap_free( old );
+        elem->attributes[elem->attributeCount - 1]->value = new;
+        break;
+    }
+    default:
+        FIXME( "unhandled output encoding %u\n", writer->output_enc );
+        return E_NOTIMPL;
+    }
 
     return S_OK;
 }
@@ -2057,7 +2203,6 @@ static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *va
 {
     struct node *node;
     WS_XML_TEXT_NODE *text;
-    WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
 
     if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
@@ -2065,13 +2210,37 @@ static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *va
         node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
 
     if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
-    if ((hr = text_to_utf8text( value, NULL, &utf8 )) != S_OK)
+    text = (WS_XML_TEXT_NODE *)node;
+
+    switch (writer->output_enc)
     {
+    case WS_XML_WRITER_ENCODING_TYPE_TEXT:
+    {
+        WS_XML_UTF8_TEXT *new;
+        if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
+        {
+            heap_free( node );
+            return hr;
+        }
+        text->text = &new->text;
+        break;
+    }
+    case WS_XML_WRITER_ENCODING_TYPE_BINARY:
+    {
+        WS_XML_TEXT *new;
+        if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
+        {
+            heap_free( node );
+            return hr;
+        }
+        text->text = new;
+        break;
+    }
+    default:
+        FIXME( "unhandled output encoding %u\n", writer->output_enc );
         heap_free( node );
-        return hr;
+        return E_NOTIMPL;
     }
-    text = (WS_XML_TEXT_NODE *)node;
-    text->text = &utf8->text;
 
     write_insert_node( writer, writer->current, node );
     return S_OK;
@@ -2146,24 +2315,40 @@ static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG
 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
 {
     WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
-    ULONG offset;
+    ULONG offset = 0;
     HRESULT hr;
 
     if ((hr = write_flush( writer )) != S_OK) return hr;
     if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
     {
-        offset = 0;
         if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
         node = (WS_XML_TEXT_NODE *)writer->current;
     }
     else
     {
-        WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
-
-        offset = old->value.length;
-        if ((hr = text_to_utf8text( text, old, &new )) != S_OK) return hr;
-        heap_free( old );
-        node->text = &new->text;
+        switch (writer->output_enc)
+        {
+        case WS_XML_WRITER_ENCODING_TYPE_TEXT:
+        {
+            WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
+            offset = old->value.length;
+            if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
+            heap_free( old );
+            node->text = &new->text;
+            break;
+        }
+        case WS_XML_WRITER_ENCODING_TYPE_BINARY:
+        {
+            WS_XML_TEXT *new, *old = node->text;
+            if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
+            heap_free( old );
+            node->text = new;
+            break;
+        }
+        default:
+            FIXME( "unhandled output encoding %u\n", writer->output_enc );
+            return E_NOTIMPL;
+        }
     }
 
     if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
-- 
2.1.4




More information about the wine-patches mailing list