Although UTF-16 text is converted to UTF-8 before transmission it's stored inline
rather than in the dictionary.
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/webservices/reader.c | 12 +
dlls/webservices/webservices_private.h | 1 +
dlls/webservices/writer.c | 1411 +++++++++++++++++---------------
3 files changed, 754 insertions(+), 670 deletions(-)
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 9d024a3446..a05b1edb33 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -788,6 +788,18 @@ WS_XML_UTF8_TEXT *alloc_utf8_text( const BYTE *data, ULONG len )
return ret;
}
+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;
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index f8cc6d9cfe..e477e0fc3f 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -68,6 +68,7 @@ HRESULT read_header( WS_XML_READER *, const WS_XML_STRING *, const WS_XML_STRING
HRESULT create_header_buffer( WS_XML_READER *, WS_HEAP *, WS_XML_BUFFER ** ) 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;
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 4b2466390c..be2994af83 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -667,6 +667,15 @@ static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL
if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
return RECORD_CHARS32_TEXT;
}
+ case WS_XML_TEXT_TYPE_UTF16:
+ {
+ const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
+ int len = text_utf16->byteCount / sizeof(WCHAR);
+ int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
+ if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT;
+ if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT;
+ return RECORD_CHARS32_TEXT;
+ }
case WS_XML_TEXT_TYPE_BASE64:
{
const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
@@ -784,153 +793,566 @@ static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULON
return FALSE;
}
-static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
+static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
{
- enum record_type type;
- BOOL use_dict = FALSE;
- HRESULT hr;
- ULONG id;
-
- if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
+ static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
+ if (*ptr)
{
- const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
- use_dict = get_string_id( writer, &utf8->value, &id );
+ memcpy( buf, bool_true, sizeof(bool_true) );
+ return sizeof(bool_true);
}
- type = get_attr_text_record_type( text, use_dict );
+ memcpy( buf, bool_false, sizeof(bool_false) );
+ return sizeof(bool_false);
+}
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- write_char( writer, type );
+static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
+{
+ return wsprintfA( (char *)buf, "%d", *ptr );
+}
- switch (type)
+static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
+{
+ return wsprintfA( (char *)buf, "%I64d", *ptr );
+}
+
+static 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 )
+{
+#ifdef HAVE_POWL
+ static const long double precision = 0.0000000000000001;
+ unsigned char *p = buf;
+ long double val = *ptr;
+ int neg, mag, mag2, use_exp;
+
+ if (isnan( val ))
{
- case RECORD_CHARS8_TEXT:
+ memcpy( buf, "NaN", 3 );
+ return 3;
+ }
+ if (isinf( val ))
{
- WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
- if (!text_utf8)
+ if (val < 0)
{
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- write_char( writer, 0 );
- return S_OK;
+ memcpy( buf, "-INF", 4 );
+ return 4;
}
- if ((hr = write_grow_buffer( writer, 1 + text_utf8->value.length )) != S_OK) return hr;
- write_char( writer, text_utf8->value.length );
- write_bytes( writer, text_utf8->value.bytes, text_utf8->value.length );
- return S_OK;
+ memcpy( buf, "INF", 3 );
+ return 3;
}
- case RECORD_CHARS16_TEXT:
+ if (val == 0.0)
{
- WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
- UINT16 len = text_utf8->value.length;
- if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&len, sizeof(len) );
- write_bytes( writer, text_utf8->value.bytes, len );
- return S_OK;
+ *p = '0';
+ return 1;
}
- case RECORD_BYTES8_TEXT:
+
+ if ((neg = val < 0))
{
- WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
- if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
- write_char( writer, text_base64->length );
- write_bytes( writer, text_base64->bytes, text_base64->length );
- return S_OK;
+ *p++ = '-';
+ val = -val;
}
- case RECORD_BYTES16_TEXT:
+
+ mag = log10l( val );
+ use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
+ if (use_exp)
{
- WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
- UINT16 len = text_base64->length;
- if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&len, sizeof(len) );
- write_bytes( writer, text_base64->bytes, len );
- return S_OK;
+ if (mag < 0) mag -= 1;
+ val = val / powl( 10.0, mag );
+ mag2 = mag;
+ mag = 0;
}
- case RECORD_ZERO_TEXT:
- case RECORD_ONE_TEXT:
- case RECORD_FALSE_TEXT:
- case RECORD_TRUE_TEXT:
- return S_OK;
+ else if (mag < 1) mag = 0;
- case RECORD_INT8_TEXT:
+ while (val > precision || mag >= 0)
{
- INT8 val = get_text_value_int( text );
- if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
- write_char( writer, val );
- return S_OK;
+ long double weight = powl( 10.0, mag );
+ if (weight > 0 && !isinf( weight ))
+ {
+ int digit = floorl( val / weight );
+ val -= digit * weight;
+ *(p++) = '0' + digit;
+ }
+ if (!mag && val > precision) *(p++) = '.';
+ mag--;
}
- case RECORD_INT16_TEXT:
+
+ if (use_exp)
{
- INT16 val = get_text_value_int( text );
- if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&val, sizeof(val) );
- return S_OK;
+ int i, j;
+ *(p++) = 'E';
+ if (mag2 > 0) *(p++) = '+';
+ else
+ {
+ *(p++) = '-';
+ mag2 = -mag2;
+ }
+ mag = 0;
+ while (mag2 > 0)
+ {
+ *(p++) = '0' + mag2 % 10;
+ mag2 /= 10;
+ mag++;
+ }
+ for (i = -mag, j = -1; i < j; i++, j--)
+ {
+ p[i] ^= p[j];
+ p[j] ^= p[i];
+ p[i] ^= p[j];
+ }
}
- case RECORD_INT32_TEXT:
+
+ return p - buf;
+#else
+ FIXME( "powl not found at build time\n" );
+ return 0;
+#endif
+}
+
+static inline int year_size( int year )
+{
+ return leap_year( year ) ? 366 : 365;
+}
+
+#define TZ_OFFSET 8
+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;
+ unsigned __int64 ticks, day_ticks;
+ ULONG len;
+
+ if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
+ ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
{
- INT32 val = get_text_value_int( text );
- if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&val, sizeof(val) );
- return S_OK;
+ ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
+ tz_hour = TZ_OFFSET;
}
- case RECORD_INT64_TEXT:
+ else
{
- INT64 val = get_text_value_int( text );
- if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&val, sizeof(val) );
- return S_OK;
+ ticks = ptr->ticks;
+ tz_hour = 0;
}
- case RECORD_UINT64_TEXT:
+ day = ticks / TICKS_PER_DAY;
+ day_ticks = ticks % TICKS_PER_DAY;
+ hour = day_ticks / TICKS_PER_HOUR;
+ min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
+ sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
+ sec_frac = day_ticks % TICKS_PER_SEC;
+
+ while (day >= year_size( year ))
{
- WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
- if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
- return S_OK;
+ day -= year_size( year );
+ year++;
}
- case RECORD_DOUBLE_TEXT:
+ while (day >= month_days[leap_year( year )][month])
{
- WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
- if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
- return S_OK;
+ day -= month_days[leap_year( year )][month];
+ month++;
}
- case RECORD_GUID_TEXT:
+
+ len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
+ if (sec_frac)
{
- WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
- if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
- return S_OK;
+ static const char fmt_frac[] = ".%07u";
+ len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
+ while (buf[len - 1] == '0') len--;
}
- case RECORD_UNIQUE_ID_TEXT:
+ if (ptr->format == WS_DATETIME_FORMAT_UTC)
{
- WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
- if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
- return S_OK;
+ buf[len++] = 'Z';
}
- case RECORD_DATETIME_TEXT:
+ else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
{
- WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
- UINT64 val = text_datetime->value.ticks;
+ static const char fmt_tz[] = "%c%02u:00";
+ len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
+ }
- assert( val <= TICKS_MAX );
- if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
- else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
+ return len;
+}
- if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)&val, sizeof(val) );
- return S_OK;
- }
- default:
- FIXME( "unhandled record type %02x\n", type );
- return E_NOTIMPL;
- }
+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,
+ ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
+ ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
}
-static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
+static ULONG format_urn( const GUID *ptr, unsigned char *buf )
{
- if (!attr->prefix || !attr->prefix->length)
- {
- if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
- return RECORD_SHORT_ATTRIBUTE;
- }
+ 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,
+ ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
+ ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
+}
+
+static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
+{
+ ULONG len = 0;
+ if (prefix && prefix->length)
+ {
+ memcpy( buf, prefix->bytes, prefix->length );
+ len += prefix->length;
+ buf[len++] = ':';
+ }
+ memcpy( buf + len, localname->bytes, localname->length );
+ return len + localname->length;
+}
+
+static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
+{
+ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ ULONG i = 0, x;
+
+ while (len > 0)
+ {
+ buf[i++] = base64[(bin[0] & 0xfc) >> 2];
+ x = (bin[0] & 3) << 4;
+ if (len == 1)
+ {
+ buf[i++] = base64[x];
+ buf[i++] = '=';
+ buf[i++] = '=';
+ break;
+ }
+ buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
+ x = (bin[1] & 0x0f) << 2;
+ if (len == 2)
+ {
+ buf[i++] = base64[x];
+ buf[i++] = '=';
+ break;
+ }
+ buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
+ buf[i++] = base64[bin[2] & 0x3f];
+ bin += 3;
+ len -= 3;
+ }
+ return i;
+}
+
+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)
+ {
+ case WS_XML_TEXT_TYPE_UTF8:
+ {
+ const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_UTF16:
+ {
+ const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
+ const WCHAR *str = (const WCHAR *)src->bytes;
+ ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
+
+ if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
+ len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_BASE64:
+ {
+ const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
+ ULONG len = ((4 * base64->length / 3) + 3) & ~3;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_BOOL:
+ {
+ const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_INT32:
+ {
+ const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
+ unsigned char buf[12]; /* "-2147483648" */
+ ULONG len = format_int32( &int32_text->value, buf );
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ memcpy( (*ret)->value.bytes + len_old, buf, len );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_INT64:
+ {
+ const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
+ unsigned char buf[21]; /* "-9223372036854775808" */
+ ULONG len = format_int64( &int64_text->value, buf );
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ memcpy( (*ret)->value.bytes + len_old, buf, len );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_UINT64:
+ {
+ const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
+ unsigned char buf[21]; /* "18446744073709551615" */
+ ULONG len = format_uint64( &uint64_text->value, buf );
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ memcpy( (*ret)->value.bytes + len_old, buf, len );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_DOUBLE:
+ {
+ const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
+ unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
+ unsigned short fpword;
+ ULONG len;
+
+ if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
+ len = format_double( &double_text->value, buf );
+ restore_fpword( fpword );
+ if (!len) return E_NOTIMPL;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ memcpy( (*ret)->value.bytes + len_old, buf, len );
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_GUID:
+ {
+ const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_UNIQUE_ID:
+ {
+ const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_DATETIME:
+ {
+ const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
+
+ if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ case WS_XML_TEXT_TYPE_QNAME:
+ {
+ const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
+ ULONG len = qn->localName->length;
+
+ if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
+ if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
+ (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
+ return S_OK;
+ }
+ default:
+ FIXME( "unhandled text type %u\n", text->textType );
+ return E_NOTIMPL;
+ }
+}
+
+static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
+{
+ enum record_type type;
+ BOOL use_dict = FALSE;
+ HRESULT hr;
+ ULONG id;
+
+ if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
+ {
+ const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
+ use_dict = get_string_id( writer, &utf8->value, &id );
+ }
+ type = get_attr_text_record_type( text, use_dict );
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ write_char( writer, type );
+
+ switch (type)
+ {
+ case RECORD_CHARS8_TEXT:
+ {
+ const WS_XML_UTF8_TEXT *text_utf8;
+ WS_XML_UTF8_TEXT *new = NULL;
+ UINT8 len;
+
+ if (!text)
+ {
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ write_char( writer, 0 );
+ return S_OK;
+ }
+ if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
+ else
+ {
+ if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
+ text_utf8 = new;
+ }
+ len = text_utf8->value.length;
+ if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
+ {
+ heap_free( new );
+ return hr;
+ }
+ write_char( writer, len );
+ write_bytes( writer, text_utf8->value.bytes, len );
+ heap_free( new );
+ return S_OK;
+ }
+ case RECORD_CHARS16_TEXT:
+ {
+ const WS_XML_UTF8_TEXT *text_utf8;
+ WS_XML_UTF8_TEXT *new = NULL;
+ UINT16 len;
+
+ if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
+ else
+ {
+ if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
+ text_utf8 = new;
+ }
+ len = text_utf8->value.length;
+ if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
+ {
+ heap_free( new );
+ return hr;
+ }
+ write_bytes( writer, (const BYTE *)&len, sizeof(len) );
+ write_bytes( writer, text_utf8->value.bytes, len );
+ heap_free( new );
+ return S_OK;
+ }
+ case RECORD_BYTES8_TEXT:
+ {
+ WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
+ if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
+ write_char( writer, text_base64->length );
+ write_bytes( writer, text_base64->bytes, text_base64->length );
+ return S_OK;
+ }
+ case RECORD_BYTES16_TEXT:
+ {
+ WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
+ UINT16 len = text_base64->length;
+ if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&len, sizeof(len) );
+ write_bytes( writer, text_base64->bytes, len );
+ return S_OK;
+ }
+ case RECORD_ZERO_TEXT:
+ case RECORD_ONE_TEXT:
+ case RECORD_FALSE_TEXT:
+ case RECORD_TRUE_TEXT:
+ return S_OK;
+
+ case RECORD_INT8_TEXT:
+ {
+ INT8 val = get_text_value_int( text );
+ if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
+ write_char( writer, val );
+ return S_OK;
+ }
+ case RECORD_INT16_TEXT:
+ {
+ INT16 val = get_text_value_int( text );
+ if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&val, sizeof(val) );
+ return S_OK;
+ }
+ case RECORD_INT32_TEXT:
+ {
+ INT32 val = get_text_value_int( text );
+ if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&val, sizeof(val) );
+ return S_OK;
+ }
+ case RECORD_INT64_TEXT:
+ {
+ INT64 val = get_text_value_int( text );
+ if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&val, sizeof(val) );
+ return S_OK;
+ }
+ case RECORD_UINT64_TEXT:
+ {
+ WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
+ if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
+ return S_OK;
+ }
+ case RECORD_DOUBLE_TEXT:
+ {
+ WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
+ if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
+ return S_OK;
+ }
+ case RECORD_GUID_TEXT:
+ {
+ WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
+ if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
+ return S_OK;
+ }
+ case RECORD_UNIQUE_ID_TEXT:
+ {
+ WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
+ if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
+ return S_OK;
+ }
+ case RECORD_DATETIME_TEXT:
+ {
+ WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
+ UINT64 val = text_datetime->value.ticks;
+
+ assert( val <= TICKS_MAX );
+ if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
+ else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
+
+ if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)&val, sizeof(val) );
+ return S_OK;
+ }
+ default:
+ FIXME( "unhandled record type %02x\n", type );
+ return E_NOTIMPL;
+ }
+}
+
+static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
+{
+ if (!attr->prefix || !attr->prefix->length)
+ {
+ 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 (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
@@ -1584,236 +2006,15 @@ static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *
/**************************************************************************
* WsWriteStartAttribute [webservices.@]
*/
-HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
- const WS_XML_STRING *localname, const WS_XML_STRING *ns,
- BOOL single, WS_ERROR *error )
-{
- struct writer *writer = (struct writer *)handle;
- HRESULT hr;
-
- TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
- debugstr_xmlstr(ns), single, error );
- if (error) FIXME( "ignoring error parameter\n" );
-
- if (!writer || !localname || !ns) return E_INVALIDARG;
-
- EnterCriticalSection( &writer->cs );
-
- if (writer->magic != WRITER_MAGIC)
- {
- LeaveCriticalSection( &writer->cs );
- return E_INVALIDARG;
- }
-
- if (writer->state != WRITER_STATE_STARTELEMENT)
- {
- LeaveCriticalSection( &writer->cs );
- return WS_E_INVALID_OPERATION;
- }
-
- if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
- writer->state = WRITER_STATE_STARTATTRIBUTE;
-
- LeaveCriticalSection( &writer->cs );
- return hr;
-}
-
-/* flush current start element if necessary */
-static HRESULT write_flush( struct writer *writer )
-{
- if (writer->state == WRITER_STATE_STARTELEMENT)
- {
- HRESULT hr;
- if ((hr = set_namespaces( writer )) != S_OK) return hr;
- if ((hr = write_startelement( writer )) != S_OK) return hr;
- if ((hr = write_endstartelement( writer )) != S_OK) return hr;
- writer->state = WRITER_STATE_ENDSTARTELEMENT;
- }
- return S_OK;
-}
-
-static HRESULT write_add_cdata_node( struct writer *writer )
-{
- struct node *node, *parent;
- if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
- if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
- write_insert_node( writer, parent, node );
- return S_OK;
-}
-
-static HRESULT write_add_endcdata_node( struct writer *writer )
-{
- struct node *node;
- if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
- node->parent = writer->current;
- list_add_tail( &node->parent->children, &node->entry );
- return S_OK;
-}
-
-static HRESULT write_cdata( struct writer *writer )
-{
- HRESULT hr;
- if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
- return S_OK;
-}
-
-static HRESULT write_cdata_node( struct writer *writer )
-{
- HRESULT hr;
- if ((hr = write_flush( writer )) != S_OK) return hr;
- if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
- if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
- if ((hr = write_cdata( writer )) != S_OK) return hr;
- writer->state = WRITER_STATE_STARTCDATA;
- return S_OK;
-}
-
-/**************************************************************************
- * WsWriteStartCData [webservices.@]
- */
-HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
-{
- struct writer *writer = (struct writer *)handle;
- HRESULT hr;
-
- TRACE( "%p %p\n", handle, error );
- if (error) FIXME( "ignoring error parameter\n" );
-
- if (!writer) return E_INVALIDARG;
-
- EnterCriticalSection( &writer->cs );
-
- if (writer->magic != WRITER_MAGIC)
- {
- LeaveCriticalSection( &writer->cs );
- return E_INVALIDARG;
- }
-
- hr = write_cdata_node( writer );
-
- LeaveCriticalSection( &writer->cs );
- return hr;
-}
-
-static HRESULT write_endcdata( struct writer *writer )
-{
- HRESULT hr;
- if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
- write_bytes( writer, (const BYTE *)"]]>", 3 );
- return S_OK;
-}
-
-static HRESULT write_endcdata_node( struct writer *writer )
-{
- HRESULT hr;
- if ((hr = write_endcdata( writer )) != S_OK) return hr;
- writer->current = writer->current->parent;
- writer->state = WRITER_STATE_ENDCDATA;
- return S_OK;
-}
-
-/**************************************************************************
- * WsWriteEndCData [webservices.@]
- */
-HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
-{
- struct writer *writer = (struct writer *)handle;
- HRESULT hr;
-
- TRACE( "%p %p\n", handle, error );
- if (error) FIXME( "ignoring error parameter\n" );
-
- if (!writer) return E_INVALIDARG;
-
- EnterCriticalSection( &writer->cs );
-
- if (writer->magic != WRITER_MAGIC)
- {
- LeaveCriticalSection( &writer->cs );
- return E_INVALIDARG;
- }
-
- if (writer->state != WRITER_STATE_TEXT)
- {
- LeaveCriticalSection( &writer->cs );
- return WS_E_INVALID_OPERATION;
- }
-
- hr = write_endcdata_node( writer );
-
- LeaveCriticalSection( &writer->cs );
- return hr;
-}
-
-static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
- const WS_XML_STRING *localname, const WS_XML_STRING *ns )
-{
- struct node *node, *parent;
- WS_XML_ELEMENT_NODE *elem;
-
- if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
-
- if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
- {
- elem = &parent->hdr;
- if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
- }
-
- if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
- elem = &node->hdr;
-
- if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
- {
- free_node( node );
- return E_OUTOFMEMORY;
- }
- if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
- {
- free_node( node );
- return E_OUTOFMEMORY;
- }
- if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
- {
- free_node( node );
- return E_OUTOFMEMORY;
- }
- write_insert_node( writer, parent, node );
- return S_OK;
-}
-
-static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
-{
- struct node *node;
- if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
- node->parent = parent;
- list_add_tail( &parent->children, &node->entry );
- return S_OK;
-}
-
-static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
- const WS_XML_STRING *localname, const WS_XML_STRING *ns )
-{
- HRESULT hr;
- if ((hr = write_flush( writer )) != S_OK) return hr;
- if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
- if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
- writer->state = WRITER_STATE_STARTELEMENT;
- return S_OK;
-}
-
-/**************************************************************************
- * WsWriteStartElement [webservices.@]
- */
-HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
- const WS_XML_STRING *localname, const WS_XML_STRING *ns,
- WS_ERROR *error )
+HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
+ const WS_XML_STRING *localname, const WS_XML_STRING *ns,
+ BOOL single, WS_ERROR *error )
{
struct writer *writer = (struct writer *)handle;
HRESULT hr;
- TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
- debugstr_xmlstr(ns), error );
+ TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
+ debugstr_xmlstr(ns), single, error );
if (error) FIXME( "ignoring error parameter\n" );
if (!writer || !localname || !ns) return E_INVALIDARG;
@@ -1826,394 +2027,231 @@ HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *
return E_INVALIDARG;
}
- hr = write_element_node( writer, prefix, localname, ns );
+ if (writer->state != WRITER_STATE_STARTELEMENT)
+ {
+ LeaveCriticalSection( &writer->cs );
+ return WS_E_INVALID_OPERATION;
+ }
+
+ if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
+ writer->state = WRITER_STATE_STARTATTRIBUTE;
LeaveCriticalSection( &writer->cs );
return hr;
}
-static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
+/* flush current start element if necessary */
+static HRESULT write_flush( struct writer *writer )
{
- static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
- if (*ptr)
+ if (writer->state == WRITER_STATE_STARTELEMENT)
{
- memcpy( buf, bool_true, sizeof(bool_true) );
- return sizeof(bool_true);
+ HRESULT hr;
+ if ((hr = set_namespaces( writer )) != S_OK) return hr;
+ if ((hr = write_startelement( writer )) != S_OK) return hr;
+ if ((hr = write_endstartelement( writer )) != S_OK) return hr;
+ writer->state = WRITER_STATE_ENDSTARTELEMENT;
}
- memcpy( buf, bool_false, sizeof(bool_false) );
- return sizeof(bool_false);
+ return S_OK;
}
-static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
+static HRESULT write_add_cdata_node( struct writer *writer )
{
- return wsprintfA( (char *)buf, "%d", *ptr );
+ struct node *node, *parent;
+ if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
+ if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
+ write_insert_node( writer, parent, node );
+ return S_OK;
}
-static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
+static HRESULT write_add_endcdata_node( struct writer *writer )
{
- return wsprintfA( (char *)buf, "%I64d", *ptr );
+ struct node *node;
+ if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
+ node->parent = writer->current;
+ list_add_tail( &node->parent->children, &node->entry );
+ return S_OK;
}
-static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
+static HRESULT write_cdata( struct writer *writer )
{
- return wsprintfA( (char *)buf, "%I64u", *ptr );
+ HRESULT hr;
+ if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
+ return S_OK;
}
-static ULONG format_double( const double *ptr, unsigned char *buf )
+static HRESULT write_cdata_node( struct writer *writer )
{
-#ifdef HAVE_POWL
- static const long double precision = 0.0000000000000001;
- unsigned char *p = buf;
- long double val = *ptr;
- int neg, mag, mag2, use_exp;
+ HRESULT hr;
+ if ((hr = write_flush( writer )) != S_OK) return hr;
+ if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
+ if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
+ if ((hr = write_cdata( writer )) != S_OK) return hr;
+ writer->state = WRITER_STATE_STARTCDATA;
+ return S_OK;
+}
- if (isnan( val ))
- {
- memcpy( buf, "NaN", 3 );
- return 3;
- }
- if (isinf( val ))
- {
- if (val < 0)
- {
- memcpy( buf, "-INF", 4 );
- return 4;
- }
- memcpy( buf, "INF", 3 );
- return 3;
- }
- if (val == 0.0)
- {
- *p = '0';
- return 1;
- }
+/**************************************************************************
+ * WsWriteStartCData [webservices.@]
+ */
+HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
+{
+ struct writer *writer = (struct writer *)handle;
+ HRESULT hr;
- if ((neg = val < 0))
- {
- *p++ = '-';
- val = -val;
- }
+ TRACE( "%p %p\n", handle, error );
+ if (error) FIXME( "ignoring error parameter\n" );
- mag = log10l( val );
- use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
- if (use_exp)
- {
- if (mag < 0) mag -= 1;
- val = val / powl( 10.0, mag );
- mag2 = mag;
- mag = 0;
- }
- else if (mag < 1) mag = 0;
+ if (!writer) return E_INVALIDARG;
- while (val > precision || mag >= 0)
- {
- long double weight = powl( 10.0, mag );
- if (weight > 0 && !isinf( weight ))
- {
- int digit = floorl( val / weight );
- val -= digit * weight;
- *(p++) = '0' + digit;
- }
- if (!mag && val > precision) *(p++) = '.';
- mag--;
- }
+ EnterCriticalSection( &writer->cs );
- if (use_exp)
+ if (writer->magic != WRITER_MAGIC)
{
- int i, j;
- *(p++) = 'E';
- if (mag2 > 0) *(p++) = '+';
- else
- {
- *(p++) = '-';
- mag2 = -mag2;
- }
- mag = 0;
- while (mag2 > 0)
- {
- *(p++) = '0' + mag2 % 10;
- mag2 /= 10;
- mag++;
- }
- for (i = -mag, j = -1; i < j; i++, j--)
- {
- p[i] ^= p[j];
- p[j] ^= p[i];
- p[i] ^= p[j];
- }
+ LeaveCriticalSection( &writer->cs );
+ return E_INVALIDARG;
}
- return p - buf;
-#else
- FIXME( "powl not found at build time\n" );
- return 0;
-#endif
-}
+ hr = write_cdata_node( writer );
-static inline int year_size( int year )
-{
- return leap_year( year ) ? 366 : 365;
+ LeaveCriticalSection( &writer->cs );
+ return hr;
}
-#define TZ_OFFSET 8
-static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
+static HRESULT write_endcdata( struct writer *writer )
{
- static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
- int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
- unsigned __int64 ticks, day_ticks;
- ULONG len;
-
- if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
- ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
- {
- ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
- tz_hour = TZ_OFFSET;
- }
- else
- {
- ticks = ptr->ticks;
- tz_hour = 0;
- }
- day = ticks / TICKS_PER_DAY;
- day_ticks = ticks % TICKS_PER_DAY;
- hour = day_ticks / TICKS_PER_HOUR;
- min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
- sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
- sec_frac = day_ticks % TICKS_PER_SEC;
-
- while (day >= year_size( year ))
- {
- day -= year_size( year );
- year++;
- }
- while (day >= month_days[leap_year( year )][month])
- {
- day -= month_days[leap_year( year )][month];
- month++;
- }
-
- len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
- if (sec_frac)
- {
- static const char fmt_frac[] = ".%07u";
- len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
- while (buf[len - 1] == '0') len--;
- }
- if (ptr->format == WS_DATETIME_FORMAT_UTC)
- {
- buf[len++] = 'Z';
- }
- else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
- {
- static const char fmt_tz[] = "%c%02u:00";
- len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
- }
-
- return len;
+ HRESULT hr;
+ if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
+ write_bytes( writer, (const BYTE *)"]]>", 3 );
+ return S_OK;
}
-static ULONG format_guid( const GUID *ptr, unsigned char *buf )
+static HRESULT write_endcdata_node( struct writer *writer )
{
- 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,
- ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
- ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
+ HRESULT hr;
+ if ((hr = write_endcdata( writer )) != S_OK) return hr;
+ writer->current = writer->current->parent;
+ writer->state = WRITER_STATE_ENDCDATA;
+ return S_OK;
}
-static ULONG format_urn( const GUID *ptr, unsigned char *buf )
+/**************************************************************************
+ * WsWriteEndCData [webservices.@]
+ */
+HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
{
- 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,
- ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
- ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
-}
+ struct writer *writer = (struct writer *)handle;
+ HRESULT hr;
+
+ TRACE( "%p %p\n", handle, error );
+ if (error) FIXME( "ignoring error parameter\n" );
+
+ if (!writer) return E_INVALIDARG;
+
+ EnterCriticalSection( &writer->cs );
-static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
-{
- ULONG len = 0;
- if (prefix && prefix->length)
+ if (writer->magic != WRITER_MAGIC)
{
- memcpy( buf, prefix->bytes, prefix->length );
- len += prefix->length;
- buf[len++] = ':';
+ LeaveCriticalSection( &writer->cs );
+ return E_INVALIDARG;
}
- memcpy( buf + len, localname->bytes, localname->length );
- return len + localname->length;
-}
-
-static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
-{
- static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- ULONG i = 0, x;
- while (len > 0)
+ if (writer->state != WRITER_STATE_TEXT)
{
- buf[i++] = base64[(bin[0] & 0xfc) >> 2];
- x = (bin[0] & 3) << 4;
- if (len == 1)
- {
- buf[i++] = base64[x];
- buf[i++] = '=';
- buf[i++] = '=';
- break;
- }
- buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
- x = (bin[1] & 0x0f) << 2;
- if (len == 2)
- {
- buf[i++] = base64[x];
- buf[i++] = '=';
- break;
- }
- buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
- buf[i++] = base64[bin[2] & 0x3f];
- bin += 3;
- len -= 3;
+ LeaveCriticalSection( &writer->cs );
+ return WS_E_INVALID_OPERATION;
}
- return i;
+
+ hr = write_endcdata_node( writer );
+
+ LeaveCriticalSection( &writer->cs );
+ return hr;
}
-static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
- WS_XML_UTF8_TEXT **ret )
+static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
+ const WS_XML_STRING *localname, const WS_XML_STRING *ns )
{
- ULONG len_old = old ? old->value.length : 0;
- if (offset) *offset = len_old;
+ struct node *node, *parent;
+ WS_XML_ELEMENT_NODE *elem;
- switch (text->textType)
- {
- case WS_XML_TEXT_TYPE_UTF8:
- {
- const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
+ if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
- if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_UTF16:
+ if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
{
- const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
- const WCHAR *str = (const WCHAR *)src->bytes;
- ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
-
- if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
- len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
- if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
- return S_OK;
+ elem = &parent->hdr;
+ if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
}
- case WS_XML_TEXT_TYPE_BASE64:
- {
- const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
- ULONG len = ((4 * base64->length / 3) + 3) & ~3;
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_BOOL:
- {
- const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
+ if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
+ elem = &node->hdr;
- if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_INT32:
+ if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
{
- const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
- unsigned char buf[12]; /* "-2147483648" */
- ULONG len = format_int32( &int32_text->value, buf );
-
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- memcpy( (*ret)->value.bytes + len_old, buf, len );
- return S_OK;
+ free_node( node );
+ return E_OUTOFMEMORY;
}
- case WS_XML_TEXT_TYPE_INT64:
+ if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
{
- const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
- unsigned char buf[21]; /* "-9223372036854775808" */
- ULONG len = format_int64( &int64_text->value, buf );
-
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- memcpy( (*ret)->value.bytes + len_old, buf, len );
- return S_OK;
+ free_node( node );
+ return E_OUTOFMEMORY;
}
- case WS_XML_TEXT_TYPE_UINT64:
+ if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
{
- const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
- unsigned char buf[21]; /* "18446744073709551615" */
- ULONG len = format_uint64( &uint64_text->value, buf );
-
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- memcpy( (*ret)->value.bytes + len_old, buf, len );
- return S_OK;
+ free_node( node );
+ return E_OUTOFMEMORY;
}
- case WS_XML_TEXT_TYPE_DOUBLE:
- {
- const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
- unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
- unsigned short fpword;
- ULONG len;
+ write_insert_node( writer, parent, node );
+ return S_OK;
+}
- if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
- len = format_double( &double_text->value, buf );
- restore_fpword( fpword );
- if (!len) return E_NOTIMPL;
+static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
+{
+ struct node *node;
+ if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
+ node->parent = parent;
+ list_add_tail( &parent->children, &node->entry );
+ return S_OK;
+}
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- memcpy( (*ret)->value.bytes + len_old, buf, len );
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_GUID:
- {
- const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
+static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
+ const WS_XML_STRING *localname, const WS_XML_STRING *ns )
+{
+ HRESULT hr;
+ if ((hr = write_flush( writer )) != S_OK) return hr;
+ if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
+ if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
+ writer->state = WRITER_STATE_STARTELEMENT;
+ return S_OK;
+}
- if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_UNIQUE_ID:
- {
- const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
+/**************************************************************************
+ * WsWriteStartElement [webservices.@]
+ */
+HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
+ const WS_XML_STRING *localname, const WS_XML_STRING *ns,
+ WS_ERROR *error )
+{
+ struct writer *writer = (struct writer *)handle;
+ HRESULT hr;
- if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_DATETIME:
- {
- const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
+ TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
+ debugstr_xmlstr(ns), error );
+ if (error) FIXME( "ignoring error parameter\n" );
- if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- case WS_XML_TEXT_TYPE_QNAME:
- {
- const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
- ULONG len = qn->localName->length;
+ if (!writer || !localname || !ns) return E_INVALIDARG;
- if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
- if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
- if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
- (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
- return S_OK;
- }
- default:
- FIXME( "unhandled text type %u\n", text->textType );
- return E_NOTIMPL;
+ EnterCriticalSection( &writer->cs );
+
+ if (writer->magic != WRITER_MAGIC)
+ {
+ LeaveCriticalSection( &writer->cs );
+ return E_INVALIDARG;
}
+
+ hr = write_element_node( writer, prefix, localname, ns );
+
+ LeaveCriticalSection( &writer->cs );
+ return hr;
}
static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
@@ -2238,16 +2276,14 @@ static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, UL
case WS_XML_TEXT_TYPE_UTF16:
{
const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
- const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
- WS_XML_UTF8_TEXT *new;
- const WCHAR *str = (const WCHAR *)utf16->bytes;
- ULONG len = utf16->byteCount / sizeof(WCHAR), len_utf8, len_old = utf8_old ? utf8_old->value.length : 0;
+ const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
+ WS_XML_UTF16_TEXT *new;
+ ULONG len = utf16->byteCount, len_old = utf16_old ? utf16_old->byteCount : 0;
if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
- len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
- if (!(new = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
- if (old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
- WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)new->value.bytes + len_old, len_utf8, NULL, NULL );
+ if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
+ if (utf16_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;
@@ -2477,6 +2513,15 @@ static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_
if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
}
+ case WS_XML_TEXT_TYPE_UTF16:
+ {
+ const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
+ int len = text_utf16->byteCount / sizeof(WCHAR);
+ int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
+ if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
+ if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
+ return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
+ }
case WS_XML_TEXT_TYPE_BASE64:
{
const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
@@ -2570,24 +2615,50 @@ static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, U
{
case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
{
- const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
- UINT8 len = text_utf8->value.length;
+ const WS_XML_UTF8_TEXT *text_utf8;
+ WS_XML_UTF8_TEXT *new = NULL;
+ UINT8 len;
- if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
+ if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
+ else
+ {
+ if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
+ text_utf8 = new;
+ }
+ len = text_utf8->value.length;
+ if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
+ {
+ heap_free( new );
+ return hr;
+ }
write_char( writer, type );
write_char( writer, len );
write_bytes( writer, text_utf8->value.bytes, len );
+ heap_free( new );
return S_OK;
}
case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
{
- const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
- UINT16 len = text_utf8->value.length;
+ const WS_XML_UTF8_TEXT *text_utf8;
+ WS_XML_UTF8_TEXT *new = NULL;
+ UINT16 len;
- if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
+ if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
+ else
+ {
+ if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
+ text_utf8 = new;
+ }
+ len = text_utf8->value.length;
+ if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
+ {
+ heap_free( new );
+ return hr;
+ }
write_char( writer, type );
write_bytes( writer, (const BYTE *)&len, sizeof(len) );
write_bytes( writer, text_utf8->value.bytes, len );
+ heap_free( new );
return S_OK;
}
case RECORD_BYTES8_TEXT:
--
2.11.0