From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 76 +++++++++++-- dlls/windows.web/tests/web.c | 197 +++++++++++++++++++++++++++++++++- 2 files changed, 263 insertions(+), 10 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index ed539219ef4..648b8a5d764 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -128,6 +128,7 @@ struct json_value HSTRING string_value; double number_value; IJsonArray *array_value; + IJsonObject *object_value; }; }; @@ -178,6 +179,8 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface ) WindowsDeleteString( impl->string_value ); else if (impl->json_value_type == JsonValueType_Array) IJsonArray_Release( impl->array_value ); + else if (impl->json_value_type == JsonValueType_Object) + IJsonObject_Release( impl->object_value ); free( impl ); } @@ -276,12 +279,14 @@ static HRESULT WINAPI json_value_GetObject( IJsonValue *iface, IJsonObject **val { struct json_value *impl = impl_from_IJsonValue( iface ); - FIXME( "iface %p, value %p stub!\n", iface, value ); + TRACE( "iface %p, value %p\n", iface, value ); if (!value) return E_POINTER; if (impl->json_value_type != JsonValueType_Object) return E_ILLEGAL_METHOD_CALL; - return E_NOTIMPL; + IJsonObject_AddRef( impl->object_value ); + *value = impl->object_value; + return S_OK; } static const struct IJsonValueVtbl json_value_vtbl = @@ -453,13 +458,71 @@ static HRESULT parse_json_string( struct json_buffer *json, HSTRING *output ) return hr; } +static HRESULT parse_json_object( struct json_buffer *json, IJsonObject **value ) +{ + IJsonObject *object; + IJsonValue *child; + HSTRING name; + HRESULT hr; + + if (!json_buffer_take( json, L"{" )) return WEB_E_INVALID_JSON_STRING; + if (FAILED(hr = IActivationFactory_ActivateInstance( + json_object_factory, (IInspectable**)&object ))) return hr; + + json_buffer_trim( json ); + while (json->len && *json->str != '}') + { + if (FAILED(hr = parse_json_string( json, &name ))) + { + IJsonObject_Release( object ); + return hr; + } + + json_buffer_trim( json ); + if (!json_buffer_take( json, L":" )) + { + IJsonObject_Release( object ); + WindowsDeleteString( name ); + return WEB_E_INVALID_JSON_STRING; + } + + json_buffer_trim( json ); + if (FAILED(hr = parse_json_value( json, &child ))) + { + IJsonObject_Release( object ); + WindowsDeleteString( name ); + return hr; + } + + hr = IJsonObject_SetNamedValue( object, name, child ); + IJsonValue_Release( child ); + WindowsDeleteString( name ); + if (FAILED(hr)) + { + IJsonObject_Release( object ); + return hr; + } + + json_buffer_trim( json ); + if (!json_buffer_take( json, L"," )) break; + json_buffer_trim( json ); + } + + if (!json_buffer_take( json, L"}" )) + { + IJsonObject_Release( object ); + return WEB_E_INVALID_JSON_STRING; + } + + *value = object; + return S_OK; +} + static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) { struct json_value *impl; HRESULT hr = S_OK; - /* FIXME: Handle all JSON edge cases */ - if (!json->len) return WEB_E_INVALID_JSON_STRING; if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; @@ -491,9 +554,8 @@ static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) } else if (*json->str == '{') { - FIXME( "Object parsing not implemented!\n" ); + hr = parse_json_object( json, &impl->object_value ); impl->json_value_type = JsonValueType_Object; - hr = WEB_E_INVALID_JSON_STRING; } else { @@ -534,7 +596,7 @@ static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRIN { HRESULT hr; - FIXME( "iface %p, input %s, value %p semi-stub\n", iface, debugstr_hstring( input ), value ); + TRACE( "iface %p, input %s, value %p\n", iface, debugstr_hstring( input ), value ); if (!value) return E_POINTER; if (!input) return WEB_E_INVALID_JSON_STRING; diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 1b29447dfd2..8b91ddfe530 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -256,14 +256,37 @@ static void test_JsonArrayStatics(void) static void test_JsonObjectStatics(void) { + static const WCHAR *json_value_statics_name = L"Windows.Data.Json.JsonValue"; static const WCHAR *json_object_name = L"Windows.Data.Json.JsonObject"; + IJsonValueStatics *json_value_statics = (void *)0xdeadbeef; IActivationFactory *factory = (void *)0xdeadbeef; IInspectable *inspectable = (void *)0xdeadbeef; + IJsonObject *child_object = (void *)0xdeadbeef; IJsonObject *json_object = (void *)0xdeadbeef; + IJsonArray *child_array = (void *)0xdeadbeef; + IJsonValue *child_value = (void *)0xdeadbeef; + BOOLEAN child_boolean; + HSTRING child_string; + DOUBLE child_number; HSTRING str = NULL; HRESULT hr; LONG ref; + hr = WindowsCreateString( json_value_statics_name, wcslen( json_value_statics_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); + WindowsDeleteString( str ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "got hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( json_value_statics_name ) ); + return; + } + + hr = IActivationFactory_QueryInterface( factory, &IID_IJsonValueStatics, (void **)&json_value_statics ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ref = IActivationFactory_Release( factory ); + hr = WindowsCreateString( json_object_name, wcslen( json_object_name ), &str ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); @@ -292,9 +315,179 @@ static void test_JsonObjectStatics(void) ok( hr == S_OK, "got hr %#lx.\n", hr ); check_interface( inspectable, &IID_IAgileObject ); + IInspectable_Release( inspectable ); + + hr = WindowsCreateString( L"key", wcslen( L"key" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + /* key pair does not exist */ + + hr = IJsonObject_GetNamedValue( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedValue( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedValue( json_object, NULL, &child_value ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + hr = IJsonObject_GetNamedObject( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedObject( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedObject( json_object, NULL, &child_object ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + hr = IJsonObject_GetNamedArray( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, NULL, &child_array ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + hr = IJsonObject_GetNamedString( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, NULL, &child_string ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + hr = IJsonObject_GetNamedNumber( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, NULL, &child_number ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + hr = IJsonObject_GetNamedBoolean( json_object, NULL, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, NULL, &child_boolean ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr ); + + /* key pair exists */ + + WindowsDeleteString( str ); + hr = WindowsCreateString( L"{}", wcslen( L"{}" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + hr = WindowsCreateString( L"key", wcslen( L"key" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_SetNamedValue( json_object, str, child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonObject_Release( child_object ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + WindowsDeleteString( str ); + hr = WindowsCreateString( L"[]", wcslen( L"[]" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_Parse( json_value_statics, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + hr = WindowsCreateString( L"key", wcslen( L"key" ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_SetNamedValue( json_object, str, child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonArray_Release( child_array ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_SetNamedValue( json_object, str, child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( child_string ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 10, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_SetNamedValue( json_object, str, child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + + hr = IJsonValueStatics_CreateBooleanValue( json_value_statics, FALSE, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonObject_SetNamedValue( json_object, str, child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedValue( json_object, str, &child_value ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( child_value ); + hr = IJsonObject_GetNamedObject( json_object, str, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedArray( json_object, str, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedString( json_object, str, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedNumber( json_object, str, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); IJsonObject_Release( json_object ); - IInspectable_Release( inspectable ); + IJsonValueStatics_Release( json_value_statics ); ref = IActivationFactory_Release( factory ); ok( ref == 1, "got ref %ld.\n", ref ); } @@ -327,7 +520,6 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static return; } - todo_wine_if(expected_json_value_type == JsonValueType_Object) ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); if (FAILED(hr)) return; hr = IJsonValue_get_ValueType( json_value, &json_value_type ); @@ -403,7 +595,6 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static 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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263