webservices: Decode XML entities.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2016-07-04 11:35:40 +02:00 committed by Alexandre Julliard
parent f01a209e2b
commit f449b1324f
2 changed files with 248 additions and 3 deletions

View file

@ -1008,11 +1008,129 @@ static HRESULT parse_name( const unsigned char *str, unsigned int len,
return S_OK;
}
static int codepoint_to_utf8( int cp, unsigned char *dst )
{
if (cp < 0x80)
{
*dst = cp;
return 1;
}
if (cp < 0x800)
{
dst[1] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[0] = 0xc0 | cp;
return 2;
}
if ((cp >= 0xd800 && cp <= 0xdfff) || cp == 0xfffe || cp == 0xffff) return -1;
if (cp < 0x10000)
{
dst[2] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[1] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[0] = 0xe0 | cp;
return 3;
}
dst[3] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[2] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[1] = 0x80 | (cp & 0x3f);
cp >>= 6;
dst[0] = 0xf0 | cp;
return 4;
}
static HRESULT decode_text( const unsigned char *str, ULONG len, unsigned char *ret, ULONG *ret_len )
{
const unsigned char *p = str;
unsigned char *q = ret;
*ret_len = 0;
while (len)
{
if (*p == '&')
{
p++; len--;
if (!len) return WS_E_INVALID_FORMAT;
if (len >= 3 && !memcmp( p, "lt;", 3 ))
{
*q++ = '<';
p += 3;
len -= 3;
}
else if (len >= 3 && !memcmp( p, "gt;", 3 ))
{
*q++ = '>';
p += 3;
len -= 3;
}
else if (len >= 5 && !memcmp( p, "quot;", 5 ))
{
*q++ = '"';
p += 5;
len -= 5;
}
else if (len >= 4 && !memcmp( p, "amp;", 4 ))
{
*q++ = '&';
p += 4;
len -= 4;
}
else if (len >= 5 && !memcmp( p, "apos;", 5 ))
{
*q++ = '\'';
p += 5;
len -= 5;
}
else if (*p == '#')
{
ULONG start, nb_digits, i;
int len_utf8, cp = 0;
p++; len--;
if (!len || *p != 'x') return WS_E_INVALID_FORMAT;
p++; len--;
start = len;
while (len && isxdigit( *p )) { p++; len--; };
if (!len) return WS_E_INVALID_FORMAT;
p -= nb_digits = start - len;
if (!nb_digits || nb_digits > 5 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
for (i = 0; i < nb_digits; i++)
{
cp *= 16;
if (*p >= '0' && *p <= '9') cp += *p - '0';
else if (*p >= 'a' && *p <= 'f') cp += *p - 'a' + 10;
else cp += *p - 'A' + 10;
p++;
}
p++; len--;
if ((len_utf8 = codepoint_to_utf8( cp, q )) < 0) return WS_E_INVALID_FORMAT;
*ret_len += len_utf8;
q += len_utf8;
continue;
}
else return WS_E_INVALID_FORMAT;
}
else
{
*q++ = *p++;
len--;
}
*ret_len += 1;
}
return S_OK;
}
static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
{
static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
WS_XML_ATTRIBUTE *attr;
WS_XML_UTF8_TEXT *text;
WS_XML_UTF8_TEXT *text = NULL;
unsigned int len = 0, ch, skip, quote;
const unsigned char *start;
WS_XML_STRING *prefix, *localname;
@ -1083,7 +1201,11 @@ static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
if (!(text = alloc_utf8_text( NULL, 0 ))) goto error;
}
else if (!(text = alloc_utf8_text( start, len ))) goto error;
else
{
if (!(text = alloc_utf8_text( NULL, len ))) goto error;
if ((hr = decode_text( start, len, text->value.bytes, &text->value.length )) != S_OK) goto error;
}
attr->value = &text->text;
attr->singleQuote = (quote == '\'');
@ -1092,6 +1214,7 @@ static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
return S_OK;
error:
heap_free( text );
free_attribute( attr );
return hr;
}
@ -1207,6 +1330,7 @@ static HRESULT read_text( struct reader *reader )
struct node *node, *parent;
WS_XML_TEXT_NODE *text;
WS_XML_UTF8_TEXT *utf8;
HRESULT hr;
start = read_current_ptr( reader );
for (;;)
@ -1222,11 +1346,17 @@ static HRESULT read_text( struct reader *reader )
if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
text = (WS_XML_TEXT_NODE *)node;
if (!(utf8 = alloc_utf8_text( start, len )))
if (!(utf8 = alloc_utf8_text( NULL, len )))
{
heap_free( node );
return E_OUTOFMEMORY;
}
if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK)
{
heap_free( utf8 );
heap_free( node );
return hr;
}
text->text = &utf8->text;
read_insert_node( reader, parent, node );

View file

@ -3542,6 +3542,120 @@ static void test_WsSetReaderPosition(void)
WsFreeHeap( heap );
}
static void test_entities(void)
{
static const char str1[] = "<t>&#xA</t>";
static const char str2[] = "<t>&#xA;</t>";
static const char str3[] = "<t>&#xa;</t>";
static const char str4[] = "<t>&#xaaaa;</t>";
static const char str5[] = "<t>&#xaaaaa;</t>";
static const char str6[] = "<t>&1</t>";
static const char str7[] = "<t>&1;</t>";
static const char str8[] = "<t>&1111;</t>";
static const char str9[] = "<t>&11111;</t>";
static const char str10[] = "<t>&lt;</t>";
static const char str11[] = "<t>&gt;</t>";
static const char str12[] = "<t>&quot;</t>";
static const char str13[] = "<t>&amp;</t>";
static const char str14[] = "<t>&apos;</t>";
static const char str15[] = "<t>&sopa;</t>";
static const char str16[] = "<t>&#;</t>";
static const char str17[] = "<t>&;</t>";
static const char str18[] = "<t>&&</t>";
static const char str19[] = "<t>&</t>";
static const char str20[] = "<t>&#xaaaaaa;</t>";
static const char str21[] = "<t>&#xd7ff;</t>";
static const char str22[] = "<t>&#xd800;</t>";
static const char str23[] = "<t>&#xdfff;</t>";
static const char str24[] = "<t>&#xe000;</t>";
static const char str25[] = "<t>&#xfffe;</t>";
static const char str26[] = "<t>&#xffff;</t>";
static const char str27[] = "<t>&LT;</t>";
static const char res4[] = {0xea, 0xaa, 0xaa, 0x00};
static const char res5[] = {0xf2, 0xaa, 0xaa, 0xaa, 0x00};
static const char res21[] = {0xed, 0x9f, 0xbf, 0x00};
static const char res24[] = {0xee, 0x80, 0x80, 0x00};
static const struct
{
const char *str;
HRESULT hr;
const char *res;
}
tests[] =
{
{ str1, WS_E_INVALID_FORMAT },
{ str2, S_OK, "\n" },
{ str3, S_OK, "\n" },
{ str4, S_OK, res4 },
{ str5, S_OK, res5 },
{ str6, WS_E_INVALID_FORMAT },
{ str7, WS_E_INVALID_FORMAT },
{ str8, WS_E_INVALID_FORMAT },
{ str9, WS_E_INVALID_FORMAT },
{ str10, S_OK, "<" },
{ str11, S_OK, ">" },
{ str12, S_OK, "\"" },
{ str13, S_OK, "&" },
{ str14, S_OK, "'" },
{ str15, WS_E_INVALID_FORMAT },
{ str16, WS_E_INVALID_FORMAT },
{ str17, WS_E_INVALID_FORMAT },
{ str18, WS_E_INVALID_FORMAT },
{ str19, WS_E_INVALID_FORMAT },
{ str20, WS_E_INVALID_FORMAT },
{ str21, S_OK, res21 },
{ str22, WS_E_INVALID_FORMAT },
{ str23, WS_E_INVALID_FORMAT },
{ str24, S_OK, res24 },
{ str25, WS_E_INVALID_FORMAT },
{ str26, WS_E_INVALID_FORMAT },
{ str27, WS_E_INVALID_FORMAT },
};
HRESULT hr;
WS_XML_READER *reader;
const WS_XML_NODE *node;
const WS_XML_UTF8_TEXT *utf8;
ULONG i;
hr = WsCreateReader( NULL, 0, &reader, NULL ) ;
ok( hr == S_OK, "got %08x\n", hr );
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
{
hr = set_input( reader, tests[i].str, strlen(tests[i].str) );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
hr = WsReadNode( reader, NULL );
ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
if (hr != S_OK) continue;
hr = WsGetReaderNode( reader, &node, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
utf8 = (const WS_XML_UTF8_TEXT *)((const WS_XML_TEXT_NODE *)node)->text;
ok( utf8->value.length == strlen(tests[i].res), "%u: got %u\n", i, utf8->value.length );
ok( !memcmp( utf8->value.bytes, tests[i].res, strlen(tests[i].res) ), "%u: wrong data\n", i );
}
hr = set_input( reader, "<t a='&#xA;&#xA;'/>", sizeof("<t a='&#xA;&#xA;'/>") - 1 );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsGetReaderNode( reader, &node, NULL );
ok( hr == S_OK, "got %08x\n", hr );
utf8 = (const WS_XML_UTF8_TEXT *)((const WS_XML_ELEMENT_NODE *)node)->attributes[0]->value;
ok( utf8->value.length == 2, "got %u\n", utf8->value.length );
ok( !memcmp( utf8->value.bytes, "\n\n", 2 ), "wrong data\n" );
WsFreeReader( reader );
}
START_TEST(reader)
{
test_WsCreateError();
@ -3576,4 +3690,5 @@ START_TEST(reader)
test_WsResetError();
test_WsGetReaderPosition();
test_WsSetReaderPosition();
test_entities();
}