[PATCH v14 0/11] MR10263: windows.web: Support JSON array and object parsing
Implements JsonArray, JsonObject value getters and extends JsonValue.Parse to support arrays and objects. -- v14: windows.web: Support boolean & number value creation windows.web: Support object parsing windows.web: JsonObject typed getters windows.web: Add object mapping windows.web: Support array parsing windows.web: JsonArray element getters windows.web: Stub IJsonArray windows.web: Additional string parsing tests windows.web: Support escaped characters windows.web: Use json_buffer struct & helper functions windows.web: Cleanup struct json_value https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 63 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index f1930beaad3..7470d60ff81 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -121,10 +121,12 @@ struct json_value LONG ref; JsonValueType json_value_type; - HSTRING parsed_string; - double parsed_number; - boolean parsed_boolean; - HSTRING string_value; + union + { + boolean boolean_value; + HSTRING string_value; + double number_value; + }; }; static inline struct json_value *impl_from_IJsonValue( IJsonValue *iface ) @@ -170,8 +172,9 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface ) if (!ref) { - WindowsDeleteString( impl->parsed_string ); - WindowsDeleteString( impl->string_value ); + if (impl->json_value_type == JsonValueType_String) + WindowsDeleteString( impl->string_value ); + free( impl ); } return ref; @@ -222,7 +225,7 @@ static HRESULT WINAPI json_value_GetString( IJsonValue *iface, HSTRING *value ) if (impl->json_value_type != JsonValueType_String) return E_ILLEGAL_METHOD_CALL; if (!value) return E_POINTER; - return WindowsDuplicateString( impl->parsed_string, value ); + return WindowsDuplicateString( impl->string_value, value ); } static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value ) @@ -234,7 +237,7 @@ static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value ) if (impl->json_value_type != JsonValueType_Number) return E_ILLEGAL_METHOD_CALL; if (!value) return E_POINTER; - *value = impl->parsed_number; + *value = impl->number_value; return S_OK; } @@ -247,7 +250,7 @@ static HRESULT WINAPI json_value_GetBoolean( IJsonValue *iface, boolean *value ) if (impl->json_value_type != JsonValueType_Boolean) return E_ILLEGAL_METHOD_CALL; if (!value) return E_POINTER; - *value = impl->parsed_boolean; + *value = impl->boolean_value; return S_OK; } @@ -324,15 +327,19 @@ static HRESULT trim_string( HSTRING input, HSTRING *output ) return WindowsCreateString( json + start, end - start, output ); } -static HRESULT parse_json_value( HSTRING input, struct json_value *impl ) +static HRESULT parse_json_value( HSTRING input, IJsonValue **value ) { UINT32 len; const WCHAR *json = WindowsGetStringRawBuffer( input, &len ); + struct json_value *impl; HRESULT hr = S_OK; /* FIXME: Handle all JSON edge cases */ if (!len) return WEB_E_INVALID_JSON_STRING; + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; + impl->ref = 1; if (len == 4 && !wcsncmp( L"null", json, 4 )) { @@ -340,7 +347,7 @@ static HRESULT parse_json_value( HSTRING input, struct json_value *impl ) } else if ((len == 4 && !wcsncmp( L"true", json, 4 )) || (len == 5 && !wcsncmp( L"false", json, 5 ))) { - impl->parsed_boolean = len == 4; + impl->boolean_value = len == 4; impl->json_value_type = JsonValueType_Boolean; } else if (json[0] == '\"' && json[len - 1] == '\"') @@ -348,9 +355,8 @@ static HRESULT parse_json_value( HSTRING input, struct json_value *impl ) json++; len -= 2; - if (len <= 2) return WEB_E_INVALID_JSON_STRING; - if (FAILED(hr = unescape_string( json, &impl->parsed_string ))) return hr; - + if (len <= 2) hr = WEB_E_INVALID_JSON_STRING; + else hr = unescape_string( json, &impl->string_value ); impl->json_value_type = JsonValueType_String; } else if (json[0] == '[' && json[len - 1] == ']') @@ -371,22 +377,24 @@ static HRESULT parse_json_value( HSTRING input, struct json_value *impl ) errno = 0; result = wcstold( json, &end ); - if (errno || errno == ERANGE || end != json + len) return WEB_E_INVALID_JSON_NUMBER; + if (errno || errno == ERANGE || end != json + len) hr = WEB_E_INVALID_JSON_NUMBER; - impl->parsed_number = result; + impl->number_value = result; impl->json_value_type = JsonValueType_Number; } + if (FAILED(hr)) free( impl ); + else *value = &impl->IJsonValue_iface; return hr; } -static HRESULT parse_json( HSTRING json, struct json_value *impl ) +static HRESULT parse_json( HSTRING json, IJsonValue **value ) { 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 ); + if (SUCCEEDED(hr)) hr = parse_json_value( trimmed_json, value ); WindowsDeleteString( trimmed_json ); return hr; @@ -394,26 +402,17 @@ static HRESULT parse_json( HSTRING json, struct json_value *impl ) static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRING input, IJsonValue **value ) { - 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; + if (SUCCEEDED(hr = parse_json( input, value ))) + TRACE( "created IJsonValue %p.\n", *value ); - *value = &impl->IJsonValue_iface; - TRACE( "created IJsonValue %p.\n", *value ); - return S_OK; + return hr; } static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HSTRING input, IJsonValue **result, boolean *succeeded ) @@ -449,8 +448,8 @@ static HRESULT WINAPI json_value_statics_CreateStringValue( IJsonValueStatics *i impl->json_value_type = JsonValueType_String; if (FAILED(hr = WindowsDuplicateString( input, &impl->string_value ))) { - free( impl ); - return hr; + free( impl ); + return hr; } *value = &impl->IJsonValue_iface; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 88 +++++++++++++++++++++++------------ dlls/windows.web/tests/web.c | 5 +- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 7470d60ff81..fcca2334aac 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -1,6 +1,7 @@ /* WinRT Windows.Data.Json.JsonValue Implementation * * Copyright (C) 2024 Mohamad Al-Jaf + * Copyright (C) 2026 Olivia Ryan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -314,60 +315,81 @@ static HRESULT unescape_string( const WCHAR *src, HSTRING *output ) return WindowsPromoteStringBuffer( buf, output ); } -static HRESULT trim_string( HSTRING input, HSTRING *output ) +struct json_buffer +{ + const WCHAR *str; + UINT32 len; +}; + +static void json_buffer_trim( struct json_buffer *json ) { static const WCHAR valid_whitespace[] = L" \t\n\r"; - UINT32 len, start = 0, end; - const WCHAR *json = WindowsGetStringRawBuffer( input, &len ); + UINT32 start = 0, end = json->len; - end = len; - while (start < end && wcschr( valid_whitespace, json[start] )) start++; - while (end > start && wcschr( valid_whitespace, json[end - 1] )) end--; + while (start < end && wcschr( valid_whitespace, json->str[start] )) start++; + while (end > start && wcschr( valid_whitespace, json->str[end - 1] )) end--; - return WindowsCreateString( json + start, end - start, output ); + json->str += start; + json->len = end - start; } -static HRESULT parse_json_value( HSTRING input, IJsonValue **value ) +static BOOL json_buffer_take( struct json_buffer *json, const WCHAR *str ) +{ + UINT32 len = wcslen( str ); + + if (json->len < len || wcsncmp( json->str, str, len )) return FALSE; + json->str += len; + json->len -= len; + + return TRUE; +} + +static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) { - UINT32 len; - const WCHAR *json = WindowsGetStringRawBuffer( input, &len ); struct json_value *impl; HRESULT hr = S_OK; /* FIXME: Handle all JSON edge cases */ - if (!len) return WEB_E_INVALID_JSON_STRING; + 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; impl->ref = 1; - if (len == 4 && !wcsncmp( L"null", json, 4 )) + if (json_buffer_take( json, L"null" )) { impl->json_value_type = JsonValueType_Null; } - else if ((len == 4 && !wcsncmp( L"true", json, 4 )) || (len == 5 && !wcsncmp( L"false", json, 5 ))) + else if (json_buffer_take( json, L"true" )) { - impl->boolean_value = len == 4; + impl->boolean_value = TRUE; impl->json_value_type = JsonValueType_Boolean; } - else if (json[0] == '\"' && json[len - 1] == '\"') + else if (json_buffer_take( json, L"false" )) { - json++; - len -= 2; + impl->boolean_value = FALSE; + impl->json_value_type = JsonValueType_Boolean; + } + else if (*json->str == '"' && json->str[json->len - 1] == '"') + { + json->str++; + json->len -= 2; - if (len <= 2) hr = WEB_E_INVALID_JSON_STRING; - else hr = unescape_string( json, &impl->string_value ); + if (json->len <= 2) hr = WEB_E_INVALID_JSON_STRING; + else hr = unescape_string( json->str, &impl->string_value ); impl->json_value_type = JsonValueType_String; } - else if (json[0] == '[' && json[len - 1] == ']') + else if (*json->str == '[') { FIXME( "Array parsing not implemented!\n" ); impl->json_value_type = JsonValueType_Array; + hr = WEB_E_INVALID_JSON_STRING; } - else if (json[0] == '{' && json[len - 1] == '}') + else if (*json->str == '{') { FIXME( "Object parsing not implemented!\n" ); impl->json_value_type = JsonValueType_Object; + hr = WEB_E_INVALID_JSON_STRING; } else { @@ -375,9 +397,12 @@ static HRESULT parse_json_value( HSTRING input, IJsonValue **value ) WCHAR *end; errno = 0; - result = wcstold( json, &end ); + result = wcstold( json->str, &end ); + + json->len -= end - json->str; + json->str = end; - if (errno || errno == ERANGE || end != json + len) hr = WEB_E_INVALID_JSON_NUMBER; + if (errno || errno == ERANGE) hr = WEB_E_INVALID_JSON_NUMBER; impl->number_value = result; impl->json_value_type = JsonValueType_Number; @@ -388,16 +413,17 @@ static HRESULT parse_json_value( HSTRING input, IJsonValue **value ) return hr; } -static HRESULT parse_json( HSTRING json, IJsonValue **value ) +static HRESULT parse_json( HSTRING string, IJsonValue **value ) { - 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, value ); + HRESULT hr; + struct json_buffer json; + json.str = WindowsGetStringRawBuffer( string, &json.len ); - WindowsDeleteString( trimmed_json ); - return hr; + json_buffer_trim( &json ); + if (!json.len) return WEB_E_INVALID_JSON_STRING; + if (FAILED(hr = parse_json_value( &json, value ))) return hr; + if (json.len) return WEB_E_INVALID_JSON_STRING; + return S_OK; } static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRING input, IJsonValue **value ) diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index b0f38edfb3b..9af1b872846 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -112,13 +112,15 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static 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; } + + todo_wine_if(expected_json_value_type == JsonValueType_Array || 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 ); 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 ); @@ -289,7 +291,6 @@ static void test_JsonValueStatics(void) 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 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 98 +++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index fcca2334aac..f34ce5b73d9 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -300,21 +300,6 @@ static const struct IJsonValueVtbl json_value_vtbl = DEFINE_IINSPECTABLE( json_value_statics, IJsonValueStatics, struct json_value_statics, IActivationFactory_iface ) -static HRESULT unescape_string( const WCHAR *src, HSTRING *output ) -{ - UINT32 len = wcslen( src ) - 1, n; - const WCHAR *end = src + len; - HSTRING_BUFFER buf; - HRESULT hr; - WCHAR *dst; - - for (len = n = 0; len + n < end - src; len++) { if (src[len + n] == '\\') n++; } - if (FAILED(hr = WindowsPreallocateStringBuffer( len, &dst, &buf ))) return hr; - while (src != end) { if (*src == '\\' && ++src == end) break; *dst++ = *src++; } - - return WindowsPromoteStringBuffer( buf, output ); -} - struct json_buffer { const WCHAR *str; @@ -344,6 +329,81 @@ static BOOL json_buffer_take( struct json_buffer *json, const WCHAR *str ) return TRUE; } +static WCHAR json_buffer_next( struct json_buffer *json, const WCHAR *valid ) +{ + const WCHAR chr = *json->str; + + if (!json->len) return 0; + if (valid && !wcschr( valid, chr )) return 0; + json->str++; + json->len--; + + return chr; +} + +static HRESULT parse_json_string( struct json_buffer *json, HSTRING *output ) +{ + const WCHAR valid_hex_chars[] = L"abcdefABCDEF0123456789"; + WCHAR chr, *buf, *dst; + HRESULT hr; + + /* validate and escape string, assuming string occupies remainder of buffer */ + + if (!json_buffer_take( json, L"\"" )) return WEB_E_INVALID_JSON_STRING; + if (!json->len) return WEB_E_INVALID_JSON_STRING; + if (!(buf = calloc( json->len, sizeof( WCHAR )))) return E_OUTOFMEMORY; + dst = buf; + + while (json->len) + { + if (*json->str == '"') break; + if (json_buffer_take( json, L"\\\"" )) *(dst++) = '"'; + else if (json_buffer_take( json, L"\\\\" )) *(dst++) = '\\'; + else if (json_buffer_take( json, L"\\/" )) *(dst++) = '/'; + else if (json_buffer_take( json, L"\\b" )) *(dst++) = '\b'; + else if (json_buffer_take( json, L"\\f" )) *(dst++) = '\f'; + else if (json_buffer_take( json, L"\\n" )) *(dst++) = '\n'; + else if (json_buffer_take( json, L"\\r" )) *(dst++) = '\r'; + else if (json_buffer_take( json, L"\\t" )) *(dst++) = '\t'; + else if (json_buffer_take( json, L"\\u" )) + { + for (int i = 0; i < 4; i++) + { + if (!(chr = json_buffer_next( json, valid_hex_chars ))) + { + free( buf ); + return WEB_E_INVALID_JSON_STRING; + } + + *dst <<= 4; + if (chr >= 'A') *dst |= (chr & 0x7) + 9; + else *dst |= chr & 0xf; + } + dst++; + } + else if (*json->str >= ' ') + { + *(dst++) = *(json->str++); + json->len--; + } + else + { + free( buf ); + return WEB_E_INVALID_JSON_STRING; + } + } + + if (!json_buffer_take( json, L"\"" )) + { + free( buf ); + return WEB_E_INVALID_JSON_STRING; + } + + hr = WindowsCreateString( buf, dst - buf, output ); + free( buf ); + return hr; +} + static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) { struct json_value *impl; @@ -370,13 +430,9 @@ static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) impl->boolean_value = FALSE; impl->json_value_type = JsonValueType_Boolean; } - else if (*json->str == '"' && json->str[json->len - 1] == '"') + else if (*json->str == '"') { - json->str++; - json->len -= 2; - - if (json->len <= 2) hr = WEB_E_INVALID_JSON_STRING; - else hr = unescape_string( json->str, &impl->string_value ); + hr = parse_json_string( json, &impl->string_value ); impl->json_value_type = JsonValueType_String; } else if (*json->str == '[') -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/tests/web.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 9af1b872846..b0a4fc6cd92 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -321,6 +321,31 @@ static void test_JsonValueStatics(void) IJsonValue_Release( json_value ); } + json = L"\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0000\\u0057\\u0069\\u006e\\u0065\\udAbC\\uDcEf\""; + 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"\"\\/\b\f\n\r\t\0Wine\U000BF0EF"; + hr = WindowsCreateString( json, 15, &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 ); + 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 ); + IJsonValue_Release( json_value ); + } + json = L"null"; check_json( json_value_statics, json, JsonValueType_Null, TRUE ); json = L"false"; @@ -384,6 +409,10 @@ static void test_JsonValueStatics(void) 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"\"\\\""; + check_json( json_value_statics, json, JsonValueType_String, FALSE ); + json = L"\"\\u123\""; + check_json( json_value_statics, json, JsonValueType_String, FALSE ); json = L"[\"Wine\" \"Linux\"]"; check_json( json_value_statics, json, JsonValueType_Array, FALSE ); json = L"{" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/Makefile.in | 1 + dlls/windows.web/classes.idl | 1 + dlls/windows.web/json_array.c | 239 ++++++++++++++++++++++++++++++++++ dlls/windows.web/main.c | 2 + dlls/windows.web/private.h | 1 + dlls/windows.web/tests/web.c | 46 +++++++ 6 files changed, 290 insertions(+) create mode 100644 dlls/windows.web/json_array.c diff --git a/dlls/windows.web/Makefile.in b/dlls/windows.web/Makefile.in index ebcf7bbc2f3..aaaacd6b298 100644 --- a/dlls/windows.web/Makefile.in +++ b/dlls/windows.web/Makefile.in @@ -3,6 +3,7 @@ IMPORTS = combase SOURCES = \ classes.idl \ + json_array.c \ json_object.c \ json_value.c \ main.c diff --git a/dlls/windows.web/classes.idl b/dlls/windows.web/classes.idl index 37537cfeb26..266f560af01 100644 --- a/dlls/windows.web/classes.idl +++ b/dlls/windows.web/classes.idl @@ -24,6 +24,7 @@ import "windows.data.json.idl"; namespace Windows.Data.Json { + runtimeclass JsonArray; runtimeclass JsonObject; runtimeclass JsonValue; } diff --git a/dlls/windows.web/json_array.c b/dlls/windows.web/json_array.c new file mode 100644 index 00000000000..d62427d92d1 --- /dev/null +++ b/dlls/windows.web/json_array.c @@ -0,0 +1,239 @@ +/* WinRT Windows.Data.Json.JsonArray Implementation + * + * Copyright (C) 2026 Olivia Ryan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(web); + +struct json_array +{ + IJsonArray IJsonArray_iface; + LONG ref; +}; + +static inline struct json_array *impl_from_IJsonArray( IJsonArray *iface ) +{ + return CONTAINING_RECORD( iface, struct json_array, IJsonArray_iface ); +} + +static HRESULT WINAPI json_array_statics_QueryInterface( IJsonArray *iface, REFIID iid, void **out ) +{ + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IJsonArray )) + { + *out = &impl->IJsonArray_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI json_array_statics_AddRef( IJsonArray *iface ) +{ + struct json_array *impl = impl_from_IJsonArray( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI json_array_statics_Release( IJsonArray *iface ) +{ + struct json_array *impl = impl_from_IJsonArray( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI json_array_statics_GetIids( IJsonArray *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetRuntimeClassName( IJsonArray *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetTrustLevel( IJsonArray *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetObjectAt( IJsonArray *iface, UINT32 index, IJsonObject **value ) +{ + FIXME( "iface %p, index %u, value %p\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetArrayAt( IJsonArray *iface, UINT32 index, IJsonArray **value ) +{ + FIXME( "iface %p, index %u, value %p\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetStringAt( IJsonArray *iface, UINT32 index, HSTRING *value ) +{ + FIXME( "iface %p, index %u, value %p\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetNumberAt( IJsonArray *iface, UINT32 index, double *value ) +{ + FIXME( "iface %p, index %u, value %p\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI json_array_statics_GetBooleanAt( IJsonArray *iface, UINT32 index, boolean *value ) +{ + FIXME( "iface %p, index %u, value %p\n", iface, index, value ); + return E_NOTIMPL; +} + +static const struct IJsonArrayVtbl json_array_statics_vtbl = +{ + json_array_statics_QueryInterface, + json_array_statics_AddRef, + json_array_statics_Release, + /* IInspectable methods */ + json_array_statics_GetIids, + json_array_statics_GetRuntimeClassName, + json_array_statics_GetTrustLevel, + /* IJsonArray methods */ + json_array_statics_GetObjectAt, + json_array_statics_GetArrayAt, + json_array_statics_GetStringAt, + json_array_statics_GetNumberAt, + json_array_statics_GetBooleanAt, +}; + +struct json_array_statics +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct json_array_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct json_array_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct json_array_statics *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + *out = &impl->IActivationFactory_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IActivationFactory *iface ) +{ + struct json_array_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct json_array_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + struct json_array *impl; + + TRACE( "iface %p, instance %p.\n", iface, instance ); + + *instance = NULL; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + + impl->IJsonArray_iface.lpVtbl = &json_array_statics_vtbl; + impl->ref = 1; + + *instance = (IInspectable*)&impl->IJsonArray_iface; + return S_OK; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +static struct json_array_statics json_array_statics = +{ + {&factory_vtbl}, + 1, +}; + +IActivationFactory *json_array_factory = &json_array_statics.IActivationFactory_iface; diff --git a/dlls/windows.web/main.c b/dlls/windows.web/main.c index 60e95fdba0c..bec92a81775 100644 --- a/dlls/windows.web/main.c +++ b/dlls/windows.web/main.c @@ -38,6 +38,8 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **fa *factory = NULL; + if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonArray )) + IActivationFactory_QueryInterface( json_array_factory, &IID_IActivationFactory, (void **)factory ); if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonObject )) IActivationFactory_QueryInterface( json_object_factory, &IID_IActivationFactory, (void **)factory ); if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonValue )) diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h index d5f0e76d641..9dda1e095f1 100644 --- a/dlls/windows.web/private.h +++ b/dlls/windows.web/private.h @@ -36,6 +36,7 @@ #define WIDL_using_Windows_Data_Json #include "windows.data.json.h" +extern IActivationFactory *json_array_factory; extern IActivationFactory *json_object_factory; extern IActivationFactory *json_value_factory; diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index b0a4fc6cd92..84a1f3e850a 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -45,6 +45,51 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid ) IUnknown_Release( unk ); } +static void test_JsonArrayStatics(void) +{ + static const WCHAR *json_array_name = L"Windows.Data.Json.JsonArray"; + IActivationFactory *factory = (void *)0xdeadbeef; + IInspectable *inspectable = (void *)0xdeadbeef; + IJsonArray *json_array = (void *)0xdeadbeef; + HSTRING str = NULL; + HRESULT hr; + LONG ref; + + hr = WindowsCreateString( json_array_name, wcslen( json_array_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_array_name ) ); + return; + } + + check_interface( factory, &IID_IUnknown ); + check_interface( factory, &IID_IInspectable ); + check_interface( factory, &IID_IAgileObject ); + + hr = IActivationFactory_QueryInterface( factory, &IID_IJsonArray, (void **)&json_array ); + ok( hr == E_NOINTERFACE, "got hr %#lx.\n", hr ); + + hr = WindowsCreateString( json_array_name, wcslen( json_array_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = RoActivateInstance( str, &inspectable ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + + hr = IInspectable_QueryInterface( inspectable, &IID_IJsonArray, (void **)&json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_interface( inspectable, &IID_IAgileObject ); + + IJsonArray_Release( json_array ); + IInspectable_Release( inspectable ); + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %ld.\n", ref ); +} + static void test_JsonObjectStatics(void) { static const WCHAR *json_object_name = L"Windows.Data.Json.JsonObject"; @@ -434,6 +479,7 @@ START_TEST(web) hr = RoInitialize( RO_INIT_MULTITHREADED ); ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + test_JsonArrayStatics(); test_JsonObjectStatics(); test_JsonValueStatics(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_array.c | 64 ++++++++++--- dlls/windows.web/tests/web.c | 164 ++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 10 deletions(-) diff --git a/dlls/windows.web/json_array.c b/dlls/windows.web/json_array.c index d62427d92d1..c48b868e062 100644 --- a/dlls/windows.web/json_array.c +++ b/dlls/windows.web/json_array.c @@ -26,6 +26,8 @@ struct json_array { IJsonArray IJsonArray_iface; LONG ref; + IJsonValue **elements; + ULONG length; }; static inline struct json_array *impl_from_IJsonArray( IJsonArray *iface ) @@ -66,7 +68,17 @@ static ULONG WINAPI json_array_statics_Release( IJsonArray *iface ) { struct json_array *impl = impl_from_IJsonArray( iface ); ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + for (UINT32 i = 0; i < impl->length; i++) + IJsonValue_Release( impl->elements[i] ); + + if (impl->elements) free( impl->elements ); + free( impl ); + } return ref; } @@ -90,32 +102,62 @@ static HRESULT WINAPI json_array_statics_GetTrustLevel( IJsonArray *iface, Trust static HRESULT WINAPI json_array_statics_GetObjectAt( IJsonArray *iface, UINT32 index, IJsonObject **value ) { - FIXME( "iface %p, index %u, value %p\n", iface, index, value ); - return E_NOTIMPL; + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, index %u, value %p\n", iface, index, value ); + + if (!value) return E_INVALIDARG; + if (index >= impl->length) return E_BOUNDS; + + return IJsonValue_GetObject( impl->elements[index], value ); } static HRESULT WINAPI json_array_statics_GetArrayAt( IJsonArray *iface, UINT32 index, IJsonArray **value ) { - FIXME( "iface %p, index %u, value %p\n", iface, index, value ); - return E_NOTIMPL; + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, index %u, value %p\n", iface, index, value ); + + if (!value) return E_INVALIDARG; + if (index >= impl->length) return E_BOUNDS; + + return IJsonValue_GetArray( impl->elements[index], value ); } static HRESULT WINAPI json_array_statics_GetStringAt( IJsonArray *iface, UINT32 index, HSTRING *value ) { - FIXME( "iface %p, index %u, value %p\n", iface, index, value ); - return E_NOTIMPL; + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, index %u, value %p\n", iface, index, value ); + + if (!value) return E_INVALIDARG; + if (index >= impl->length) return E_BOUNDS; + + return IJsonValue_GetString( impl->elements[index], value ); } static HRESULT WINAPI json_array_statics_GetNumberAt( IJsonArray *iface, UINT32 index, double *value ) { - FIXME( "iface %p, index %u, value %p\n", iface, index, value ); - return E_NOTIMPL; + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, index %u, value %p\n", iface, index, value ); + + if (!value) return E_INVALIDARG; + if (index >= impl->length) return E_BOUNDS; + + return IJsonValue_GetNumber( impl->elements[index], value ); } static HRESULT WINAPI json_array_statics_GetBooleanAt( IJsonArray *iface, UINT32 index, boolean *value ) { - FIXME( "iface %p, index %u, value %p\n", iface, index, value ); - return E_NOTIMPL; + struct json_array *impl = impl_from_IJsonArray( iface ); + + TRACE( "iface %p, index %u, value %p\n", iface, index, value ); + + if (!value) return E_INVALIDARG; + if (index >= impl->length) return E_BOUNDS; + + return IJsonValue_GetBoolean( impl->elements[index], value ); } static const struct IJsonArrayVtbl json_array_statics_vtbl = @@ -212,6 +254,8 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp impl->IJsonArray_iface.lpVtbl = &json_array_statics_vtbl; impl->ref = 1; + impl->elements = NULL; + impl->length = 0; *instance = (IInspectable*)&impl->IJsonArray_iface; return S_OK; diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 84a1f3e850a..87c7f7fb66a 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -47,14 +47,37 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid ) static void test_JsonArrayStatics(void) { + static const WCHAR *json_value_statics_name = L"Windows.Data.Json.JsonValue"; static const WCHAR *json_array_name = L"Windows.Data.Json.JsonArray"; + IJsonValueStatics *json_value_statics = (void *)0xdeadbeef; IActivationFactory *factory = (void *)0xdeadbeef; IInspectable *inspectable = (void *)0xdeadbeef; + IJsonObject *child_object = (void *)0xdeadbeef; + IJsonArray *child_array = (void *)0xdeadbeef; IJsonArray *json_array = (void *)0xdeadbeef; + IJsonValue *json_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_array_name, wcslen( json_array_name ), &str ); ok( hr == S_OK, "got hr %#lx.\n", hr ); hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); @@ -84,10 +107,151 @@ static void test_JsonArrayStatics(void) check_interface( inspectable, &IID_IAgileObject ); + hr = IJsonArray_GetObjectAt( json_array, 0, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == E_BOUNDS, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == E_BOUNDS, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == E_BOUNDS, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == E_BOUNDS, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, NULL ); + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == E_BOUNDS, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); IInspectable_Release( inspectable ); ref = IActivationFactory_Release( factory ); ok( ref == 1, "got ref %ld.\n", ref ); + + hr = WindowsCreateString( L"[{}]", wcslen( L"[{}]" ), &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)) + { + hr = IJsonValue_GetArray( json_value, &json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( json_value ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonObject_Release( child_object ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); + } + + hr = WindowsCreateString( L"[[]]", wcslen( L"[[]]" ), &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)) + { + hr = IJsonValue_GetArray( json_value, &json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( json_value ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonArray_Release( child_array ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); + } + + hr = WindowsCreateString( L"[\"Hello, World!\"]", wcslen( L"[\"Hello, World!\"]" ), &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)) + { + hr = IJsonValue_GetArray( json_value, &json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( json_value ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( child_string ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); + } + + hr = WindowsCreateString( L"[12.6]", wcslen( L"[12.6]" ), &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)) + { + hr = IJsonValue_GetArray( json_value, &json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( json_value ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); + } + + hr = WindowsCreateString( L"[true]", wcslen( L"[true]" ), &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)) + { + hr = IJsonValue_GetArray( json_value, &json_array ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonValue_Release( json_value ); + hr = IJsonArray_GetObjectAt( json_array, 0, &child_object ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetArrayAt( json_array, 0, &child_array ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetStringAt( json_array, 0, &child_string ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetNumberAt( json_array, 0, &child_number ); + ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr ); + hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IJsonArray_Release( json_array ); + } + + IJsonValueStatics_Release( json_value_statics ); } static void test_JsonObjectStatics(void) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_array.c | 19 ++++++++++++ dlls/windows.web/json_value.c | 56 ++++++++++++++++++++++++++++++++--- dlls/windows.web/private.h | 2 ++ dlls/windows.web/tests/web.c | 3 +- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/dlls/windows.web/json_array.c b/dlls/windows.web/json_array.c index c48b868e062..1bb7bef6b84 100644 --- a/dlls/windows.web/json_array.c +++ b/dlls/windows.web/json_array.c @@ -35,6 +35,25 @@ static inline struct json_array *impl_from_IJsonArray( IJsonArray *iface ) return CONTAINING_RECORD( iface, struct json_array, IJsonArray_iface ); } +HRESULT json_array_push( IJsonArray *iface, IJsonValue *value ) +{ + struct json_array *impl = impl_from_IJsonArray( iface ); + IJsonValue **new = impl->elements; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!(new = realloc( new, ++impl->length * sizeof(*new) ))) + { + impl->length--; + return E_OUTOFMEMORY; + } + + impl->elements = new; + IJsonValue_AddRef( value ); + impl->elements[impl->length - 1] = value; + return S_OK; +} + static HRESULT WINAPI json_array_statics_QueryInterface( IJsonArray *iface, REFIID iid, void **out ) { struct json_array *impl = impl_from_IJsonArray( iface ); diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index f34ce5b73d9..ed539219ef4 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -127,6 +127,7 @@ struct json_value boolean boolean_value; HSTRING string_value; double number_value; + IJsonArray *array_value; }; }; @@ -175,6 +176,8 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface ) { if (impl->json_value_type == JsonValueType_String) WindowsDeleteString( impl->string_value ); + else if (impl->json_value_type == JsonValueType_Array) + IJsonArray_Release( impl->array_value ); free( impl ); } @@ -259,12 +262,14 @@ 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 ); + TRACE( "iface %p, value %p\n", iface, value ); if (!value) return E_POINTER; if (impl->json_value_type != JsonValueType_Array) return E_ILLEGAL_METHOD_CALL; - return E_NOTIMPL; + IJsonArray_AddRef( impl->array_value ); + *value = impl->array_value; + return S_OK; } static HRESULT WINAPI json_value_GetObject( IJsonValue *iface, IJsonObject **value ) @@ -341,6 +346,50 @@ static WCHAR json_buffer_next( struct json_buffer *json, const WCHAR *valid ) return chr; } +static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ); + +static HRESULT parse_json_array( struct json_buffer *json, IJsonArray **value ) +{ + IJsonArray *array; + IJsonValue *child; + HRESULT hr; + + if (!json_buffer_take( json, L"[" )) return WEB_E_INVALID_JSON_STRING; + if (FAILED(hr = IActivationFactory_ActivateInstance( + json_array_factory, (IInspectable**)&array ))) return hr; + + json_buffer_trim( json ); + while (json->len && *json->str != ']') + { + if (FAILED(hr = parse_json_value( json, &child ))) + { + IJsonArray_Release( array ); + return hr; + } + + hr = json_array_push( array, child ); + IJsonValue_Release( child ); + if (FAILED(hr)) + { + IJsonArray_Release( array ); + return hr; + } + + json_buffer_trim( json ); + if (!json_buffer_take( json, L"," )) break; + json_buffer_trim( json ); + } + + if (!json_buffer_take( json, L"]" )) + { + IJsonArray_Release( array ); + return WEB_E_INVALID_JSON_STRING; + } + + *value = array; + return S_OK; +} + static HRESULT parse_json_string( struct json_buffer *json, HSTRING *output ) { const WCHAR valid_hex_chars[] = L"abcdefABCDEF0123456789"; @@ -437,9 +486,8 @@ static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value ) } else if (*json->str == '[') { - FIXME( "Array parsing not implemented!\n" ); + hr = parse_json_array( json, &impl->array_value ); impl->json_value_type = JsonValueType_Array; - hr = WEB_E_INVALID_JSON_STRING; } else if (*json->str == '{') { diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h index 9dda1e095f1..b8cc30cda42 100644 --- a/dlls/windows.web/private.h +++ b/dlls/windows.web/private.h @@ -40,6 +40,8 @@ extern IActivationFactory *json_array_factory; extern IActivationFactory *json_object_factory; extern IActivationFactory *json_value_factory; +HRESULT json_array_push( IJsonArray *iface, IJsonValue *value ); + #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 87c7f7fb66a..1b29447dfd2 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -327,7 +327,7 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static return; } - todo_wine_if(expected_json_value_type == JsonValueType_Array || expected_json_value_type == JsonValueType_Object) + 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 ); @@ -398,7 +398,6 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static 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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_object.c | 50 ++++++++++++++++++++++++++++++---- dlls/windows.web/private.h | 1 + 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/dlls/windows.web/json_object.c b/dlls/windows.web/json_object.c index 38c899288b7..81f12e2b72d 100644 --- a/dlls/windows.web/json_object.c +++ b/dlls/windows.web/json_object.c @@ -1,6 +1,7 @@ /* WinRT Windows.Data.Json.JsonObject Implementation * * Copyright (C) 2024 Mohamad Al-Jaf + * Copyright (C) 2026 Olivia Ryan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ struct json_object { IJsonObject IJsonObject_iface; LONG ref; + IMap_HSTRING_IInspectable *members; }; static inline struct json_object *impl_from_IJsonObject( IJsonObject *iface ) @@ -69,7 +71,10 @@ static ULONG WINAPI json_object_statics_Release( IJsonObject *iface ) TRACE( "iface %p, ref %lu.\n", iface, ref ); - if (!ref) free( impl ); + if (!ref) { + IMap_HSTRING_IInspectable_Release( impl->members ); + free( impl ); + } return ref; } @@ -93,14 +98,25 @@ static HRESULT WINAPI json_object_statics_GetTrustLevel( IJsonObject *iface, Tru static HRESULT WINAPI json_object_statics_GetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue **value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + struct json_object *impl = impl_from_IJsonObject( iface ); + boolean exists; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + + hr = IMap_HSTRING_IInspectable_HasKey( impl->members, name, &exists ); + if ( FAILED(hr) || !exists ) return WEB_E_JSON_VALUE_NOT_FOUND; + return IMap_HSTRING_IInspectable_Lookup( impl->members, name, (IInspectable**)value ); } static HRESULT WINAPI json_object_statics_SetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue *value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + boolean dummy; + struct json_object *impl = impl_from_IJsonObject( iface ); + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + return IMap_HSTRING_IInspectable_Insert( impl->members, name, (IInspectable*)value, &dummy ); } static HRESULT WINAPI json_object_statics_GetNamedObject( IJsonObject *iface, HSTRING name, IJsonObject **value ) @@ -220,7 +236,12 @@ static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLev static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) { + const WCHAR *property_set_str = RuntimeClass_Windows_Foundation_Collections_PropertySet; + IPropertySet *property_set; + HSTRING property_set_class; struct json_object *impl; + HSTRING_HEADER header; + HRESULT hr; TRACE( "iface %p, instance %p.\n", iface, instance ); @@ -230,6 +251,25 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp impl->IJsonObject_iface.lpVtbl = &json_object_statics_vtbl; impl->ref = 1; + WindowsCreateStringReference( + property_set_str, wcslen( property_set_str ), &header, &property_set_class ); + + if (FAILED(hr = RoActivateInstance( property_set_class, (IInspectable**)&property_set ))) + { + free( impl ); + return hr; + } + + hr = IPropertySet_QueryInterface( + property_set, &IID_IMap_HSTRING_IInspectable, (void**)&impl->members ); + + IPropertySet_Release( property_set ); + if (FAILED(hr)) + { + free( impl ); + return hr; + } + *instance = (IInspectable *)&impl->IJsonObject_iface; return S_OK; } diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h index b8cc30cda42..6722d69bc57 100644 --- a/dlls/windows.web/private.h +++ b/dlls/windows.web/private.h @@ -29,6 +29,7 @@ #include "winstring.h" #include "activation.h" +#include "roapi.h" #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_object.c | 85 ++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/dlls/windows.web/json_object.c b/dlls/windows.web/json_object.c index 81f12e2b72d..afb0fc6e1f4 100644 --- a/dlls/windows.web/json_object.c +++ b/dlls/windows.web/json_object.c @@ -121,32 +121,97 @@ static HRESULT WINAPI json_object_statics_SetNamedValue( IJsonObject *iface, HST static HRESULT WINAPI json_object_statics_GetNamedObject( IJsonObject *iface, HSTRING name, IJsonObject **value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + IJsonValue *internal_value; + JsonValueType value_type; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value ))) + return hr; + + IJsonValue_Release( internal_value ); + IJsonValue_get_ValueType( internal_value, &value_type ); + if (value_type != JsonValueType_Object) return E_ILLEGAL_METHOD_CALL; + + return IJsonValue_GetObject( internal_value, value ); } static HRESULT WINAPI json_object_statics_GetNamedArray( IJsonObject *iface, HSTRING name, IJsonArray **value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + IJsonValue *internal_value; + JsonValueType value_type; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value ))) + return hr; + + IJsonValue_Release( internal_value ); + IJsonValue_get_ValueType( internal_value, &value_type ); + if (value_type != JsonValueType_Array) return E_ILLEGAL_METHOD_CALL; + + return IJsonValue_GetArray( internal_value, value ); } static HRESULT WINAPI json_object_statics_GetNamedString( IJsonObject *iface, HSTRING name, HSTRING *value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + IJsonValue *internal_value; + JsonValueType value_type; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value ))) + return hr; + + IJsonValue_Release( internal_value ); + IJsonValue_get_ValueType( internal_value, &value_type ); + if (value_type != JsonValueType_String) return E_ILLEGAL_METHOD_CALL; + + return IJsonValue_GetString( internal_value, value ); } static HRESULT WINAPI json_object_statics_GetNamedNumber( IJsonObject *iface, HSTRING name, DOUBLE *value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + IJsonValue *internal_value; + JsonValueType value_type; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value ))) + return hr; + + IJsonValue_Release( internal_value ); + IJsonValue_get_ValueType( internal_value, &value_type ); + if (value_type != JsonValueType_Number) return E_ILLEGAL_METHOD_CALL; + + return IJsonValue_GetNumber( internal_value, value ); } static HRESULT WINAPI json_object_statics_GetNamedBoolean( IJsonObject *iface, HSTRING name, boolean *value ) { - FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value ); - return E_NOTIMPL; + IJsonValue *internal_value; + JsonValueType value_type; + HRESULT hr; + + TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value ); + + if (!value) return E_POINTER; + if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value ))) + return hr; + + IJsonValue_Release( internal_value ); + IJsonValue_get_ValueType( internal_value, &value_type ); + if (value_type != JsonValueType_Boolean) return E_ILLEGAL_METHOD_CALL; + + return IJsonValue_GetBoolean( internal_value, value ); } static const struct IJsonObjectVtbl json_object_statics_vtbl = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 74 ++++++++++++- dlls/windows.web/tests/web.c | 197 +++++++++++++++++++++++++++++++++- 2 files changed, 263 insertions(+), 8 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index ed539219ef4..8de5627f673 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,6 +458,66 @@ 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; @@ -491,9 +556,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 +598,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
From: Olivia Ryan <olivia.r.dev@gmail.com> --- dlls/windows.web/json_value.c | 34 ++++++++++++++++++++++++++++++---- dlls/windows.web/tests/web.c | 24 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index 8de5627f673..0a20be5150a 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -617,14 +617,40 @@ static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HST static HRESULT WINAPI json_value_statics_CreateBooleanValue( IJsonValueStatics *iface, boolean input, IJsonValue **value ) { - FIXME( "iface %p, input %d, value %p stub!\n", iface, input, value ); - return E_NOTIMPL; + struct json_value *impl; + + TRACE( "iface %p, input %d, value %p\n", iface, input, value ); + + if (!value) return E_POINTER; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + + impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; + impl->ref = 1; + impl->json_value_type = JsonValueType_Boolean; + impl->boolean_value = input != FALSE; + + *value = &impl->IJsonValue_iface; + TRACE( "created IJsonValue %p.\n", *value ); + return S_OK; } static HRESULT WINAPI json_value_statics_CreateNumberValue( IJsonValueStatics *iface, DOUBLE input, IJsonValue **value ) { - FIXME( "iface %p, input %f, value %p stub!\n", iface, input, value ); - return E_NOTIMPL; + struct json_value *impl; + + TRACE( "iface %p, input %f, value %p\n", iface, input, value ); + + if (!value) return E_POINTER; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + + impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; + impl->ref = 1; + impl->json_value_type = JsonValueType_Number; + impl->number_value = input; + + *value = &impl->IJsonValue_iface; + TRACE( "created IJsonValue %p.\n", *value ); + return S_OK; } static HRESULT WINAPI json_value_statics_CreateStringValue( IJsonValueStatics *iface, HSTRING input, IJsonValue **value ) diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c index 8b91ddfe530..67e82dbe63e 100644 --- a/dlls/windows.web/tests/web.c +++ b/dlls/windows.web/tests/web.c @@ -661,6 +661,30 @@ 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_CreateBooleanValue( json_value_statics, FALSE, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_CreateBooleanValue( json_value_statics, FALSE, &json_value ); + ok( hr == S_OK, "got hr %#lx,\n", hr ); + hr = IJsonValue_get_ValueType( json_value, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_get_ValueType( json_value, &json_value_type ); + ok( json_value_type == JsonValueType_Boolean, "got JsonValueType %d.\n", json_value_type ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ref = IJsonValue_Release( json_value ); + ok( ref == 0, "got ref %ld.\n", ref ); + + hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 0, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 0, &json_value ); + ok( hr == S_OK, "got hr %#lx,\n", hr ); + hr = IJsonValue_get_ValueType( json_value, NULL ); + ok( hr == E_POINTER, "got hr %#lx.\n", hr ); + hr = IJsonValue_get_ValueType( json_value, &json_value_type ); + ok( json_value_type == JsonValueType_Number, "got JsonValueType %d.\n", json_value_type ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ref = IJsonValue_Release( json_value ); + ok( ref == 0, "got ref %ld.\n", ref ); + 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 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10263
participants (2)
-
Olivia Ryan -
Olivia Ryan (@olivi-r)