From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56914 --- dlls/windows.web/json_value.c | 175 +++++++++++++++++++++++++++++++++- dlls/windows.web/private.h | 1 + 2 files changed, 174 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c index dfd3820b915..7b08aa0de2f 100644 --- a/dlls/windows.web/json_value.c +++ b/dlls/windows.web/json_value.c @@ -121,6 +121,9 @@ struct json_value LONG ref;
JsonValueType json_value_type; + HSTRING parsed_string; + double parsed_number; + boolean parsed_boolean; HSTRING string_value; };
@@ -167,6 +170,7 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface )
if (!ref) { + WindowsDeleteString( impl->parsed_string ); WindowsDeleteString( impl->string_value ); free( impl ); } @@ -260,10 +264,177 @@ static const struct IJsonValueVtbl json_value_vtbl =
DEFINE_IINSPECTABLE( json_value_statics, IJsonValueStatics, struct json_value_statics, IActivationFactory_iface )
+static HRESULT validate_json( HSTRING input, JsonValueType *json_value_type, double *parsed_number, boolean *parsed_boolean ) +{ + BOOL in_string = FALSE, expect_comma = FALSE, expect_value = TRUE; + int square_brackets = 0, curly_brackets = 0; + const WCHAR *json = WindowsGetStringRawBuffer( input, NULL ); + UINT json_len = wcslen( json ); + + /* FIXME: Handle all JSON edge cases */ + + if (!wcscmp( L"null", json )) + { + *json_value_type = JsonValueType_Null; + return S_OK; + } + if (!wcscmp( L"true", json ) || !wcscmp( L"false", json )) + { + *parsed_boolean = !wcscmp( L"true", json ); + *json_value_type = JsonValueType_Boolean; + return S_OK; + } + if (json[0] == '"' && json[json_len - 1] == '"') + { + *json_value_type = JsonValueType_String; + return S_OK; + } + if (json[0] == '[' && json[json_len - 1] == ']') + { + *json_value_type = JsonValueType_Array; + } + else if (json[0] == '{' && json[json_len - 1] == '}') + { + *json_value_type = JsonValueType_Object; + } + else + { + double result = 0; + WCHAR *end; + + errno = 0; + result = wcstod( json, &end ); + + if (errno == ERANGE) return WEB_E_INVALID_JSON_NUMBER; + if (result || ( !errno && end != json )) + { + *parsed_number = result; + *json_value_type = JsonValueType_Number; + return S_OK; + } + } + + for ( int i = 0; json[i] != '\0'; i++ ) + { + char c = json[i]; + + if (c == '"' && ( i == 0 || json[i - 1] != '\' )) + { + in_string = !in_string; + + if (!in_string) + { + if (expect_value) + { + expect_value = FALSE; + expect_comma = TRUE; + } + else if (expect_comma) + { + return WEB_E_INVALID_JSON_STRING; + } + } + continue; + } + + if (in_string || isspace(c)) continue; + + switch (c) + { + case '{': + if (!expect_value) return WEB_E_INVALID_JSON_STRING; + curly_brackets++; + expect_value = TRUE; + expect_comma = FALSE; + break; + case '}': + if (!curly_brackets || expect_value) return WEB_E_INVALID_JSON_STRING; + curly_brackets--; + expect_comma = TRUE; + break; + case '[': + if (!expect_value) return WEB_E_INVALID_JSON_STRING; + square_brackets++; + expect_value = TRUE; + expect_comma = FALSE; + break; + case ']': + if (!square_brackets || expect_value) return WEB_E_INVALID_JSON_STRING; + square_brackets--; + expect_comma = TRUE; + break; + case ':': + if (!expect_comma) return WEB_E_INVALID_JSON_STRING; + expect_value = TRUE; + expect_comma = FALSE; + break; + case ',': + if (!expect_comma) return WEB_E_INVALID_JSON_STRING; + expect_value = TRUE; + expect_comma = FALSE; + break; + default: + if (!expect_value) return WEB_E_INVALID_JSON_STRING; + expect_value = FALSE; + expect_comma = TRUE; + break; + } + } + + return (!in_string && !curly_brackets && !square_brackets && !expect_value) ? S_OK : WEB_E_INVALID_JSON_STRING; +} + +static HRESULT trim_string( HSTRING input, const WCHAR *string_to_remove, HSTRING *trimmed_string ) +{ + HSTRING pattern = NULL, new_string = NULL; + HRESULT hr = WindowsCreateString( string_to_remove, wcslen( string_to_remove ), &pattern ); + + if (SUCCEEDED(hr)) hr = WindowsTrimStringStart( input, pattern, &new_string ); + if (SUCCEEDED(hr)) hr = WindowsTrimStringEnd( new_string, pattern, &new_string ); + if (SUCCEEDED(hr)) hr = WindowsDuplicateString( new_string, trimmed_string ); + + WindowsDeleteString( pattern ); + WindowsDeleteString( new_string ); + return hr; +} + +static HRESULT parse_json( HSTRING json, struct json_value *impl ) +{ + HSTRING trimmed_json = NULL; + HRESULT hr = trim_string( json, L" ", &trimmed_json ); + + if (SUCCEEDED(hr) && WindowsIsStringEmpty( trimmed_json )) hr = WEB_E_INVALID_JSON_STRING; + + if (SUCCEEDED(hr)) hr = validate_json( trimmed_json, &impl->json_value_type, &impl->parsed_number, &impl->parsed_boolean ); + if (SUCCEEDED(hr)) hr = trim_string( trimmed_json, L"\"", &trimmed_json ); + if (SUCCEEDED(hr)) hr = WindowsDuplicateString( trimmed_json, &impl->parsed_string ); + + WindowsDeleteString( trimmed_json ); + return hr; +} + static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRING input, IJsonValue **value ) { - FIXME( "iface %p, input %s, value %p stub!\n", iface, debugstr_hstring( input ), value ); - return E_NOTIMPL; + struct json_value *impl; + HRESULT hr; + + FIXME( "iface %p, input %s, value %p semi-stub\n", iface, debugstr_hstring( input ), value ); + + if (!value) return E_POINTER; + if (!input) return WEB_E_INVALID_JSON_STRING; + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + if (FAILED(hr = parse_json( input, impl ))) + { + free( impl ); + return hr; + } + impl->IJsonValue_iface.lpVtbl = &json_value_vtbl; + impl->ref = 1; + + *value = &impl->IJsonValue_iface; + TRACE( "created IJsonValue %p.\n", *value ); + return S_OK; }
static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HSTRING input, IJsonValue **result, boolean *succeeded ) diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h index 393affd61e1..d5f0e76d641 100644 --- a/dlls/windows.web/private.h +++ b/dlls/windows.web/private.h @@ -21,6 +21,7 @@ #define __WINE_WINDOWS_WEB_PRIVATE_H
#include <stdarg.h> +#include <errno.h>
#define COBJMACROS #include "windef.h"