From 8214fcfa5d22f112e7d05de5a2b046014d92d1b8 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 30 May 2017 10:09:07 +0200 Subject: [PATCH] webservices: Add a builtin dictionary. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/msg.c | 2 +- dlls/webservices/reader.c | 301 +++++++++++++++++++------ dlls/webservices/tests/reader.c | 2 +- dlls/webservices/webservices_private.h | 1 + dlls/webservices/writer.c | 41 ++-- 5 files changed, 261 insertions(+), 86 deletions(-) diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c index 2c6667ac6bc..3032c831651 100644 --- a/dlls/webservices/msg.c +++ b/dlls/webservices/msg.c @@ -119,7 +119,7 @@ static void free_header( struct header *header ) { heap_free( header->name.bytes ); heap_free( header->ns.bytes ); - if (header->mapped) heap_free( header->u.text ); + if (header->mapped) free_xml_string( header->u.text ); heap_free( header ); } diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 8485ad65c17..01b464fab50 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -70,6 +70,202 @@ HRESULT prop_get( const struct prop *prop, ULONG count, ULONG id, void *buf, ULO return S_OK; } +static CRITICAL_SECTION dict_cs; +static CRITICAL_SECTION_DEBUG dict_cs_debug = +{ + 0, 0, &dict_cs, + {&dict_cs_debug.ProcessLocksList, + &dict_cs_debug.ProcessLocksList}, + 0, 0, {(DWORD_PTR)(__FILE__ ": dict_cs")} +}; +static CRITICAL_SECTION dict_cs = {&dict_cs_debug, -1, 0, 0, 0, 0}; + +static ULONG dict_size, *dict_sorted; +static WS_XML_DICTIONARY dict_builtin = +{ + {0x82704485,0x222a,0x4f7c,{0xb9,0x7b,0xe9,0xa4,0x62,0xa9,0x66,0x2b}} +}; + +static inline int cmp_string( const unsigned char *str, ULONG len, const unsigned char *str2, ULONG len2 ) +{ + if (len < len2) return -1; + else if (len > len2) return 1; + while (len--) + { + if (*str == *str2) { str++; str2++; } + else return *str - *str2; + } + return 0; +} + +/* return -1 and string id if found, sort index if not found */ +static int find_string( const unsigned char *data, ULONG len, ULONG *id ) +{ + int i, c, min = 0, max = dict_builtin.stringCount - 1; + while (min <= max) + { + i = (min + max) / 2; + c = cmp_string( data, len, + dict_builtin.strings[dict_sorted[i]].bytes, + dict_builtin.strings[dict_sorted[i]].length ); + if (c < 0) + max = i - 1; + else if (c > 0) + min = i + 1; + else + { + *id = dict_builtin.strings[dict_sorted[i]].id; + return -1; + } + } + return max + 1; +} + +#define MIN_DICTIONARY_SIZE 256 +#define MAX_DICTIONARY_SIZE 2048 + +static BOOL grow_dict( ULONG size ) +{ + WS_XML_STRING *tmp; + ULONG new_size, *tmp_sorted; + + if (dict_size >= dict_builtin.stringCount + size) return TRUE; + if (dict_size + size > MAX_DICTIONARY_SIZE) return FALSE; + + if (!dict_builtin.strings) + { + new_size = max( MIN_DICTIONARY_SIZE, size ); + if (!(dict_builtin.strings = heap_alloc( new_size * sizeof(WS_XML_STRING) ))) return FALSE; + if (!(dict_sorted = heap_alloc( new_size * sizeof(ULONG) ))) + { + heap_free( dict_builtin.strings ); + dict_builtin.strings = NULL; + return FALSE; + } + dict_size = new_size; + return TRUE; + } + + new_size = max( dict_size * 2, size ); + if (!(tmp = heap_realloc( dict_builtin.strings, new_size * sizeof(*tmp) ))) return FALSE; + dict_builtin.strings = tmp; + if (!(tmp_sorted = heap_realloc( dict_sorted, new_size * sizeof(*tmp_sorted) ))) return FALSE; + dict_sorted = tmp_sorted; + + dict_size = new_size; + return TRUE; +} + +static BOOL insert_string( unsigned char *data, ULONG len, int i, ULONG *ret_id ) +{ + ULONG id = dict_builtin.stringCount; + if (!grow_dict( 1 )) return FALSE; + memmove( &dict_sorted[i] + 1, &dict_sorted[i], (dict_builtin.stringCount - i) * sizeof(WS_XML_STRING *) ); + dict_sorted[i] = id; + + dict_builtin.strings[id].length = len; + dict_builtin.strings[id].bytes = data; + dict_builtin.strings[id].dictionary = &dict_builtin; + dict_builtin.strings[id].id = id; + dict_builtin.stringCount++; + *ret_id = id; + return TRUE; +} + +static HRESULT add_xml_string( WS_XML_STRING *str ) +{ + int index; + ULONG id; + + if (str->dictionary) return S_OK; + + EnterCriticalSection( &dict_cs ); + if ((index = find_string( str->bytes, str->length, &id )) == -1) + { + heap_free( str->bytes ); + *str = dict_builtin.strings[id]; + LeaveCriticalSection( &dict_cs ); + return S_OK; + } + if (insert_string( str->bytes, str->length, index, &id )) + { + *str = dict_builtin.strings[id]; + LeaveCriticalSection( &dict_cs ); + return S_OK; + } + LeaveCriticalSection( &dict_cs ); + return WS_E_QUOTA_EXCEEDED; +} + +WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len ) +{ + WS_XML_STRING *ret; + + if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL; + if ((ret->length = len) && !(ret->bytes = heap_alloc( len ))) + { + heap_free( ret ); + return NULL; + } + if (data) + { + memcpy( ret->bytes, data, len ); + if (add_xml_string( ret ) != S_OK) WARN( "string not added to dictionary\n" ); + } + return ret; +} + +void free_xml_string( WS_XML_STRING *str ) +{ + if (!str) return; + if (!str->dictionary) heap_free( str->bytes ); + heap_free( str ); +} + +WS_XML_STRING *dup_xml_string( const WS_XML_STRING *src ) +{ + WS_XML_STRING *ret; + unsigned char *data; + int index; + ULONG id; + + if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL; + if (src->dictionary) + { + *ret = *src; + return ret; + } + + EnterCriticalSection( &dict_cs ); + if ((index = find_string( src->bytes, src->length, &id )) == -1) + { + *ret = dict_builtin.strings[id]; + LeaveCriticalSection( &dict_cs ); + return ret; + } + if (!(data = heap_alloc( src->length ))) + { + heap_free( ret ); + LeaveCriticalSection( &dict_cs ); + return NULL; + } + memcpy( data, src->bytes, src->length ); + if (insert_string( data, src->length, index, &id )) + { + *ret = dict_builtin.strings[id]; + LeaveCriticalSection( &dict_cs ); + return ret; + } + LeaveCriticalSection( &dict_cs ); + + WARN( "string not added to dictionary\n" ); + ret->length = src->length; + ret->bytes = data; + ret->dictionary = NULL; + ret->id = 0; + return ret; +} + struct node *alloc_node( WS_XML_NODE_TYPE type ) { struct node *ret; @@ -84,9 +280,9 @@ struct node *alloc_node( WS_XML_NODE_TYPE type ) void free_attribute( WS_XML_ATTRIBUTE *attr ) { if (!attr) return; - heap_free( attr->prefix ); - heap_free( attr->localName ); - heap_free( attr->ns ); + free_xml_string( attr->prefix ); + free_xml_string( attr->localName ); + free_xml_string( attr->ns ); heap_free( attr->value ); heap_free( attr ); } @@ -103,9 +299,9 @@ void free_node( struct node *node ) for (i = 0; i < elem->attributeCount; i++) free_attribute( elem->attributes[i] ); heap_free( elem->attributes ); - heap_free( elem->prefix ); - heap_free( elem->localName ); - heap_free( elem->ns ); + free_xml_string( elem->prefix ); + free_xml_string( elem->localName ); + free_xml_string( elem->ns ); break; } case WS_XML_NODE_TYPE_TEXT: @@ -351,8 +547,8 @@ enum reader_state struct prefix { - WS_XML_STRING str; - WS_XML_STRING ns; + WS_XML_STRING *str; + WS_XML_STRING *ns; }; struct reader @@ -411,13 +607,10 @@ static void clear_prefixes( struct prefix *prefixes, ULONG count ) ULONG i; for (i = 0; i < count; i++) { - heap_free( prefixes[i].str.bytes ); - prefixes[i].str.bytes = NULL; - prefixes[i].str.length = 0; - - heap_free( prefixes[i].ns.bytes ); - prefixes[i].ns.bytes = NULL; - prefixes[i].ns.length = 0; + free_xml_string( prefixes[i].str ); + prefixes[i].str = NULL; + free_xml_string( prefixes[i].ns ); + prefixes[i].ns = NULL; } } @@ -425,17 +618,11 @@ static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, cons { if (str) { - heap_free( prefix->str.bytes ); - if (!(prefix->str.bytes = heap_alloc( str->length ))) return E_OUTOFMEMORY; - memcpy( prefix->str.bytes, str->bytes, str->length ); - prefix->str.length = str->length; + free_xml_string( prefix->str ); + if (!(prefix->str = dup_xml_string( str ))) return E_OUTOFMEMORY; } - - heap_free( prefix->ns.bytes ); - if (!(prefix->ns.bytes = heap_alloc( ns->length ))) return E_OUTOFMEMORY; - memcpy( prefix->ns.bytes, ns->bytes, ns->length ); - prefix->ns.length = ns->length; - + if (prefix->ns) free_xml_string( prefix->ns ); + if (!(prefix->ns = dup_xml_string( ns ))) return E_OUTOFMEMORY; return S_OK; } @@ -446,7 +633,7 @@ static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, for (i = 0; i < reader->nb_prefixes; i++) { - if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK) + if (WsXmlStringEquals( prefix, reader->prefixes[i].str, NULL ) == S_OK) return set_prefix( &reader->prefixes[i], NULL, ns ); } if (i >= reader->nb_prefixes_allocated) @@ -457,7 +644,6 @@ static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, reader->prefixes = tmp; reader->nb_prefixes_allocated *= 2; } - if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr; reader->nb_prefixes++; return S_OK; @@ -468,8 +654,8 @@ static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_S ULONG i; for (i = 0; i < reader->nb_prefixes; i++) { - if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK) - return &reader->prefixes[i].ns; + if (WsXmlStringEquals( prefix, reader->prefixes[i].str, NULL ) == S_OK) + return reader->prefixes[i].ns; } return NULL; } @@ -511,7 +697,9 @@ static void free_reader( struct reader *reader ) static HRESULT init_reader( struct reader *reader ) { + static const WS_XML_STRING empty = {0, NULL}; struct node *node; + HRESULT hr; reader->state = READER_STATE_INITIAL; destroy_nodes( reader->root ); @@ -519,10 +707,12 @@ static HRESULT init_reader( struct reader *reader ) reader->current_attr = 0; clear_prefixes( reader->prefixes, reader->nb_prefixes ); reader->nb_prefixes = 1; + if ((hr = bind_prefix( reader, &empty, &empty )) != S_OK) return hr; + if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY; read_insert_eof( reader, node ); reader->input_enc = WS_XML_READER_ENCODING_TYPE_TEXT; - reader->dict = NULL; + reader->dict = &dict_builtin; return S_OK; } @@ -786,33 +976,6 @@ HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *at return E_NOTIMPL; } -WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len ) -{ - WS_XML_STRING *ret; - - if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL; - ret->length = len; - ret->bytes = len ? (BYTE *)(ret + 1) : NULL; - ret->dictionary = NULL; - ret->id = 0; - if (data) memcpy( ret->bytes, data, len ); - return ret; -} - -WS_XML_STRING *dup_xml_string( const WS_XML_STRING *src ) -{ - WS_XML_STRING *ret; - - if (!src->dictionary) return alloc_xml_string( src->bytes, src->length ); - - if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL; - ret->length = src->length; - ret->bytes = src->bytes; - ret->dictionary = src->dictionary; - ret->id = src->id; - return ret; -} - WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len ) { WS_XML_UTF8_TEXT *ret; @@ -1036,7 +1199,7 @@ static HRESULT parse_name( const unsigned char *str, ULONG len, WS_XML_STRING ** if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY; if (!(*localname = alloc_xml_string( localname_ptr, localname_len ))) { - heap_free( *prefix ); + free_xml_string( *prefix ); *prefix = NULL; return E_OUTOFMEMORY; } @@ -1274,8 +1437,12 @@ static HRESULT read_string( struct reader *reader, WS_XML_STRING **str ) HRESULT hr; if ((hr = read_int31( reader, &len )) != S_OK) return hr; if (!(*str = alloc_xml_string( NULL, len ))) return E_OUTOFMEMORY; - if ((hr = read_bytes( reader, (*str)->bytes, len )) == S_OK) return S_OK; - heap_free( *str ); + if ((hr = read_bytes( reader, (*str)->bytes, len )) == S_OK) + { + if (add_xml_string( *str ) != S_OK) WARN( "string not added to dictionary\n" ); + return S_OK; + } + free_xml_string( *str ); return hr; } @@ -1350,11 +1517,11 @@ static HRESULT read_attribute_text( struct reader *reader, WS_XML_ATTRIBUTE **re if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) goto error; if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK) { - heap_free( prefix ); + free_xml_string( prefix ); attr->isXmlNs = 1; if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length ))) { - heap_free( localname ); + free_xml_string( localname ); hr = E_OUTOFMEMORY; goto error; } @@ -1524,15 +1691,15 @@ static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem ULONG i; if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT; - if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY; - if (!elem->ns->length) elem->ns->bytes = (BYTE *)(elem->ns + 1); /* quirk */ + if (!(elem->ns = dup_xml_string( ns ))) return E_OUTOFMEMORY; for (i = 0; i < elem->attributeCount; i++) { WS_XML_ATTRIBUTE *attr = elem->attributes[i]; if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue; if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT; - if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY; + if (!(attr->ns = alloc_xml_string( NULL, ns->length ))) return E_OUTOFMEMORY; + if (attr->ns->length) memcpy( attr->ns->bytes, ns->bytes, ns->length ); } return S_OK; } @@ -1990,8 +2157,8 @@ static HRESULT read_endelement_text( struct reader *reader ) if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) return hr; parent = find_startelement( reader, prefix, localname ); - heap_free( prefix ); - heap_free( localname ); + free_xml_string( prefix ); + free_xml_string( localname ); if (!parent) return WS_E_INVALID_FORMAT; reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry ); diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 7eab4b8215f..0e21e864bcd 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -4554,7 +4554,7 @@ static void test_binary_encoding(void) ok( elem->prefix->bytes == NULL, "bytes set\n" ); ok( elem->localName->length == 1, "got %u\n", elem->localName->length ); ok( !memcmp( elem->localName->bytes, "t", 1 ), "wrong name\n" ); - todo_wine ok( elem->localName->dictionary != NULL, "dictionary not set\n" ); + ok( elem->localName->dictionary != NULL, "dictionary not set\n" ); ok( !elem->ns->length, "got %u\n", elem->ns->length ); ok( elem->ns->bytes != NULL, "bytes not set\n" ); ok( !elem->attributeCount, "got %u\n", elem->attributeCount ); diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index d117ebaf048..db839b447a5 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -36,6 +36,7 @@ void free_xmlbuf( struct xmlbuf * ) 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; +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; diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index d22d5e49f33..1b1ac5d1510 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -83,6 +83,7 @@ struct writer WS_XML_WRITER_OUTPUT_TYPE output_type; struct xmlbuf *output_buf; WS_HEAP *output_heap; + WS_XML_DICTIONARY *dict; ULONG prop_count; struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])]; }; @@ -109,7 +110,7 @@ static struct writer *alloc_writer(void) static void free_writer( struct writer *writer ) { destroy_nodes( writer->root ); - heap_free( writer->current_ns ); + free_xml_string( writer->current_ns ); WsFreeHeap( writer->output_heap ); writer->cs.DebugInfo->Spare[0] = 0; @@ -157,13 +158,14 @@ static HRESULT init_writer( struct writer *writer ) writer->write_bufptr = NULL; destroy_nodes( writer->root ); writer->root = writer->current = NULL; - heap_free( writer->current_ns ); + free_xml_string( writer->current_ns ); writer->current_ns = NULL; if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY; write_insert_eof( writer, node ); writer->state = WRITER_STATE_INITIAL; writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT; + writer->dict = NULL; return S_OK; } @@ -379,7 +381,9 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING } case WS_XML_WRITER_ENCODING_TYPE_BINARY: { + WS_XML_WRITER_BINARY_ENCODING *bin = (WS_XML_WRITER_BINARY_ENCODING *)encoding; writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY; + writer->dict = bin->staticDictionary; break; } default: @@ -665,25 +669,26 @@ static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TE } } -static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr ) +static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict ) { if (!attr->prefix || !attr->prefix->length) { - if (attr->localName->dictionary) return RECORD_SHORT_DICTIONARY_ATTRIBUTE; + if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE; return RECORD_SHORT_ATTRIBUTE; } if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z') { - if (attr->localName->dictionary) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a'; + if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a'; return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a'; } - if (attr->localName->dictionary) return RECORD_DICTIONARY_ATTRIBUTE; + if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE; return RECORD_ATTRIBUTE; }; static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr ) { - enum record_type type = get_attr_record_type( attr ); + BOOL use_dict = (writer->dict && attr->localName->dictionary == writer->dict); + enum record_type type = get_attr_record_type( attr, use_dict ); HRESULT hr; if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr; @@ -817,20 +822,21 @@ static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_X return S_OK; } -static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr ) +static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict ) { if (!attr->prefix || !attr->prefix->length) { - if (attr->ns->dictionary) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE; + if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE; return RECORD_SHORT_XMLNS_ATTRIBUTE; } - if (attr->ns->dictionary) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE; + if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE; return RECORD_XMLNS_ATTRIBUTE; }; static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr ) { - enum record_type type = get_xmlns_record_type( attr ); + BOOL use_dict = (writer->dict && attr->ns->dictionary == writer->dict); + enum record_type type = get_xmlns_record_type( attr, use_dict ); HRESULT hr; if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr; @@ -932,7 +938,7 @@ static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING { WS_XML_STRING *str; if (!(str = dup_xml_string( ns ))) return E_OUTOFMEMORY; - heap_free( writer->current_ns ); + free_xml_string( writer->current_ns ); writer->current_ns = str; return S_OK; } @@ -1029,26 +1035,27 @@ static HRESULT write_startelement_text( struct writer *writer ) return write_attributes( writer, elem ); } -static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem ) +static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict ) { if (!elem->prefix || !elem->prefix->length) { - if (elem->localName->dictionary) return RECORD_SHORT_DICTIONARY_ELEMENT; + if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT; return RECORD_SHORT_ELEMENT; } if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z') { - if (elem->localName->dictionary) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a'; + if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a'; return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a'; } - if (elem->localName->dictionary) return RECORD_DICTIONARY_ELEMENT; + if (use_dict) return RECORD_DICTIONARY_ELEMENT; return RECORD_ELEMENT; }; static HRESULT write_startelement_bin( struct writer *writer ) { const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr; - enum record_type type = get_elem_record_type( elem ); + BOOL use_dict = (writer->dict && elem->localName->dictionary == writer->dict); + enum record_type type = get_elem_record_type( elem, use_dict ); HRESULT hr; if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;