1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "js/CharacterEncoding.h" // JS::FindSmallestEncoding, JS::SmallestEncoding
6 #include "js/GCAPI.h" // JSExternalStringCallbacks, JS_NewExternalUCString, JS_NewExternalStringLatin1, JS_NewMaybeExternalStringUTF8, JS::AutoRequireNoGC
7 #include "js/String.h" // JS::IsExternalStringLatin1
8 #include "jsapi-tests/tests.h"
11 static const char16_t arr
[] = u
"hi, don't delete me";
12 static const size_t arrlen
= js_strlen(arr
);
14 static const char arr2
[] = "hi, don't delete me";
15 static const size_t arrlen2
= js_strlen(arr2
);
17 static int finalized1
= 0;
18 static int finalized2
= 0;
19 static int finalized3
= 0;
20 static int finalized4
= 0;
22 struct ExternalStringCallbacks
: public JSExternalStringCallbacks
{
23 int* finalizedCount
= nullptr;
24 bool isTwoBytes
= false;
26 explicit ExternalStringCallbacks(int* finalizedCount
, bool isTwoBytes
)
27 : finalizedCount(finalizedCount
), isTwoBytes(isTwoBytes
) {}
29 void finalize(JS::Latin1Char
* chars
) const override
{
30 MOZ_ASSERT(!isTwoBytes
);
31 MOZ_ASSERT(chars
== (JS::Latin1Char
*)arr2
);
35 void finalize(char16_t
* chars
) const override
{
36 MOZ_ASSERT(isTwoBytes
);
37 MOZ_ASSERT(chars
== arr
);
41 size_t sizeOfBuffer(const JS::Latin1Char
* chars
,
42 mozilla::MallocSizeOf mallocSizeOf
) const override
{
43 MOZ_CRASH("Unexpected call");
46 size_t sizeOfBuffer(const char16_t
* chars
,
47 mozilla::MallocSizeOf mallocSizeOf
) const override
{
48 MOZ_CRASH("Unexpected call");
52 static const ExternalStringCallbacks
callbacks1(&finalized1
, true);
53 static const ExternalStringCallbacks
callbacks2(&finalized2
, true);
54 static const ExternalStringCallbacks
callbacks3(&finalized3
, false);
55 static const ExternalStringCallbacks
callbacks4(&finalized4
, false);
57 BEGIN_TEST(testExternalStrings
) {
58 const unsigned N
= 1000;
60 for (unsigned i
= 0; i
< N
; ++i
) {
61 CHECK(JS_NewExternalUCString(cx
, arr
, arrlen
, &callbacks1
));
62 CHECK(JS_NewExternalUCString(cx
, arr
, arrlen
, &callbacks2
));
63 CHECK(JS_NewExternalStringLatin1(cx
, (JS::Latin1Char
*)arr2
, arrlen2
,
65 CHECK(JS_NewExternalStringLatin1(cx
, (JS::Latin1Char
*)arr2
, arrlen2
,
71 CHECK((N
- finalized1
) == 0);
72 CHECK((N
- finalized2
) == 0);
73 CHECK((N
- finalized3
) == 0);
74 CHECK((N
- finalized4
) == 0);
78 END_TEST(testExternalStrings
)
80 struct SimpleExternalStringCallbacks
: public JSExternalStringCallbacks
{
81 SimpleExternalStringCallbacks() = default;
83 void finalize(JS::Latin1Char
* chars
) const override
{}
85 void finalize(char16_t
* chars
) const override
{
86 MOZ_CRASH("Unexpected call");
89 size_t sizeOfBuffer(const JS::Latin1Char
* chars
,
90 mozilla::MallocSizeOf mallocSizeOf
) const override
{
91 MOZ_CRASH("Unexpected call");
94 size_t sizeOfBuffer(const char16_t
* chars
,
95 mozilla::MallocSizeOf mallocSizeOf
) const override
{
96 MOZ_CRASH("Unexpected call");
100 static const SimpleExternalStringCallbacks simpleCallback
;
102 static const char utf8ASCII
[] = "hi, I'm UTF-8 string";
103 static const size_t utf8ASCIILen
= js_strlen(utf8ASCII
);
105 static const char utf8Latin1
[] = "hi, I'm \xC3\x9CTF-8 string";
106 static const size_t utf8Latin1Len
= js_strlen(utf8Latin1
);
108 static const char latin1
[] = "hi, I'm \xDCTF-8 string";
109 static const size_t latin1Len
= js_strlen(latin1
);
111 static const char utf8UTF16
[] = "hi, I'm UTF-\xEF\xBC\x98 string";
112 static const size_t utf8UTF16Len
= js_strlen(utf8UTF16
);
114 static const char16_t utf16
[] = u
"hi, I'm UTF-8 string";
115 static const size_t utf16Len
= js_strlen(utf16
);
117 BEGIN_TEST(testExternalStringsUTF8
) {
118 // UTF-8 chars with ASCII range content should be converted into external
121 JS::UTF8Chars
utf8Chars(utf8ASCII
, utf8ASCIILen
);
122 CHECK(JS::FindSmallestEncoding(utf8Chars
) == JS::SmallestEncoding::ASCII
);
123 bool allocatedExternal
= false;
124 JS::Rooted
<JSString
*> str(
125 cx
, JS_NewMaybeExternalStringUTF8(cx
, utf8Chars
, &simpleCallback
,
126 &allocatedExternal
));
128 CHECK(allocatedExternal
);
130 const JSExternalStringCallbacks
* callbacks
= nullptr;
131 const JS::Latin1Char
* chars
= nullptr;
132 CHECK(JS::IsExternalStringLatin1(str
, &callbacks
, &chars
));
133 CHECK(callbacks
== &simpleCallback
);
134 CHECK((void*)chars
== (void*)utf8ASCII
);
136 CHECK(StringHasLatin1Chars(str
));
138 JS::AutoAssertNoGC
nogc(cx
);
140 chars
= JS_GetLatin1StringCharsAndLength(cx
, nogc
, str
, &length
);
141 CHECK(length
== utf8ASCIILen
);
142 CHECK(memcmp(chars
, utf8ASCII
, length
) == 0);
145 // UTF-8 chars with latin-1 range content shouldn't be converted into external
146 // string, but regular latin-1 string.
148 JS::UTF8Chars
utf8Chars(utf8Latin1
, utf8Latin1Len
);
149 CHECK(JS::FindSmallestEncoding(utf8Chars
) == JS::SmallestEncoding::Latin1
);
150 bool allocatedExternal
= false;
151 JS::Rooted
<JSString
*> str(
152 cx
, JS_NewMaybeExternalStringUTF8(cx
, utf8Chars
, &simpleCallback
,
153 &allocatedExternal
));
155 CHECK(!allocatedExternal
);
157 const JSExternalStringCallbacks
* callbacks
= nullptr;
158 const JS::Latin1Char
* chars
= nullptr;
159 CHECK(!JS::IsExternalStringLatin1(str
, &callbacks
, &chars
));
163 CHECK(StringHasLatin1Chars(str
));
165 JS::AutoAssertNoGC
nogc(cx
);
167 chars
= JS_GetLatin1StringCharsAndLength(cx
, nogc
, str
, &length
);
168 CHECK(length
== latin1Len
);
169 CHECK(memcmp(chars
, latin1
, length
) == 0);
172 // UTF-8 chars with UTF-16 range content shouldn't be converted into external
173 // string, but regular TwoBytes string.
175 JS::UTF8Chars
utf8Chars(utf8UTF16
, utf8UTF16Len
);
176 CHECK(JS::FindSmallestEncoding(utf8Chars
) == JS::SmallestEncoding::UTF16
);
177 bool allocatedExternal
= false;
178 JS::Rooted
<JSString
*> str(
179 cx
, JS_NewMaybeExternalStringUTF8(cx
, utf8Chars
, &simpleCallback
,
180 &allocatedExternal
));
182 CHECK(!allocatedExternal
);
184 const JSExternalStringCallbacks
* callbacks
= nullptr;
185 const JS::Latin1Char
* chars
= nullptr;
186 CHECK(!JS::IsExternalStringLatin1(str
, &callbacks
, &chars
));
190 CHECK(!StringHasLatin1Chars(str
));
192 JS::AutoAssertNoGC
nogc(cx
);
194 const char16_t
* chars16
= nullptr;
195 chars16
= JS_GetTwoByteStringCharsAndLength(cx
, nogc
, str
, &length
);
196 CHECK(length
== utf16Len
);
197 CHECK(memcmp(chars16
, utf16
, length
* sizeof(char16_t
)) == 0);
202 END_TEST(testExternalStringsUTF8
)