Skip to content

Commit 72719d8

Browse files
committed
[MERGE #5251 @msdimitrov] Convert JavascriptString::EntryLocaleCompare to use LogicalStringCompare
Merge pull request #5251 from msdimitrov:entrylocalecompare Resolves #4841 Resolves #4843 I didn't change the error message, since I'm not sure if a new error message should be added to `rterros.h` or throw the error from `GetLastError()` .
2 parents 81632c7 + c4aee80 commit 72719d8

File tree

11 files changed

+79
-36
lines changed

11 files changed

+79
-36
lines changed

bin/ChakraCore/TestHooks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Internal
1414
{
1515
// this is in place of including PlatformAgnostic/UnicodeTextInternal.h, which has template
1616
// instantiations that upset Clang on macOS and Linux
17-
int LogicalStringCompareImpl(const char16* p1, const char16* p2);
17+
int LogicalStringCompareImpl(const char16* p1, int p1size, const char16* p2, int p2size);
1818
}
1919
}
2020
}

bin/ChakraCore/TestHooks.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct TestHooks
2222
typedef HRESULT(TESTHOOK_CALL *SetAssertToConsoleFlagPtr)(bool flag);
2323
typedef HRESULT(TESTHOOK_CALL *SetEnableCheckMemoryLeakOutputPtr)(bool flag);
2424
typedef void(TESTHOOK_CALL * NotifyUnhandledExceptionPtr)(PEXCEPTION_POINTERS exceptionInfo);
25-
typedef int(TESTHOOK_CALL *LogicalStringCompareImpl)(const char16* p1, const char16* p2);
25+
typedef int(TESTHOOK_CALL *LogicalStringCompareImpl)(const char16* p1, int p1size, const char16* p2, int p2size);
2626

2727
SetConfigFlagsPtr pfSetConfigFlags;
2828
SetConfigFilePtr pfSetConfigFile;

bin/NativeTests/UnicodeTextTests.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,29 @@ namespace UnicodeTextTest
1717
REQUIRE(g_testHooksLoaded);
1818

1919
// there are two tests, one to validate the expected value and validate the result of the call
20-
int compareStringResult = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_DIGITSASNUMBERS, str1, -1, str2, -1);
20+
int compareStringResult = CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE | SORT_DIGITSASNUMBERS, str1, -1, str2, -1, NULL, NULL, 0);
2121
CHECK(compareStringResult != 0);
2222
compareStringResult = compareStringResult - CSTR_EQUAL;
2323

24-
int res = g_testHooks.pfLogicalCompareStringImpl(str1, str2);
24+
int res = g_testHooks.pfLogicalCompareStringImpl(str1, static_cast<int>(wcslen(str1)), str2, static_cast<int>(wcslen(str2)));
25+
26+
//test to check that expected value passed is correct
27+
REQUIRE(compareStringResult == expected);
28+
29+
//test to check that the result from call to LogicalStringCompareImpl is the expected value
30+
REQUIRE(res == expected);
31+
}
32+
33+
void TestNullCharacters(const WCHAR* str1, int str1size, const WCHAR* str2, int str2size, int expected)
34+
{
35+
REQUIRE(g_testHooksLoaded);
36+
37+
// there are two tests, one to validate the expected value and validate the result of the call
38+
int compareStringResult = CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE | SORT_DIGITSASNUMBERS, str1, str1size, str2, str2size, NULL, NULL, 0);
39+
CHECK(compareStringResult != 0);
40+
compareStringResult = compareStringResult - CSTR_EQUAL;
41+
42+
int res = g_testHooks.pfLogicalCompareStringImpl(str1, str1size, str2, str2size);
2543

2644
//test to check that expected value passed is correct
2745
REQUIRE(compareStringResult == expected);
@@ -88,4 +106,10 @@ namespace UnicodeTextTest
88106
Test(_u("20sTRing"), _u("st2ring"), -1);
89107
Test(_u("st3rING"), _u("st2riNG"), 1);
90108
}
109+
110+
TEST_CASE("LogicalCompareString_EmbeddedNullCharacters", "[UnicodeText]")
111+
{
112+
TestNullCharacters(_u("\0\0ab\0\0c123def\0\0"), 15, _u("abc123def"), 9, 0);
113+
}
114+
91115
}

lib/Runtime/Library/JavascriptString.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//-------------------------------------------------------------------------------------------------------
1+
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
33
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
44
//-------------------------------------------------------------------------------------------------------
@@ -1296,6 +1296,8 @@ namespace Js
12961296

12971297
Var JavascriptString::EntryLocaleCompare(RecyclableObject* function, CallInfo callInfo, ...)
12981298
{
1299+
using namespace PlatformAgnostic;
1300+
12991301
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
13001302

13011303
ARGUMENTS(args, callInfo);
@@ -1371,25 +1373,18 @@ namespace Js
13711373
const char16* pThatStr = pThat->GetString();
13721374
int thatStrCount = pThat->GetLength();
13731375

1374-
// xplat-todo: doing a locale-insensitive compare here
1375-
// but need to move locale-specific string comparison to
1376-
// platform agnostic interface
1377-
#ifdef ENABLE_GLOBALIZATION
1378-
LCID lcid = GetUserDefaultLCID();
1379-
int result = CompareStringW(lcid, NULL, pThisStr, thisStrCount, pThatStr, thatStrCount );
1380-
if (result == 0)
1376+
int result = UnicodeText::LogicalStringCompare(pThisStr, thisStrCount, pThatStr, thatStrCount);
1377+
1378+
// LogicalStringCompare will return -2 if CompareStringEx fails.
1379+
if (result == -2)
13811380
{
13821381
// TODO there is no spec on the error thrown here.
13831382
// When the support for HR errors is implemented replace this with the same error reported by v5.8
13841383
JavascriptError::ThrowRangeError(function->GetScriptContext(),
13851384
VBSERR_InternalError /* TODO-ERROR: _u("Failed compare operation")*/ );
13861385
}
1387-
return JavascriptNumber::ToVar(result-2, scriptContext);
1388-
#else // !ENABLE_GLOBALIZATION
1389-
// no ICU / or external support for localization. Use c-lib
1390-
const int result = wcscmp(pThisStr, pThatStr);
1391-
return JavascriptNumber::ToVar(result > 0 ? 1 : result == 0 ? 0 : -1, scriptContext);
1392-
#endif
1386+
1387+
return JavascriptNumber::ToVar(result, scriptContext);
13931388
}
13941389

13951390

lib/Runtime/PlatformAgnostic/Platform/Common/UnicodeText.Common.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ namespace PlatformAgnostic
7272
return num;
7373
}
7474

75+
template <typename CharType>
76+
bool isNull(__in CharType c)
77+
{
78+
return c == '\0';
79+
}
80+
7581
///
7682
/// Implementation of CompareString(NORM_IGNORECASE | SORT_DIGITSASNUMBERS)
7783
/// This code is in the common library so that we can unit test it on Windows too
@@ -88,14 +94,18 @@ namespace PlatformAgnostic
8894
/// Otherwise, they're the same to continue scanning
8995
/// else they're both not numbers:
9096
/// Compare lexically till we find a number
97+
/// if either of the strings current character is a null character continue scanning
9198
/// The algorithm treats the characters in a case-insensitive manner
9299
///
93-
int LogicalStringCompareImpl(const char16* p1, const char16* p2)
100+
int LogicalStringCompareImpl(const char16* p1, int p1size, const char16* p2, int p2size)
94101
{
95102
Assert(p1 != nullptr);
96103
Assert(p2 != nullptr);
97104

98-
while (*p1 && *p2)
105+
const char16* str1End = p1 + p1size;
106+
const char16* str2End = p2 + p2size;
107+
108+
while (p1 < str1End && p2 < str2End)
99109
{
100110
bool isDigit1 = isDigit(*p1);
101111
bool isDigit2 = isDigit(*p2);
@@ -170,6 +180,16 @@ namespace PlatformAgnostic
170180
p1++; p2++;
171181
}
172182
}
183+
184+
while (isNull(*p1) && p1 < str1End)
185+
{
186+
p1++;
187+
}
188+
189+
while (isNull(*p2) && p2 < str2End)
190+
{
191+
p2++;
192+
}
173193
}
174194

175195
if (*p1 == *p2) return 0;

lib/Runtime/PlatformAgnostic/Platform/Common/UnicodeText.ICU.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,12 @@ namespace PlatformAgnostic
266266
return u_hasBinaryProperty(ch, UCHAR_ID_CONTINUE);
267267
}
268268

269-
int LogicalStringCompare(const char16* string1, const char16* string2)
269+
#ifndef _WIN32
270+
int LogicalStringCompare(const char16* string1, int str1size, const char16* string2, int str2size)
270271
{
271-
return PlatformAgnostic::UnicodeText::Internal::LogicalStringCompareImpl(string1, string2);
272+
return PlatformAgnostic::UnicodeText::Internal::LogicalStringCompareImpl(string1, str1size, string2, str2size);
272273
}
274+
#endif
273275

274276
bool IsExternalUnicodeLibraryAvailable()
275277
{

lib/Runtime/PlatformAgnostic/Platform/POSIX/UnicodeText.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ namespace PlatformAgnostic
123123
}
124124
}
125125

126-
int LogicalStringCompare(const char16* string1, const char16* string2)
126+
int LogicalStringCompare(const char16* string1, int str1size, const char16* string2, int str2size)
127127
{
128-
return PlatformAgnostic::UnicodeText::Internal::LogicalStringCompareImpl(string1, string2);
128+
return PlatformAgnostic::UnicodeText::Internal::LogicalStringCompareImpl(string1, str1size, string2, str2size);
129129
}
130130

131131
bool IsExternalUnicodeLibraryAvailable()

lib/Runtime/PlatformAgnostic/Platform/Windows/UnicodeText.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ namespace PlatformAgnostic
164164
return CharacterClassificationType::Invalid;
165165
}
166166

167+
int LogicalStringCompare(const char16* string1, int str1size, const char16* string2, int str2size)
168+
{
169+
// CompareStringEx called with these flags is equivalent to calling StrCmpLogicalW
170+
// and we have the added advantage of not having to link with shlwapi.lib just for one function
171+
int i = CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE | SORT_DIGITSASNUMBERS, string1, str1size, string2, str2size, NULL, NULL, 0);
172+
173+
return i - CSTR_EQUAL;
174+
}
175+
167176
// Everything below this has a preferred ICU implementation in Platform\Common\UnicodeText.ICU.cpp
168177
#ifndef HAS_ICU
169178
template <typename TRet, typename Fn>
@@ -426,15 +435,6 @@ namespace PlatformAgnostic
426435
#endif
427436
}, false);
428437
}
429-
430-
int LogicalStringCompare(const char16* string1, const char16* string2)
431-
{
432-
// CompareStringW called with these flags is equivalent to calling StrCmpLogicalW
433-
// and we have the added advantage of not having to link with shlwapi.lib just for one function
434-
int i = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_DIGITSASNUMBERS, string1, -1, string2, -1);
435-
436-
return i - CSTR_EQUAL;
437-
}
438438
#endif // HAS_ICU
439439
};
440440
};

lib/Runtime/PlatformAgnostic/UnicodeText.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,6 @@ namespace PlatformAgnostic
231231
// -1 - string1 is greater than string2
232232
// +1 - string1 is lesser than string2
233233
//
234-
int LogicalStringCompare(const char16* string1, const char16* string2);
234+
int LogicalStringCompare(const char16* string1, int str1size, const char16* string2, int str2size);
235235
};
236236
};

lib/Runtime/PlatformAgnostic/UnicodeTextInternal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ template charcount_t ChangeStringLinguisticCase<false, false>(const char16* sour
1818
namespace Internal
1919
{
2020

21-
int LogicalStringCompareImpl(const char16* p1, const char16* p2);
21+
int LogicalStringCompareImpl(const char16* p1, int p1size, const char16* p2, int p2size);
2222

2323
}; // namespace Internal
2424
}; // namespace UnicodeText

0 commit comments

Comments
 (0)