For React Native.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/wintypes/main.c | 208 +++++++++++++++++++++++++++++++++ dlls/wintypes/wintypes.spec | 2 +- include/rometadataresolution.h | 1 + 3 files changed, 210 insertions(+), 1 deletion(-)
diff --git a/dlls/wintypes/main.c b/dlls/wintypes/main.c index ac4214b486f..46c2a1d7911 100644 --- a/dlls/wintypes/main.c +++ b/dlls/wintypes/main.c @@ -1240,3 +1240,211 @@ HRESULT WINAPI RoResolveNamespace(HSTRING name, HSTRING windowsMetaDataDir,
return RO_E_METADATA_NAME_NOT_FOUND; } + +struct parse_type_context +{ + DWORD allocated_parts_count; + DWORD parts_count; + HSTRING *parts; +}; + +static HRESULT add_part(struct parse_type_context *context, const WCHAR *part, size_t length) +{ + DWORD new_parts_count; + HSTRING *new_parts; + HRESULT hr; + + if (context->parts_count == context->allocated_parts_count) + { + new_parts_count = context->allocated_parts_count ? context->allocated_parts_count * 2 : 4; + new_parts = CoTaskMemRealloc(context->parts, new_parts_count * sizeof(*context->parts)); + if (!new_parts) + return E_OUTOFMEMORY; + + context->allocated_parts_count = new_parts_count; + context->parts = new_parts; + } + + if (FAILED(hr = WindowsCreateString(part, length, &context->parts[context->parts_count]))) + return hr; + + context->parts_count++; + return S_OK; +} + +static HRESULT parse_part(struct parse_type_context *context, const WCHAR *input, unsigned int length) +{ + const WCHAR *start, *end, *ptr; + + start = input; + end = start + length; + + /* Remove leading spaces */ + while (start < end && *start == ' ') + start++; + + /* Remove trailing spaces */ + while (end - 1 >= start && end[-1] == ' ') + end--; + + /* Only contains spaces */ + if (start == end) + return RO_E_METADATA_INVALID_TYPE_FORMAT; + + /* Has spaces in the middle */ + for (ptr = start; ptr < end; ptr++) + { + if (*ptr == ' ') + return RO_E_METADATA_INVALID_TYPE_FORMAT; + } + + return add_part(context, start, end - start); +} + +static HRESULT parse_type(struct parse_type_context *context, const WCHAR *input, unsigned int length) +{ + unsigned int i, parameter_count, nested_level; + const WCHAR *start, *end, *part_start, *ptr; + HRESULT hr; + + start = input; + end = start + length; + part_start = start; + ptr = start; + + /* Read until the end of input or '`' or '<' or '>' or ',' */ + while (ptr < end && *ptr != '`' && *ptr != '<' && *ptr != '>' && *ptr != ',') + ptr++; + + /* If the type name has '`' and there are characters before '`' */ + if (ptr > start && ptr < end && *ptr == '`') + { + /* Move past the '`' */ + ptr++; + + /* Read the number of type parameters, expecting '1' to '9' */ + if (!(ptr < end && *ptr >= '1' && *ptr <= '9')) + return RO_E_METADATA_INVALID_TYPE_FORMAT; + parameter_count = *ptr - '0'; + + /* Move past the number of type parameters, expecting '<' */ + ptr++; + if (!(ptr < end && *ptr == '<')) + return RO_E_METADATA_INVALID_TYPE_FORMAT; + + /* Add the name of parameterized interface, e.g., the "interface`1" in "interface`1<parameter>" */ + if (FAILED(hr = parse_part(context, part_start, ptr - part_start))) + return hr; + + /* Move past the '<' */ + ptr++; + nested_level = 1; + + /* Read parameters inside brackets, e.g., the "p1" and "p2" in "interface`2<p1, p2>" */ + for (i = 0; i < parameter_count; i++) + { + /* Read a new parameter */ + part_start = ptr; + + /* Read until ','. The comma must be at the same nested bracket level */ + while (ptr < end) + { + if (*ptr == '<') + { + nested_level++; + ptr++; + } + else if (*ptr == '>') + { + /* The last parameter before '>' */ + if (i == parameter_count - 1 && nested_level == 1) + { + if (FAILED(hr = parse_type(context, part_start, ptr - part_start))) + return hr; + + nested_level--; + ptr++; + + /* Finish reading all parameters */ + break; + } + + nested_level--; + ptr++; + } + else if (*ptr == ',' && nested_level == 1) + { + /* Parse the parameter, which can be another parameterized type */ + if (FAILED(hr = parse_type(context, part_start, ptr - part_start))) + return hr; + + /* Move past the ',' */ + ptr++; + + /* Finish reading one parameter */ + break; + } + else + { + ptr++; + } + } + } + + /* Mismatching brackets or not enough parameters */ + if (nested_level != 0 || i != parameter_count) + return RO_E_METADATA_INVALID_TYPE_FORMAT; + + /* The remaining characters must be spaces */ + while (ptr < end) + { + if (*ptr++ != ' ') + return RO_E_METADATA_INVALID_TYPE_FORMAT; + } + + return S_OK; + } + /* Contain invalid '`', '<', '>' or ',' */ + else if (ptr != end) + { + return RO_E_METADATA_INVALID_TYPE_FORMAT; + } + /* Non-parameterized */ + else + { + return parse_part(context, part_start, ptr - part_start); + } +} + +HRESULT WINAPI RoParseTypeName(HSTRING type_name, DWORD *parts_count, HSTRING **parts) +{ + struct parse_type_context context = {0}; + const WCHAR *input; + unsigned int i; + HRESULT hr; + + TRACE("%s %p %p.\n", debugstr_hstring(type_name), parts_count, parts); + + /* Empty string */ + if (!WindowsGetStringLen(type_name)) + return E_INVALIDARG; + + input = WindowsGetStringRawBuffer(type_name, NULL); + /* The string has a leading space */ + if (input[0] == ' ') + return RO_E_METADATA_INVALID_TYPE_FORMAT; + + *parts_count = 0; + *parts = NULL; + if (FAILED(hr = parse_type(&context, input, wcslen(input)))) + { + for (i = 0; i < context.parts_count; i++) + WindowsDeleteString(context.parts[i]); + CoTaskMemFree(context.parts); + return hr; + } + + *parts_count = context.parts_count; + *parts = context.parts; + return S_OK; +} diff --git a/dlls/wintypes/wintypes.spec b/dlls/wintypes/wintypes.spec index 086332e0d69..a1eb0f3830d 100644 --- a/dlls/wintypes/wintypes.spec +++ b/dlls/wintypes/wintypes.spec @@ -7,5 +7,5 @@ @ stub RoGetMetaDataFile @ stdcall RoIsApiContractMajorVersionPresent(wstr long ptr) @ stub RoIsApiContractPresent -@ stub RoParseTypeName +@ stdcall RoParseTypeName(ptr ptr ptr) @ stdcall RoResolveNamespace(ptr ptr long ptr ptr ptr ptr ptr) diff --git a/include/rometadataresolution.h b/include/rometadataresolution.h index 90258ff5aa0..e47e5fa47d6 100644 --- a/include/rometadataresolution.h +++ b/include/rometadataresolution.h @@ -23,6 +23,7 @@ #include <hstring.h>
HRESULT WINAPI RoIsApiContractMajorVersionPresent(const WCHAR *, UINT16, BOOL *); +HRESULT WINAPI RoParseTypeName(HSTRING, DWORD *, HSTRING **); HRESULT WINAPI RoResolveNamespace(HSTRING, HSTRING, DWORD, const HSTRING *, DWORD *, HSTRING **, DWORD *, HSTRING **);
#endif /* _ROMETADATARESOLUTION_H */
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/wintypes/tests/wintypes.c | 148 +++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index cb24dee77cf..078afa1c224 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -814,11 +814,159 @@ static void test_RoResolveNamespace(void) RoUninitialize(); }
+static void test_RoParseTypeName(void) +{ + static const struct + { + const WCHAR *type_name; + HRESULT hr; + DWORD parts_count; + const WCHAR *parts[16]; + } + tests[] = + { + /* Invalid type names */ + {L"", E_INVALIDARG}, + {L" ", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"`", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"<", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L">", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L",", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"`<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a b", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a,b", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"1<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L" a", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L" a ", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a<", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`1<>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a<b>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`<b> ", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"`1<b>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L" a`1<b>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`1<b>c", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`1<b,>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`2<b, <c, d>>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`10<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`0xa<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + {L"a`a<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT}, + /* Valid type names */ + {L"1", S_OK, 1, {L"1"}}, + {L"a", S_OK, 1, {L"a"}}, + {L"-", S_OK, 1, {L"-"}}, + {L"a ", S_OK, 1, {L"a"}}, + {L"0`1<b>", S_OK, 2, {L"0`1", L"b"}}, + {L"a`1<b>", S_OK, 2, {L"a`1", L"b"}}, + {L"a`1<b> ", S_OK, 2, {L"a`1", L"b"}}, + {L"a`1<b >", S_OK, 2, {L"a`1", L"b"}}, + {L"a`1< b>", S_OK, 2, {L"a`1", L"b"}}, + {L"a`1< b >", S_OK, 2, {L"a`1", L"b"}}, + {L"a`2<b,c>", S_OK, 3, {L"a`2", L"b", L"c"}}, + {L"a`2<b, c>", S_OK, 3, {L"a`2", L"b", L"c"}}, + {L"a`2<b ,c>", S_OK, 3, {L"a`2", L"b", L"c"}}, + {L"a`2<b , c>", S_OK, 3, {L"a`2", L"b", L"c"}}, + {L"a`3<b, c, d>", S_OK, 4, {L"a`3", L"b", L"c", L"d"}}, + {L"a`1<b`1<c>>", S_OK, 3, {L"a`1", L"b`1", L"c"}}, + {L"a`1<b`2<c, d>>", S_OK, 4, {L"a`1", L"b`2", L"c", L"d"}}, + {L"a`2<b`2<c, d>, e>", S_OK, 5, {L"a`2", L"b`2", L"c", L"d", L"e"}}, + {L"a`2<b, c`2<d, e>>", S_OK, 5, {L"a`2", L"b", L"c`2", L"d", L"e"}}, + {L"a`9<b1, b2, b3, b4, b5, b6, b7, b8, b9>", S_OK, 10, {L"a`9", L"b1", L"b2", L"b3", L"b4", L"b5", L"b6", L"b7", L"b8", L"b9"}}, + {L"Windows.Foundation.IExtensionInformation", S_OK, 1, {L"Windows.Foundation.IExtensionInformation"}}, + {L"Windows.Foundation.IReference`1<Windows.UI.Color>", S_OK, 2, {L"Windows.Foundation.IReference`1", L"Windows.UI.Color"}}, + {L"Windows.Foundation.Collections.IIterator`1<Windows.Foundation.Collections.IMapView`2<Windows.Foundation.Collections.IVector`1<String>, String>>", + S_OK, 5, {L"Windows.Foundation.Collections.IIterator`1", + L"Windows.Foundation.Collections.IMapView`2", + L"Windows.Foundation.Collections.IVector`1", + L"String", + L"String"}}, + }; + HSTRING type_name, *parts; + const WCHAR *buffer; + DWORD parts_count; + unsigned int i, j; + HRESULT hr; + + /* Parameter checks */ + hr = WindowsCreateString(L"a", 1, &type_name); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = RoParseTypeName(NULL, &parts_count, &parts); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + /* Crash on Windows */ + if (0) + { + hr = RoParseTypeName(type_name, NULL, &parts); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = RoParseTypeName(type_name, &parts_count, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + } + + hr = RoParseTypeName(type_name, &parts_count, &parts); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(parts_count == 1, "Got unexpected %ld.\n", parts_count); + hr = WindowsDeleteString(parts[0]); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + CoTaskMemFree(parts); + hr = WindowsDeleteString(type_name); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Parsing checks */ + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + winetest_push_context("%s", wine_dbgstr_w(tests[i].type_name)); + + if (tests[i].type_name) + { + hr = WindowsCreateString(tests[i].type_name, wcslen(tests[i].type_name), &type_name); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + } + else + { + type_name = NULL; + } + + parts_count = 0; + hr = RoParseTypeName(type_name, &parts_count, &parts); + ok(hr == tests[i].hr, "Got unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + { + hr = WindowsDeleteString(type_name); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + winetest_pop_context(); + continue; + } + ok(parts_count == tests[i].parts_count, "Got unexpected %lu.\n", parts_count); + + for (j = 0; j < parts_count; j++) + { + winetest_push_context("%s", wine_dbgstr_w(tests[i].parts[j])); + + buffer = WindowsGetStringRawBuffer(parts[j], NULL); + ok(!lstrcmpW(tests[i].parts[j], buffer), "Got unexpected %s.\n", wine_dbgstr_w(buffer)); + hr = WindowsDeleteString(parts[j]); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + CoTaskMemFree(parts); + + hr = WindowsDeleteString(type_name); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + winetest_pop_context(); + } +} + START_TEST(wintypes) { IsWow64Process(GetCurrentProcess(), &is_wow64);
test_IApiInformationStatics(); test_IPropertyValueStatics(); + test_RoParseTypeName(); test_RoResolveNamespace(); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149718
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: win.c:4073: Test succeeded inside todo block: Expected active window 0000000006430152, got 0000000006430152. win.c:4074: Test succeeded inside todo block: Expected focus window 0000000006430152, got 0000000006430152.