[2/2] webservices: Add support for dynamic string callbacks.

Hans Leidekker hans at codeweavers.com
Thu Jun 22 03:43:11 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/tests/writer.c | 81 ++++++++++++++++++++++++++++++++++++++++-
 dlls/webservices/writer.c       | 55 ++++++++++++++++++++--------
 2 files changed, 118 insertions(+), 18 deletions(-)

diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index 2d16cfc..cf8ab61 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -3649,6 +3649,34 @@ static const WS_XML_STRING *init_xmlstring_dict( WS_XML_DICTIONARY *dict, ULONG
     return str;
 }
 
+static HRESULT CALLBACK dict_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
+{
+    ULONG *call_count = state;
+
+    (*call_count)++;
+    switch (str->bytes[0])
+    {
+    case 't':
+        *id = 1;
+        *found = TRUE;
+        break;
+
+    case 'n':
+        *id = 2;
+        *found = TRUE;
+        break;
+
+    case 'v':
+        *found = FALSE;
+        return WS_E_OTHER;
+
+    default:
+        *found = FALSE;
+        break;
+    }
+    return S_OK;
+}
+
 static void test_dictionary(void)
 {
     static const char res[] =
@@ -3659,6 +3687,12 @@ static void test_dictionary(void)
         {0x53,0x06,0x0b,0x01,'p',0x0a,0x01};
     static const char res4[] =
         {0x43,0x02,'p','2',0x06,0x0b,0x02,'p','2',0x0a,0x01};
+    static const char res5[] =
+        {0x42,0x03,0x0a,0x05,0x01};
+    static const char res6[] =
+        {0x40,0x01,0x75,0x0a,0x05,0x01};
+    static const char res7[] =
+        {0x40,0x01,0x76,0x0a,0x05,0x01};
     static const char res100[] =
         {0x42,0x06,0x06,0x06,0x98,0x00,0x01};
     static const char res101[] =
@@ -3672,7 +3706,7 @@ static void test_dictionary(void)
     WS_XML_DICTIONARY dict;
     WS_XML_WRITER *writer;
     HRESULT hr;
-    ULONG i;
+    ULONG i, call_count;
     static const struct
     {
         ULONG       prefix;
@@ -3768,12 +3802,55 @@ static void test_dictionary(void)
         hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
         ok( hr == S_OK, "%u: got %08x\n", i, hr );
         hr = WsWriteEndAttribute( writer, NULL );
-        ok( hr == S_OK, "got %08x\n", hr );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
         hr = WsWriteEndElement( writer, NULL );
         ok( hr == S_OK, "%u: got %08x\n", i, hr );
         if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
     }
 
+    /* callback */
+    bin.staticDictionary = NULL;
+    bin.dynamicStringCallback = dict_cb;
+    bin.dynamicStringCallbackState = &call_count;
+
+    hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    init_xmlstring( "t", &localname );
+    init_xmlstring( "ns", &ns );
+    call_count = 0;
+    hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( call_count == 2, "got %u\n", call_count );
+    check_output_bin( writer, res5, sizeof(res5), __LINE__ );
+
+    /* unknown string */
+    hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    init_xmlstring( "u", &localname );
+    init_xmlstring( "ns", &ns );
+    call_count = 0;
+    hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( call_count == 2, "got %u\n", call_count );
+    check_output_bin( writer, res6, sizeof(res6), __LINE__ );
+
+    /* unknown string, error return from callback */
+    hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    init_xmlstring( "v", &localname );
+    init_xmlstring( "ns", &ns );
+    call_count = 0;
+    hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( call_count == 2, "got %u\n", call_count );
+    check_output_bin( writer, res7, sizeof(res7), __LINE__ );
+
     WsFreeWriter( writer );
 }
 
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 67ae1b7..9c479b2 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -85,6 +85,8 @@ struct writer
     struct xmlbuf               *output_buf;
     WS_HEAP                     *output_heap;
     WS_XML_DICTIONARY           *dict;
+    WS_DYNAMIC_STRING_CALLBACK   dict_cb;
+    void                        *dict_cb_state;
     ULONG                        prop_count;
     struct prop                  prop[sizeof(writer_props)/sizeof(writer_props[0])];
 };
@@ -168,6 +170,8 @@ static HRESULT init_writer( struct writer *writer )
     writer->output_enc     = WS_XML_WRITER_ENCODING_TYPE_TEXT;
     writer->output_charset = WS_CHARSET_UTF8;
     writer->dict           = NULL;
+    writer->dict_cb        = NULL;
+    writer->dict_cb_state  = NULL;
     return S_OK;
 }
 
@@ -388,6 +392,8 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING
         writer->output_enc     = WS_XML_WRITER_ENCODING_TYPE_BINARY;
         writer->output_charset = 0;
         writer->dict           = bin->staticDictionary;
+        writer->dict_cb        = bin->dynamicStringCallback;
+        writer->dict_cb_state  = bin->dynamicStringCallbackState;
         break;
     }
     default:
@@ -638,8 +644,8 @@ static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len
 static HRESULT write_dict_string( struct writer *writer, ULONG id )
 {
     HRESULT hr;
-    if (id > 0x3fffffff) return E_INVALIDARG;
-    if ((hr = write_int31( writer, id << 1 )) != S_OK) return hr;
+    if (id > 0x7fffffff) return E_INVALIDARG;
+    if ((hr = write_int31( writer, id )) != S_OK) return hr;
     return S_OK;
 }
 
@@ -678,6 +684,23 @@ static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TE
     }
 }
 
+static BOOL lookup_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
+{
+    if (writer->dict && str->dictionary == writer->dict)
+    {
+        *id = str->id << 1;
+        return TRUE;
+    }
+    if (writer->dict_cb)
+    {
+        BOOL found = FALSE;
+        writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
+        if (found) *id = (*id << 1) | 1;
+        return found;
+    }
+    return FALSE;
+}
+
 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
 {
     if (!attr->prefix || !attr->prefix->length)
@@ -696,8 +719,8 @@ static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL
 
 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
 {
-    BOOL use_dict = (writer->dict && attr->localName->dictionary == writer->dict);
-    enum record_type type = get_attr_record_type( attr, use_dict );
+    ULONG id;
+    enum record_type type = get_attr_record_type( attr, lookup_string_id(writer, attr->localName, &id) );
     HRESULT hr;
 
     if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@@ -710,7 +733,7 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
     }
     if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
     {
-        if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         return write_attribute_value_bin( writer, attr->value );
     }
 
@@ -726,12 +749,12 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
         break;
 
     case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
-        if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         break;
 
     case RECORD_DICTIONARY_ATTRIBUTE:
         if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
-        if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         break;
 
     default:
@@ -844,8 +867,8 @@ static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOO
 
 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
 {
-    BOOL use_dict = (writer->dict && attr->ns->dictionary == writer->dict);
-    enum record_type type = get_xmlns_record_type( attr, use_dict );
+    ULONG id;
+    enum record_type type = get_xmlns_record_type( attr, lookup_string_id(writer, attr->ns, &id) );
     HRESULT hr;
 
     if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@@ -861,11 +884,11 @@ static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XM
         break;
 
     case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
-        return write_dict_string( writer, attr->ns->id );
+        return write_dict_string( writer, id );
 
     case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
         if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
-        return write_dict_string( writer, attr->ns->id );
+        return write_dict_string( writer, id );
 
     default:
         ERR( "unhandled record type %02x\n", type );
@@ -1063,8 +1086,8 @@ static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, B
 static HRESULT write_startelement_bin( struct writer *writer )
 {
     const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
-    BOOL use_dict = (writer->dict && elem->localName->dictionary == writer->dict);
-    enum record_type type = get_elem_record_type( elem, use_dict );
+    ULONG id;
+    enum record_type type = get_elem_record_type( elem, lookup_string_id(writer, elem->localName, &id) );
     HRESULT hr;
 
     if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@@ -1077,7 +1100,7 @@ static HRESULT write_startelement_bin( struct writer *writer )
     }
     if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
     {
-        if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         return write_attributes( writer, elem );
     }
 
@@ -1093,12 +1116,12 @@ static HRESULT write_startelement_bin( struct writer *writer )
         break;
 
     case RECORD_SHORT_DICTIONARY_ELEMENT:
-        if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         break;
 
     case RECORD_DICTIONARY_ELEMENT:
         if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
-        if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
+        if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
         break;
 
     default:
-- 
2.1.4




More information about the wine-patches mailing list