Skip to content

Commit b6ae4e1

Browse files
committed
[RTL] Fix searching resource names
Resource names are sorted with '_' being higher than any alphabetic characters. This means _wcsicmp cannot be used to search, because it lowercases the characters before comparison, which would make '_' lower than lowercase alphabetic characters. Implement a custom compare function instead. See CORE-20401, CORE-20408
1 parent 89e4b6b commit b6ae4e1

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

sdk/lib/rtl/res.c

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,53 @@ IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
121121
return NULL;
122122
}
123123

124+
/*
125+
* This function performs a case-insensitive comparison of a
126+
* null-terminated wide string with a resource string.
127+
* Unlike _wcsicmp, which lowercases the characters before comparison,
128+
* this function uppercases them, because that is how resource strings
129+
* are sorted (e.g. '_' comes after 'z' / 'Z').
130+
*/
131+
static
132+
int
133+
CompareResourceString(
134+
const wchar_t *SearchString,
135+
const IMAGE_RESOURCE_DIR_STRING_U *ResourceString)
136+
{
137+
wchar_t const* p1 = SearchString;
138+
wchar_t const* p2 = ResourceString->NameString;
139+
size_t remaining = ResourceString->Length;
140+
wchar_t chr1, chr2;
141+
142+
while (remaining-- != 0)
143+
{
144+
chr1 = *p1++;
145+
chr2 = *p2++;
146+
147+
/* Quick direct comparison first */
148+
if (chr1 != chr2)
149+
{
150+
/* No direct match, upcase both characters */
151+
if ((chr1 >= 'a') && (chr1 <= 'z'))
152+
chr1 -= ('a' - 'A');
153+
if ((chr2 >= 'a') && (chr2 <= 'z'))
154+
chr2 -= ('a' - 'A');
155+
156+
/* Compare again, if they don't match, return the difference */
157+
if (chr1 != chr2)
158+
return chr1 - chr2;
159+
}
160+
}
161+
162+
/* All characters matched, check if the search string ends here */
163+
if (*p1 != 0)
164+
{
165+
/* The search string is longer, return a positive result */
166+
return 1;
167+
}
168+
169+
return 0;
170+
}
124171

125172
/**********************************************************************
126173
* find_entry_by_name
@@ -134,19 +181,17 @@ IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
134181
const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
135182
const IMAGE_RESOURCE_DIR_STRING_U *str;
136183
int min, max, res, pos;
137-
size_t namelen;
138184

139185
if (!((ULONG_PTR)name & 0xFFFF0000)) return find_entry_by_id( dir, (ULONG_PTR)name & 0xFFFF, root, want_dir );
140186
entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
141-
namelen = wcslen(name);
142187
min = 0;
143188
max = dir->NumberOfNamedEntries - 1;
144189
while (min <= max)
145190
{
146191
pos = (min + max) / 2;
147192
str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const char *)root + entry[pos].NameOffset);
148-
res = _wcsnicmp( name, str->NameString, str->Length );
149-
if (!res && namelen == str->Length)
193+
res = CompareResourceString(name, str);
194+
if (!res)
150195
{
151196
if (!entry[pos].DataIsDirectory == !want_dir)
152197
{

0 commit comments

Comments
 (0)