Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56914
A full implementation should ideally use a JSON library.
-- v3: 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().
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 | 101 +++++++++++++++++++++++++++++++++- dlls/windows.web/private.h | 1 + 2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index dfd3820b915..e10dc8b9345 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,103 @@ 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, const WCHAR *token, HSTRING *trimmed_string ) +{ + HSTRING pattern = NULL, new_string = NULL; + HRESULT hr = WindowsCreateString( token, wcslen( token ), &pattern ); + + if (SUCCEEDED(hr)) hr = WindowsTrimStringStart( input, pattern, &new_string ); + if (SUCCEEDED(hr)) hr = WindowsTrimStringEnd( new_string, pattern, trimmed_string ); + + WindowsDeleteString( pattern ); + WindowsDeleteString( new_string ); + return hr; +} + +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 == 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] == '"') + { + if (FAILED(hr = trim_string( input, L"\"", &impl->parsed_string ))) return hr; + impl->json_value_type = JsonValueType_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 == ERANGE) return WEB_E_INVALID_JSON_NUMBER; + if (errno || 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, L" ", &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 e10dc8b9345..a1aaadbd990 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 a1aaadbd990..48d96131ec0 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 48d96131ec0..6098262649e 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 6098262649e..cba3c97a1f3 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 cba3c97a1f3..be5f5104e15 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 | 219 ++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index a4072a92db3..3fd5d7d750d 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,146 @@ 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 ); + WindowsDeleteString( parsed_str ); + + 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( 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 +237,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 +283,80 @@ 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"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" "Wine""; + 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"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"["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 );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=150884
Your paranoid android.
=== w8 (32 bit report) ===
windows.web: web.c:229: Test failed: got hr 0x8007000e.
=== w8adm (32 bit report) ===
windows.web: 0a98:web: unhandled exception c0000005 at 77B89925
=== w864 (32 bit report) ===
windows.web: web: Timeout
=== w1064v1809 (32 bit report) ===
windows.web: web.c:229: Test failed: got hr 0x8007000e. 1dd8:web: unhandled exception c0000005 at 77AB7962
=== w1064_tsign (32 bit report) ===
windows.web: 1cd8:web: unhandled exception c0000005 at 77334626
=== w10pro64 (32 bit report) ===
windows.web: web.c:229: Test failed: got hr 0x8007000e. web.c:229: Test failed: got hr 0x8007000e. web.c:352: Test failed: got hr 0x8007000e. web.c:358: Test failed: got hr 0x8007000e.
=== w10pro64_en_AE_u8 (32 bit report) ===
windows.web: 2360:web: unhandled exception c0000005 at 77B08491
=== w11pro64 (32 bit report) ===
windows.web: web.c:229: Test failed: got hr 0x8007000e. 0464:web: unhandled exception c0000005 at 77BB7061
=== debian11b (64 bit WoW report) ===
Report validation errors: d3d11:d3d11 has no test summary line (early exit of the main process?) d3d11:d3d11 has unaccounted for failure messages d3d11:d3d11 has unaccounted for todo messages d3d11:d3d11 has unaccounted for skip messages
On Tue Jan 14 07:30:14 2025 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/6966/diffs?diff_id=152362&start_sha=5a4772baa5a33257ca437517d6ca5ca006432362#ef914b49c99a38b99fc3d98e1532f81edcea0412_299_299)
Sure, sounds good.
On Tue Jan 14 07:30:14 2025 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/6966/diffs?diff_id=152362&start_sha=5a4772baa5a33257ca437517d6ca5ca006432362#ef914b49c99a38b99fc3d98e1532f81edcea0412_341_353)
Negated this to simplify the code.
On Tue Jan 14 07:30:14 2025 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/6966/diffs?diff_id=152362&start_sha=5a4772baa5a33257ca437517d6ca5ca006432362#ef914b49c99a38b99fc3d98e1532f81edcea0412_308_320)
Good catch, I added a few tests for it.
On Tue Jan 14 07:31:56 2025 +0000, Rémi Bernon wrote:
Regarding using a library, I would have considered adding cJSON to libs/ but we actually need to parse WCHAR strings, which it doesn't do. And JSON should hopefully be simple enough to implement our own parser.
Yeah, cJSON was what I was going to suggest, but I didn't know it doesn't parse WCHAR strings. Fortunately, the JSON I've seen so far has been simple so there's not really a need for a library now.
Rémi Bernon (@rbernon) commented about dlls/windows.web/json_value.c:
- UINT json_len;
- const WCHAR *json = WindowsGetStringRawBuffer( input, &json_len );
- HRESULT hr = S_OK;
- /* FIXME: Handle all JSON edge cases */
- 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] == '"')
You should probably check that json_len > 1.
Rémi Bernon (@rbernon) commented about dlls/windows.web/json_value.c:
- HRESULT hr = S_OK;
- /* FIXME: Handle all JSON edge cases */
- 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] == '"')
- {
if (FAILED(hr = trim_string( input, L"\\\"", &impl->parsed_string ))) return hr;
Do we really want to trim `"`? The string quotes aren't escaped as you just checked that the first char is '"', so I think this should be `L"""` instead?
**But**, do we really want to trim the string? What if it ends with `""`? We should keep a quote in the string in this case. As you checked for first and last char I think you can simply shrink the string by 1 char on each side instead of trimming.
Rémi Bernon (@rbernon) commented about dlls/windows.web/tests/web.c:
- 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" "Wine"";
- 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\"]\
- }";
I think you can split strings on multiple lines, which would save you the EOL escapes and would IMO be better:
```suggestion:-4+0 json = L"{" " "Wine": "The Wine Project"," " "Linux": ["Arch", "BTW"]" "}"; ```
Rémi Bernon (@rbernon) commented about dlls/windows.web/json_value.c:
result = wcstold( json, &end );
if (errno == ERANGE) return WEB_E_INVALID_JSON_NUMBER;
if (errno || 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, L" ", &trimmed_json );
What about newlines, tabs and other whitespaces which are probably allowed?