From 14c1cd97e5e6ac9bcf0190bbef891a434b60b8bb Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 14 Jun 2017 11:07:27 +0200 Subject: [PATCH] webservices: Support more text record types in the reader. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/reader.c | 336 +++++++++++++++++++++++-- dlls/webservices/webservices_private.h | 11 + dlls/webservices/writer.c | 20 +- 3 files changed, 331 insertions(+), 36 deletions(-) diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index bd0c81a4e2f..125c3bd146e 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -1260,14 +1260,77 @@ static HRESULT read_dict_string( struct reader *reader, WS_XML_STRING **str ) return S_OK; } +static HRESULT read_datetime( struct reader *reader, WS_DATETIME *ret ) +{ + UINT64 val; + HRESULT hr; + + if ((hr = read_bytes( reader, (unsigned char *)&val, sizeof(val) )) != S_OK) return hr; + + if ((val & 0x03) == 1) ret->format = WS_DATETIME_FORMAT_UTC; + else if ((val & 0x03) == 2) ret->format = WS_DATETIME_FORMAT_LOCAL; + else ret->format = WS_DATETIME_FORMAT_NONE; + + if ((ret->ticks = val >> 2) > TICKS_MAX) return WS_E_INVALID_FORMAT; + return S_OK; +} + +static HRESULT read_encode_base64( struct reader *reader, ULONG len, unsigned char *buf, ULONG *ret_len ) +{ + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned char byte; + ULONG i = 0, x; + HRESULT hr; + + while (len > 0) + { + if ((hr = read_byte( reader, &byte )) != S_OK) return hr; + buf[i++] = base64[(byte & 0xfc) >> 2]; + x = (byte & 3) << 4; + if (len == 1) + { + buf[i++] = base64[x]; + buf[i++] = '='; + buf[i++] = '='; + break; + } + if ((hr = read_byte( reader, &byte )) != S_OK) return hr; + buf[i++] = base64[x | ((byte & 0xf0) >> 4)]; + x = (byte & 0x0f) << 2; + if (len == 2) + { + buf[i++] = base64[x]; + buf[i++] = '='; + break; + } + if ((hr = read_byte( reader, &byte )) != S_OK) return hr; + buf[i++] = base64[x | ((byte & 0xc0) >> 6)]; + buf[i++] = base64[byte & 0x3f]; + len -= 3; + } + *ret_len = i; + return S_OK; +} + 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; - unsigned char type; + unsigned char type, buf[46]; + 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; - ULONG len; if ((hr = read_byte( reader, &type )) != S_OK) return hr; if (!is_text_type( type )) return WS_E_INVALID_FORMAT; @@ -1290,26 +1353,123 @@ static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE if (!(utf8 = alloc_utf8_text( true, sizeof(true) ))) return E_OUTOFMEMORY; break; - case RECORD_CHARS8_TEXT: - { - unsigned char len8; - if ((hr = read_byte( reader, &len8 )) != S_OK) return hr; - len = len8; + case RECORD_INT8_TEXT: + 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; - } + + case RECORD_INT16_TEXT: + 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; + + 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; + + case RECORD_INT64_TEXT: + 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; + + 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; + + 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; + + case RECORD_CHARS8_TEXT: + if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr; + len = val_uint8; + break; + + case RECORD_CHARS16_TEXT: + if ((hr = read_bytes( reader, (unsigned char *)&val_uint16, sizeof(val_uint16) )) != S_OK) return hr; + len = val_uint16; + break; + + case RECORD_CHARS32_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; + len = val_int32; + break; + + case RECORD_BYTES8_TEXT: + if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr; + if (!(utf8 = alloc_utf8_text( NULL, ((4 * val_uint8 / 3) + 3) & ~3 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_uint8, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + heap_free( utf8 ); + return hr; + } + break; + + case RECORD_BYTES16_TEXT: + if ((hr = read_byte( reader, (unsigned char *)&val_uint16 )) != S_OK) return hr; + if (!(utf8 = alloc_utf8_text( NULL, ((4 * val_uint16 / 3) + 3) & ~3 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_uint16, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + heap_free( utf8 ); + return hr; + } + break; + + case RECORD_BYTES32_TEXT: + if ((hr = read_byte( reader, (unsigned char *)&val_int32 )) != S_OK) return hr; + if (val_int32 < 0) return WS_E_INVALID_FORMAT; + if (!(utf8 = alloc_utf8_text( NULL, ((4 * val_int32 / 3) + 3) & ~3 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_int32, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + heap_free( utf8 ); + return hr; + } + break; + case RECORD_EMPTY_TEXT: len = 0; break; case RECORD_DICTIONARY_TEXT: - { - ULONG id; if ((hr = read_int31( reader, &id )) != S_OK) return hr; if (!reader->dict || (id >>= 1) >= reader->dict->stringCount) return WS_E_INVALID_FORMAT; if (!(utf8 = alloc_utf8_text( reader->dict->strings[id].bytes, reader->dict->strings[id].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; + + 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; + + 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; + + 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; default: ERR( "unhandled record type %02x\n", type ); @@ -1787,21 +1947,21 @@ static HRESULT read_text_text( struct reader *reader ) return S_OK; } -static struct node *alloc_text_node( const unsigned char *data, ULONG len, unsigned char **ptr ) +static struct node *alloc_text_node( const unsigned char *data, ULONG len, WS_XML_UTF8_TEXT **ret ) { struct node *node; WS_XML_UTF8_TEXT *utf8; WS_XML_TEXT_NODE *text; if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL; - text = (WS_XML_TEXT_NODE *)node; if (!(utf8 = alloc_utf8_text( data, len ))) { heap_free( node ); return NULL; } + text = (WS_XML_TEXT_NODE *)node; text->text = &utf8->text; - if (ptr) *ptr = utf8->value.bytes; + if (ret) *ret = utf8; return node; } @@ -1809,9 +1969,21 @@ 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, *ptr; + unsigned char type, buf[46]; struct node *node = NULL, *parent; - ULONG len; + WS_XML_UTF8_TEXT *utf8; + 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; if ((hr = read_byte( reader, &type )) != S_OK) return hr; @@ -1839,14 +2011,100 @@ static HRESULT read_text_bin( struct reader *reader ) if (!(node = alloc_text_node( true, sizeof(true), NULL ))) return E_OUTOFMEMORY; break; + case RECORD_INT8_TEXT: + case RECORD_INT8_TEXT_WITH_ENDELEMENT: + if ((hr = read_byte( reader, (unsigned char *)&val_int8 )) != S_OK) return hr; + len = format_int8( &val_int8, buf ); + if (!(node = alloc_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_INT16_TEXT: + case RECORD_INT16_TEXT_WITH_ENDELEMENT: + 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_text_node( buf, len, NULL ))) 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_INT64_TEXT: + case RECORD_INT64_TEXT_WITH_ENDELEMENT: + 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_DOUBLE_TEXT: + case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT: + 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_DATETIME_TEXT: + case RECORD_DATETIME_TEXT_WITH_ENDELEMENT: + if ((hr = read_datetime( reader, &datetime )) != S_OK) return hr; + len = format_datetime( &datetime, buf ); + if (!(node = alloc_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + case RECORD_CHARS8_TEXT: case RECORD_CHARS8_TEXT_WITH_ENDELEMENT: - { - unsigned char len8; - if ((hr = read_byte( reader, &len8 )) != S_OK) return hr; - len = len8; + if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr; + len = val_uint8; + break; + + case RECORD_CHARS16_TEXT: + case RECORD_CHARS16_TEXT_WITH_ENDELEMENT: + if ((hr = read_bytes( reader, (unsigned char *)&val_uint16, sizeof(val_uint16) )) != S_OK) return hr; + len = val_uint16; + break; + + case RECORD_CHARS32_TEXT: + case RECORD_CHARS32_TEXT_WITH_ENDELEMENT: + 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; + len = val_int32; + break; + + case RECORD_BYTES8_TEXT: + case RECORD_BYTES8_TEXT_WITH_ENDELEMENT: + if ((hr = read_byte( reader, (unsigned char *)&val_uint8 )) != S_OK) return hr; + if (!(node = alloc_text_node( NULL, ((4 * val_uint8 / 3) + 3) & ~3, &utf8 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_uint8, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + free_node( node ); + return hr; + } + break; + + case RECORD_BYTES16_TEXT: + case RECORD_BYTES16_TEXT_WITH_ENDELEMENT: + if ((hr = read_byte( reader, (unsigned char *)&val_uint16 )) != S_OK) return hr; + if (!(node = alloc_text_node( NULL, ((4 * val_uint16 / 3) + 3) & ~3, &utf8 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_uint16, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + free_node( node ); + return hr; + } + break; + + case RECORD_BYTES32_TEXT: + case RECORD_BYTES32_TEXT_WITH_ENDELEMENT: + if ((hr = read_byte( reader, (unsigned char *)&val_int32 )) != S_OK) return hr; + if (val_int32 < 0) return WS_E_INVALID_FORMAT; + if (!(node = alloc_text_node( NULL, ((4 * val_int32 / 3) + 3) & ~3, &utf8 ))) return E_OUTOFMEMORY; + if ((hr = read_encode_base64( reader, val_int32, utf8->value.bytes, &utf8->value.length )) != S_OK) + { + free_node( node ); + return hr; + } break; - } case RECORD_EMPTY_TEXT: case RECORD_EMPTY_TEXT_WITH_ENDELEMENT: @@ -1855,14 +2113,40 @@ static HRESULT read_text_bin( struct reader *reader ) case RECORD_DICTIONARY_TEXT: case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT: - { - ULONG id; if ((hr = read_int31( reader, &id )) != S_OK) return hr; if (!reader->dict || (id >>= 1) >= reader->dict->stringCount) return WS_E_INVALID_FORMAT; if (!(node = alloc_text_node( reader->dict->strings[id].bytes, reader->dict->strings[id].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_text_node( buf, len, NULL ))) 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_UINT64_TEXT: + case RECORD_UINT64_TEXT_WITH_ENDELEMENT: + 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + + case RECORD_BOOL_TEXT: + case RECORD_BOOL_TEXT_WITH_ENDELEMENT: + 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_text_node( buf, len, NULL ))) return E_OUTOFMEMORY; + break; + default: ERR( "unhandled record type %02x\n", type ); return WS_E_NOT_SUPPORTED; @@ -1870,8 +2154,8 @@ static HRESULT read_text_bin( struct reader *reader ) if (!node) { - if (!(node = alloc_text_node( NULL, len, &ptr ))) return E_OUTOFMEMORY; - if ((hr = read_bytes( reader, ptr, len )) != S_OK) + if (!(node = alloc_text_node( NULL, len, &utf8 ))) return E_OUTOFMEMORY; + if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK) { free_node( node ); return hr; diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index 1ae81e9fd29..7dc299478d3 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -36,6 +36,17 @@ void free_xmlbuf( struct xmlbuf * ) DECLSPEC_HIDDEN; WS_XML_DICTIONARY dict_builtin DECLSPEC_HIDDEN; const WS_XML_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; diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 1b1ac5d1510..4de60de2ece 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -1577,7 +1577,7 @@ HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING * return hr; } -static ULONG format_bool( const BOOL *ptr, unsigned char *buf ) +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) @@ -1589,22 +1589,22 @@ static ULONG format_bool( const BOOL *ptr, unsigned char *buf ) return sizeof(bool_false); } -static ULONG format_int8( const INT8 *ptr, unsigned char *buf ) +ULONG format_int8( const INT8 *ptr, unsigned char *buf ) { return wsprintfA( (char *)buf, "%d", *ptr ); } -static ULONG format_int16( const INT16 *ptr, unsigned char *buf ) +ULONG format_int16( const INT16 *ptr, unsigned char *buf ) { return wsprintfA( (char *)buf, "%d", *ptr ); } -static ULONG format_int32( const INT32 *ptr, unsigned char *buf ) +ULONG format_int32( const INT32 *ptr, unsigned char *buf ) { return wsprintfA( (char *)buf, "%d", *ptr ); } -static ULONG format_int64( const INT64 *ptr, unsigned char *buf ) +ULONG format_int64( const INT64 *ptr, unsigned char *buf ) { return wsprintfA( (char *)buf, "%I64d", *ptr ); } @@ -1624,12 +1624,12 @@ static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf ) return wsprintfA( (char *)buf, "%u", *ptr ); } -static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf ) +ULONG format_uint64( const UINT64 *ptr, unsigned char *buf ) { return wsprintfA( (char *)buf, "%I64u", *ptr ); } -static ULONG format_double( const double *ptr, unsigned char *buf ) +ULONG format_double( const double *ptr, unsigned char *buf ) { #ifdef HAVE_POWL static const long double precision = 0.0000000000000001; @@ -1726,7 +1726,7 @@ static inline int year_size( int year ) } #define TZ_OFFSET 8 -static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf ) +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; @@ -1782,7 +1782,7 @@ static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf ) return len; } -static ULONG format_guid( const GUID *ptr, unsigned char *buf ) +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, @@ -1790,7 +1790,7 @@ static ULONG format_guid( const GUID *ptr, unsigned char *buf ) ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] ); } -static ULONG format_urn( const GUID *ptr, unsigned char *buf ) +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,