Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56914
A full implementation should ideally use a JSON library.
-- v4: windows.web/tests: Add IJsonValueStatics::Parse() tests. windows.web: Implement IJsonValue::GetBoolean(). windows.web: Implement IJsonValue::GetNumber(). windows.web: Implement IJsonValue::GetString(). windows.web: Add error handling in IJsonValue::GetObject(). windows.web: Add error handling in IJsonValue::GetArray(). windows.web: Partially implement IJsonValueStatics::Parse(). windows.web: Implement IJsonValue::get_ValueType(). windows.web/tests: Add IJsonValue::get_ValueType() tests. windows.web/tests: Remove superfluous cast.
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/tests/web.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 649a1b066ed..625cc91407e 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -119,14 +119,14 @@ static void test_JsonValueStatics(void) hr = IActivationFactory_QueryInterface( factory, &IID_IJsonValueStatics, (void **)&json_value_statics ); ok( hr == S_OK, "got hr %#lx.\n", hr );
- hr = IJsonValueStatics_CreateStringValue( json_value_statics, NULL, (IJsonValue **)&json_value ); + hr = IJsonValueStatics_CreateStringValue( json_value_statics, NULL, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); if (hr == S_OK) IJsonValue_Release( json_value ); hr = WindowsCreateString( L"Wine", wcslen( L"Wine" ), &str ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, NULL ); ok( hr == E_POINTER, "got hr %#lx.\n", hr ); - hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, (IJsonValue **)&json_value ); + hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); WindowsDeleteString( str );
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/tests/web.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 625cc91407e..28771931fec 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -96,6 +96,7 @@ static void test_JsonValueStatics(void) IJsonValueStatics *json_value_statics = (void *)0xdeadbeef; IActivationFactory *factory = (void *)0xdeadbeef; IJsonValue *json_value = (void *)0xdeadbeef; + JsonValueType json_value_type; HSTRING str; HRESULT hr; LONG ref; @@ -121,17 +122,31 @@ static void test_JsonValueStatics(void)
hr = IJsonValueStatics_CreateStringValue( json_value_statics, NULL, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); - if (hr == S_OK) IJsonValue_Release( json_value ); + hr = IJsonValue_get_ValueType( json_value, NULL ); + todo_wine + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_get_ValueType( json_value, &json_value_type ); + todo_wine + ok( json_value_type == JsonValueType_String, "got JsonValueType %d.\n", json_value_type ); + todo_wine + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ref = IJsonValue_Release( json_value ); + ok( ref == 0, "got ref %ld.\n", ref ); hr = WindowsCreateString( L"Wine", wcslen( L"Wine" ), &str ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, NULL ); ok( hr == E_POINTER, "got hr %#lx.\n", hr ); hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValue_get_ValueType( json_value, &json_value_type ); + todo_wine + ok( json_value_type == JsonValueType_String, "got JsonValueType %d.\n", json_value_type ); + todo_wine + ok( hr == S_OK, "got hr %#lx.\n", hr ); WindowsDeleteString( str ); - ref = IJsonValue_Release( json_value ); ok( ref == 0, "got ref %ld.\n", ref ); + ref = IJsonValueStatics_Release( json_value_statics ); ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory );
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 12 ++++++++++-- dlls/windows.web/tests/web.c | 5 ----- 2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 87b3365f199..dfd3820b915 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -120,6 +120,7 @@ struct json_value IJsonValue IJsonValue_iface; LONG ref;
+ JsonValueType json_value_type; HSTRING string_value; };
@@ -192,8 +193,14 @@ static HRESULT WINAPI json_value_GetTrustLevel( IJsonValue *iface, TrustLevel *t
static HRESULT WINAPI json_value_get_ValueType( IJsonValue *iface, JsonValueType *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct json_value *impl = impl_from_IJsonValue( iface ); + + TRACE( "iface %p, value %p\n", iface, value ); + + if (!value) return E_POINTER; + + *value = impl->json_value_type; + return S_OK; }
static HRESULT WINAPI json_value_Stringify( IJsonValue *iface, HSTRING *value ) @@ -289,6 +296,7 @@ static HRESULT WINAPI json_value_statics_CreateStringValue( IJsonValueStatics *i
impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; impl->ref = 1; + impl->json_value_type = JsonValueType_String; if (FAILED(hr = WindowsDuplicateString( input, &impl->string_value ))) { free( impl ); diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 28771931fec..a4072a92db3 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -123,12 +123,9 @@ static void test_JsonValueStatics(void) hr = IJsonValueStatics_CreateStringValue( json_value_statics, NULL, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = IJsonValue_get_ValueType( json_value, NULL ); - todo_wine ok( hr == E_POINTER, "got hr %#lx.\n", hr ); hr = IJsonValue_get_ValueType( json_value, &json_value_type ); - todo_wine ok( json_value_type == JsonValueType_String, "got JsonValueType %d.\n", json_value_type ); - todo_wine ok( hr == S_OK, "got hr %#lx.\n", hr ); ref = IJsonValue_Release( json_value ); ok( ref == 0, "got ref %ld.\n", ref ); @@ -139,9 +136,7 @@ static void test_JsonValueStatics(void) hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, &json_value ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = IJsonValue_get_ValueType( json_value, &json_value_type ); - todo_wine ok( json_value_type == JsonValueType_String, "got JsonValueType %d.\n", json_value_type ); - todo_wine ok( hr == S_OK, "got hr %#lx.\n", hr ); WindowsDeleteString( str ); ref = IJsonValue_Release( json_value );
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56914 --- dlls/windows.web/json_value.c | 107 +++++++++++++++++++++++++++++++++- dlls/windows.web/private.h | 1 + 2 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index dfd3820b915..cc21f65cb70 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -121,6 +121,9 @@ struct json_value LONG ref;
JsonValueType json_value_type; + HSTRING parsed_string; + double parsed_number; + boolean parsed_boolean; HSTRING string_value; };
@@ -167,6 +170,7 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface )
if (!ref) { + WindowsDeleteString( impl->parsed_string ); WindowsDeleteString( impl->string_value ); free( impl ); } @@ -260,10 +264,109 @@ static const struct IJsonValueVtbl json_value_vtbl =
DEFINE_IINSPECTABLE( json_value_statics, IJsonValueStatics, struct json_value_statics, IActivationFactory_iface )
+static HRESULT trim_string( HSTRING input, HSTRING *trimmed_string ) +{ + static const WCHAR valid_whitespace[] = L" \t\n\r"; + UINT json_len, start = 0, end; + const WCHAR *json = WindowsGetStringRawBuffer( input, &json_len ); + + end = json_len; + while (start < end && wcschr( valid_whitespace, json[start] )) start++; + while (end > start && wcschr( valid_whitespace, json[end - 1] )) end--; + + return WindowsCreateString( json + start, end - start, trimmed_string ); +} + +static HRESULT parse_json_value( HSTRING input, struct json_value *impl ) +{ + UINT json_len; + const WCHAR *json = WindowsGetStringRawBuffer( input, &json_len ); + HRESULT hr = S_OK; + + /* FIXME: Handle all JSON edge cases */ + + if (!json_len) return WEB_E_INVALID_JSON_STRING; + + if (json_len == 4 && !wcsncmp( L"null", json, 4 )) + { + impl->json_value_type = JsonValueType_Null; + } + else if ((json_len == 4 && !wcsncmp( L"true", json, 4 )) || (json_len == 5 && !wcsncmp( L"false", json, 5 ))) + { + impl->parsed_boolean = json_len == 4; + impl->json_value_type = JsonValueType_Boolean; + } + else if (json[0] == '"' && json[json_len - 1] == '"') + { + json++; + json_len -= 2; + + if (json_len <= 2) return WEB_E_INVALID_JSON_STRING; + + impl->json_value_type = JsonValueType_String; + return WindowsCreateString( json, json_len, &impl->parsed_string ); + } + else if (json[0] == '[' && json[json_len - 1] == ']') + { + FIXME( "Array parsing not implemented!\n" ); + impl->json_value_type = JsonValueType_Array; + } + else if (json[0] == '{' && json[json_len - 1] == '}') + { + FIXME( "Object parsing not implemented!\n" ); + impl->json_value_type = JsonValueType_Object; + } + else + { + double result = 0; + WCHAR *end; + + errno = 0; + result = wcstold( json, &end ); + + if (errno || errno == ERANGE || end != json + json_len) return WEB_E_INVALID_JSON_NUMBER; + + impl->parsed_number = result; + impl->json_value_type = JsonValueType_Number; + } + + return hr; +} + +static HRESULT parse_json( HSTRING json, struct json_value *impl ) +{ + HSTRING trimmed_json = NULL; + HRESULT hr = trim_string( json, &trimmed_json ); + + if (SUCCEEDED(hr) && WindowsIsStringEmpty( trimmed_json )) hr = WEB_E_INVALID_JSON_STRING; + if (SUCCEEDED(hr)) hr = parse_json_value( trimmed_json, impl ); + + WindowsDeleteString( trimmed_json ); + return hr; +} + static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRING input, IJsonValue **value ) { - FIXME( "iface %p, input %s, value %p stub!\n", iface, debugstr_hstring( input ), value ); - return E_NOTIMPL; + struct json_value *impl; + HRESULT hr; + + FIXME( "iface %p, input %s, value %p semi-stub\n", iface, debugstr_hstring( input ), value ); + + if (!value) return E_POINTER; + if (!input) return WEB_E_INVALID_JSON_STRING; + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + if (FAILED(hr = parse_json( input, impl ))) + { + free( impl ); + return hr; + } + impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; + impl->ref = 1; + + *value = &impl->IJsonValue_iface; + TRACE( "created IJsonValue %p.\n", *value ); + return S_OK; }
static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HSTRING input, IJsonValue **result, boolean *succeeded ) diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h index 393affd61e1..d5f0e76d641 100644 --- a/dlls/windows.web/private.h +++ b/dlls/windows.web/private.h @@ -21,6 +21,7 @@ #define __WINE_WINDOWS_WEB_PRIVATE_H
#include <stdarg.h> +#include <errno.h>
#define COBJMACROS #include "windef.h"
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index cc21f65cb70..e88ad6677af 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -233,7 +233,13 @@ static HRESULT WINAPI json_value_GetBoolean( IJsonValue *iface, boolean *value )
static HRESULT WINAPI json_value_GetArray( IJsonValue *iface, IJsonArray **value ) { + struct json_value *impl = impl_from_IJsonValue( iface ); + FIXME( "iface %p, value %p stub!\n", iface, value ); + + if (!value) return E_POINTER; + if (impl->json_value_type != JsonValueType_Array) return E_ILLEGAL_METHOD_CALL; + return E_NOTIMPL; }
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index e88ad6677af..9daa85058cf 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -245,7 +245,13 @@ static HRESULT WINAPI json_value_GetArray( IJsonValue *iface, IJsonArray **value
static HRESULT WINAPI json_value_GetObject( IJsonValue *iface, IJsonObject **value ) { + struct json_value *impl = impl_from_IJsonValue( iface ); + FIXME( "iface %p, value %p stub!\n", iface, value ); + + if (!value) return E_POINTER; + if (impl->json_value_type != JsonValueType_Object) return E_ILLEGAL_METHOD_CALL; + return E_NOTIMPL; }
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 9daa85058cf..627e831317f 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -215,8 +215,14 @@ static HRESULT WINAPI json_value_Stringify( IJsonValue *iface, HSTRING *value )
static HRESULT WINAPI json_value_GetString( IJsonValue *iface, HSTRING *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct json_value *impl = impl_from_IJsonValue( iface ); + + TRACE( "iface %p, value %p\n", iface, value ); + + if (impl->json_value_type != JsonValueType_String) return E_ILLEGAL_METHOD_CALL; + if (!value) return E_POINTER; + + return WindowsDuplicateString( impl->parsed_string, value ); }
static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value )
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 627e831317f..12d09edc511 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -227,8 +227,15 @@ static HRESULT WINAPI json_value_GetString( IJsonValue *iface, HSTRING *value )
static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct json_value *impl = impl_from_IJsonValue( iface ); + + TRACE( "iface %p, value %p\n", iface, value ); + + if (impl->json_value_type != JsonValueType_Number) return E_ILLEGAL_METHOD_CALL; + if (!value) return E_POINTER; + + *value = impl->parsed_number; + return S_OK; }
static HRESULT WINAPI json_value_GetBoolean( IJsonValue *iface, boolean *value )
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/json_value.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 12d09edc511..66f1212d6da 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -240,8 +240,15 @@ static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value )
static HRESULT WINAPI json_value_GetBoolean( IJsonValue *iface, boolean *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct json_value *impl = impl_from_IJsonValue( iface ); + + TRACE( "iface %p, value %p\n", iface, value ); + + if (impl->json_value_type != JsonValueType_Boolean) return E_ILLEGAL_METHOD_CALL; + if (!value) return E_POINTER; + + *value = impl->parsed_boolean; + return S_OK; }
static HRESULT WINAPI json_value_GetArray( IJsonValue *iface, IJsonArray **value )
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.web/tests/web.c | 253 ++++++++++++++++++++++++++++++++++- 1 file changed, 251 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index a4072a92db3..2a8d469ceb8 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -51,7 +51,7 @@ static void test_JsonObjectStatics(void) IActivationFactory *factory = (void *)0xdeadbeef; IInspectable *inspectable = (void *)0xdeadbeef; IJsonObject *json_object = (void *)0xdeadbeef; - HSTRING str; + HSTRING str = NULL; HRESULT hr; LONG ref;
@@ -90,6 +90,145 @@ static void test_JsonObjectStatics(void) ok( ref == 1, "got ref %ld.\n", ref ); }
+#define check_json( json_value_statics, json, expected_json_value_type, valid ) check_json_( __LINE__, json_value_statics, json, expected_json_value_type, valid ) +static void check_json_( unsigned int line, IJsonValueStatics *json_value_statics, const WCHAR *json, JsonValueType expected_json_value_type, boolean valid ) +{ + HSTRING str = NULL, parsed_str = NULL, empty_space = NULL; + IJsonObject *json_object = (void *)0xdeadbeef; + IJsonArray *json_array = (void *)0xdeadbeef; + IJsonValue *json_value = (void *)0xdeadbeef; + boolean parsed_boolean, expected_boolean; + JsonValueType json_value_type; + DOUBLE parsed_num; + HRESULT hr; + LONG ref; + int res; + + hr = WindowsCreateString( json, wcslen( json ), &str ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value ); + if (!valid) + { + if (expected_json_value_type == JsonValueType_Number) + ok_(__FILE__, line)( hr == WEB_E_INVALID_JSON_NUMBER, "got hr %#lx.\n", hr ); + else + todo_wine + ok_(__FILE__, line)( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr ); + + WindowsDeleteString( str ); + return; + } + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValue_get_ValueType( json_value, &json_value_type ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + ok_(__FILE__, line)( json_value_type == expected_json_value_type, "got json_value_type %d.\n", json_value_type ); + + switch (expected_json_value_type) + { + case JsonValueType_Null: + hr = IJsonValue_GetString( json_value, NULL ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetString( json_value, &parsed_str ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValue_GetNumber( json_value, NULL ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetNumber( json_value, &parsed_num ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValue_GetBoolean( json_value, NULL ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetBoolean( json_value, &parsed_boolean ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValue_GetArray( json_value, NULL ); + ok_(__FILE__, line)( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetArray( json_value, &json_array ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + if (hr == S_OK) IJsonArray_Release( json_array ); + + hr = IJsonValue_GetObject( json_value, NULL ); + ok_(__FILE__, line)( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetObject( json_value, &json_object ); + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + if (hr == S_OK) IJsonObject_Release( json_object ); + break; + case JsonValueType_Boolean: + hr = WindowsCreateString( L" ", wcslen( L" " ), &empty_space ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + hr = WindowsTrimStringStart( str, empty_space, &parsed_str ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + hr = WindowsTrimStringEnd( parsed_str, empty_space, &parsed_str ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + expected_boolean = !wcscmp( L"true", WindowsGetStringRawBuffer( parsed_str, NULL ) ); + + hr = IJsonValue_GetBoolean( json_value, NULL ); + ok_(__FILE__, line)( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetBoolean( json_value, &parsed_boolean ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + ok_(__FILE__, line)( parsed_boolean == expected_boolean, "boolean mismatch, got %d, expected %d.\n", parsed_boolean, expected_boolean ); + break; + case JsonValueType_Number: + parsed_num = 0xdeadbeef; + hr = IJsonValue_GetNumber( json_value, NULL ); + ok_(__FILE__, line)( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetNumber( json_value, &parsed_num ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + ok_(__FILE__, line)( parsed_num != 0xdeadbeef, "failed to get parsed_num\n" ); + break; + case JsonValueType_String: + hr = IJsonValue_GetString( json_value, NULL ); + ok_(__FILE__, line)( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetString( json_value, &parsed_str ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + hr = WindowsCompareStringOrdinal( str, parsed_str, &res ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + ok_(__FILE__, line)( res != 0, "got same HSTRINGS str = %s, parsed_str = %s.\n", wine_dbgstr_hstring( str ), wine_dbgstr_hstring( parsed_str ) ); + break; + case JsonValueType_Array: + hr = IJsonValue_GetArray( json_value, &json_array ); + todo_wine + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) IJsonArray_Release( json_array ); + break; + case JsonValueType_Object: + hr = IJsonValue_GetObject( json_value, &json_object ); + todo_wine + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + if (hr == S_OK) IJsonObject_Release( json_object ); + break; + } + + WindowsDeleteString( empty_space ); + WindowsDeleteString( parsed_str ); + WindowsDeleteString( str ); + ref = IJsonValue_Release( json_value ); + ok_(__FILE__, line)( ref == 0, "got ref %ld.\n", ref ); +} + +WCHAR *create_non_null_terminated( const WCHAR *str ) +{ + UINT len = wcslen( str ); + WCHAR *buffer = malloc( len * sizeof( WCHAR ) ); + if (buffer) + { + memcpy( buffer, str, len * sizeof( WCHAR ) ); + buffer[len] = L'\1'; + return buffer; + } + trace( "create_non_null_terminated failed to return a string\n" ); + return NULL; +} + +#define check_non_null_terminated_json( json_value_statics, json, expected_json_value_type ) \ + check_non_null_terminated_json_( __LINE__, json_value_statics, json, expected_json_value_type ) +static void check_non_null_terminated_json_( unsigned int line, IJsonValueStatics *json_value_statics, const WCHAR *json, JsonValueType expected_json_value_type ) +{ + WCHAR *str = create_non_null_terminated( json ); + check_json_( line, json_value_statics, str, expected_json_value_type, FALSE ); + free( str ); +} + static void test_JsonValueStatics(void) { static const WCHAR *json_value_statics_name = L"Windows.Data.Json.JsonValue"; @@ -97,7 +236,8 @@ static void test_JsonValueStatics(void) IActivationFactory *factory = (void *)0xdeadbeef; IJsonValue *json_value = (void *)0xdeadbeef; JsonValueType json_value_type; - HSTRING str; + HSTRING str = NULL; + const WCHAR *json; HRESULT hr; LONG ref;
@@ -142,6 +282,115 @@ static void test_JsonValueStatics(void) ref = IJsonValue_Release( json_value ); ok( ref == 0, "got ref %ld.\n", ref );
+ hr = IJsonValueStatics_Parse( json_value_statics, NULL, &json_value ); + ok( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr ); + hr = WindowsCreateString( L"Wine", wcslen( L"Wine" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value ); + todo_wine + ok( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + + /* Valid JSON */ + + json = L""Wine\"""; + hr = WindowsCreateString( json, wcslen( json ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + if (SUCCEEDED(hr)) + { + HSTRING parsed_str = NULL; + int res; + + json = L"Wine""; + hr = WindowsCreateString( json, wcslen( json ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValue_GetString( json_value, &parsed_str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = WindowsCompareStringOrdinal( str, parsed_str, &res ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + todo_wine + ok( res == 0, "got different HSTRINGS str = %s, parsed_str = %s.\n", wine_dbgstr_hstring( str ), wine_dbgstr_hstring( parsed_str ) ); + + WindowsDeleteString( parsed_str ); + WindowsDeleteString( str ); + } + + json = L"null"; + check_json( json_value_statics, json, JsonValueType_Null, TRUE ); + json = L"false"; + check_json( json_value_statics, json, JsonValueType_Boolean, TRUE ); + json = L" true "; + check_json( json_value_statics, json, JsonValueType_Boolean, TRUE ); + json = L""true""; + check_json( json_value_statics, json, JsonValueType_String, TRUE ); + json = L" 9.22 "; + check_json( json_value_statics, json, JsonValueType_Number, TRUE ); + json = L" "The Wine Project""; + check_json( json_value_statics, json, JsonValueType_String, TRUE ); + json = L"\r\t\n "The Wine Project""; + check_json( json_value_statics, json, JsonValueType_String, TRUE ); + json = L"["Wine", "Linux"]"; + check_json( json_value_statics, json, JsonValueType_Array, TRUE ); + json = L"{" + " "Wine": "The Wine Project"," + " "Linux": ["Arch", "BTW"]" + "}"; + check_json( json_value_statics, json, JsonValueType_Object, TRUE ); + + /* Invalid JSON */ + + json = L"null"; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_Null ); + json = L"false"; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_Boolean ); + json = L" true "; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_Boolean ); + json = L""true""; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_String ); + json = L" 9.22 "; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_String ); + json = L" "Wine""; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_String ); + json = L"["Wine", "Linux"]"; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_Array ); + json = L"{" + " "Wine": "The Wine Project"," + " "Linux": ["Arch", "BTW"]" + "}"; + check_non_null_terminated_json( json_value_statics, json, JsonValueType_Object ); + + json = L"" """; + hr = WindowsCreateString( json, wcslen( json ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value ); + ok( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + + json = L"True"; + check_json( json_value_statics, json, JsonValueType_Boolean, FALSE ); + json = L"1.7976931348623158e+3080"; + check_json( json_value_statics, json, JsonValueType_Number, FALSE ); + json = L"2.2250738585072014e-3080"; + check_json( json_value_statics, json, JsonValueType_Number, FALSE ); + json = L" "Wine":"; + check_json( json_value_statics, json, JsonValueType_String, FALSE ); + json = L" "The Wine \t Project""; + check_json( json_value_statics, json, JsonValueType_String, FALSE ); + json = L"\v "The Wine Project""; + check_json( json_value_statics, json, JsonValueType_String, FALSE ); + json = L"["Wine" "Linux"]"; + check_json( json_value_statics, json, JsonValueType_Array, FALSE ); + json = L"{" + " "Wine": "The Wine Project"," + " "Linux": ["Arch", "BTW"]" + ""; + check_json( json_value_statics, json, JsonValueType_Object, FALSE ); + ref = IJsonValueStatics_Release( json_value_statics ); ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory );
On Tue Feb 11 10:42:25 2025 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/6966/diffs?diff_id=156885&start_sha=f7a69698625fc1d2c1d40fc924c0977265fc516f#ef914b49c99a38b99fc3d98e1532f81edcea0412_365_371)
Added a test for those. Looks like only \r \t \n are valid.
On Tue Feb 11 10:42:24 2025 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/6966/diffs?diff_id=156885&start_sha=f7a69698625fc1d2c1d40fc924c0977265fc516f#f1b567cc3d46c132e5276ed6aaeacd39e0a15f77_317_339)
This is indeed better, thanks.
What if it ends with `""`? We should keep a quote in the string in this case.
Passing `json = L""Wine\"""` returns `json = L"Wine""` in Windows. This seems like an edge case. I've added a todo_wine test for it, unless there's a simple way to remove the escape characters?
On Tue Feb 11 10:43:01 2025 +0000, Rémi Bernon wrote:
You should probably check that json_len > 1.
Added a check.