mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 20:37:31 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
b1db2370ed
37 changed files with 1562 additions and 1471 deletions
|
|
@ -141,35 +141,29 @@ template <typename CharT>
|
|||
static bool
|
||||
EvalStringMightBeJSON(const mozilla::Range<const CharT> chars)
|
||||
{
|
||||
// If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
|
||||
// Try the JSON parser first because it's much faster. If the eval string
|
||||
// isn't JSON, JSON parsing will probably fail quickly, so little time
|
||||
// will be lost.
|
||||
// If the eval string starts with '(' or '[' and ends with ')' or ']', it
|
||||
// may be JSON. Try the JSON parser first because it's much faster. If
|
||||
// the eval string isn't JSON, JSON parsing will probably fail quickly, so
|
||||
// little time will be lost.
|
||||
size_t length = chars.length();
|
||||
if (length > 2 &&
|
||||
((chars[0] == '[' && chars[length - 1] == ']') ||
|
||||
(chars[0] == '(' && chars[length - 1] == ')')))
|
||||
{
|
||||
// Remarkably, JavaScript syntax is not a superset of JSON syntax:
|
||||
// strings in JavaScript cannot contain the Unicode line and paragraph
|
||||
// terminator characters U+2028 and U+2029, but strings in JSON can.
|
||||
// Rather than force the JSON parser to handle this quirk when used by
|
||||
// eval, we simply don't use the JSON parser when either character
|
||||
// appears in the provided string. See bug 657367.
|
||||
if (sizeof(CharT) > 1) {
|
||||
for (RangedPtr<const CharT> cp = chars.begin() + 1, end = chars.end() - 1;
|
||||
cp < end;
|
||||
cp++)
|
||||
{
|
||||
char16_t c = *cp;
|
||||
if (c == 0x2028 || c == 0x2029)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (length < 2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// It used to be that strings in JavaScript forbid U+2028 LINE SEPARATOR
|
||||
// and U+2029 PARAGRAPH SEPARATOR, so something like
|
||||
//
|
||||
// eval("['" + "\u2028" + "']");
|
||||
//
|
||||
// i.e. an array containing a string with a line separator in it, *would*
|
||||
// be JSON but *would not* be valid JavaScript. Handing such a string to
|
||||
// the JSON parser would then fail to recognize a syntax error. As of
|
||||
// <https://tc39.github.io/proposal-json-superset/> JavaScript strings may
|
||||
// contain these two code points, so it's safe to JSON-parse eval strings
|
||||
// that contain them.
|
||||
|
||||
CharT first = chars[0], last = chars[length - 1];
|
||||
return (first == '[' && last == ']') ||
|
||||
(first == '(' && last == ')');
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
// tzdata version = 2019c
|
||||
// tzdata version = 2021a
|
||||
|
||||
#ifndef builtin_IntlTimeZoneData_h
|
||||
#define builtin_IntlTimeZoneData_h
|
||||
|
|
@ -22,6 +22,7 @@ const char* const ianaZonesTreatedAsLinksByICU[] = {
|
|||
"America/Ensenada", // America/Tijuana [backzone]
|
||||
"America/Indiana/Indianapolis", // America/Indianapolis [northamerica]
|
||||
"America/Kentucky/Louisville", // America/Louisville [northamerica]
|
||||
"America/Nuuk", // America/Godthab [europe]
|
||||
"America/Rosario", // America/Cordoba [backzone]
|
||||
"Asia/Chongqing", // Asia/Shanghai [backzone]
|
||||
"Asia/Harbin", // Asia/Shanghai [backzone]
|
||||
|
|
@ -56,6 +57,7 @@ const LinkAndTarget ianaLinksCanonicalizedDifferentlyByICU[] = {
|
|||
{ "America/Catamarca", "America/Argentina/Catamarca" }, // America/Catamarca [backward]
|
||||
{ "America/Cordoba", "America/Argentina/Cordoba" }, // America/Cordoba [backward]
|
||||
{ "America/Fort_Wayne", "America/Indiana/Indianapolis" }, // America/Indianapolis [backward]
|
||||
{ "America/Godthab", "America/Nuuk" }, // America/Godthab [backward]
|
||||
{ "America/Indianapolis", "America/Indiana/Indianapolis" }, // America/Indianapolis [backward]
|
||||
{ "America/Jujuy", "America/Argentina/Jujuy" }, // America/Jujuy [backward]
|
||||
{ "America/Kralendijk", "America/Curacao" }, // America/Kralendijk [southamerica]
|
||||
|
|
|
|||
|
|
@ -603,6 +603,10 @@ TokenStream::TokenBuf::findEOLMax(size_t start, size_t max)
|
|||
if (n >= max)
|
||||
break;
|
||||
n++;
|
||||
|
||||
// This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in
|
||||
// string and template literals. These code points do affect line and
|
||||
// column coordinates, even as they encode their literal values.
|
||||
if (TokenBuf::isRawEOLChar(*p++))
|
||||
break;
|
||||
}
|
||||
|
|
@ -2129,8 +2133,9 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
|
|||
}
|
||||
break;
|
||||
}
|
||||
} else if (TokenBuf::isRawEOLChar(c)) {
|
||||
} else if (c == '\r' || c == '\n') {
|
||||
if (!parsingTemplate) {
|
||||
// String literals don't allow ASCII line breaks.
|
||||
ungetCharIgnoreEOL(c);
|
||||
error(JSMSG_UNTERMINATED_STRING);
|
||||
return false;
|
||||
|
|
@ -2138,10 +2143,18 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
|
|||
if (c == '\r') {
|
||||
c = '\n';
|
||||
if (userbuf.peekRawChar() == '\n')
|
||||
// Treat CRLF as a single line break.
|
||||
skipCharsIgnoreEOL(1);
|
||||
}
|
||||
updateLineInfoForEOL();
|
||||
updateFlagsForEOL();
|
||||
} else if (c == LINE_SEPARATOR || c == PARA_SEPARATOR) {
|
||||
// U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR encode
|
||||
// their literal values in template literals and (as of the
|
||||
// JSON superset proposal) string literals, but they still count
|
||||
// as line terminators when computing line/column coordinates.
|
||||
updateLineInfoForEOL();
|
||||
updateFlagsForEOL();
|
||||
} else if (parsingTemplate && c == '$') {
|
||||
if ((nc = getCharIgnoreEOL()) == '{')
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -55,13 +55,10 @@ function testEvalHackNotJSON() {
|
|||
arr = eval("[]; var z; [1, 2, 3, \"abc\u1200\"]");
|
||||
assertEq(JSON.stringify(arr), '[1,2,3,"abc\u1200"]');
|
||||
|
||||
try {
|
||||
eval("[1, 2, 3, \"abc\u2028\"]");
|
||||
throw new Error("U+2028 shouldn't eval");
|
||||
} catch (e) {
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"should have thrown a SyntaxError, instead got " + e);
|
||||
}
|
||||
// JSON superset
|
||||
var arr = eval("[1, 2, 3, \"abc\u2028\"]");
|
||||
assertEq(arr.length, 4);
|
||||
assertEq(arr[3], "abc\u2028");
|
||||
}
|
||||
testEvalHackNotJSON();
|
||||
|
||||
|
|
|
|||
226
js/src/json.cpp
226
js/src/json.cpp
|
|
@ -39,78 +39,122 @@ const Class js::JSONClass = {
|
|||
JSCLASS_HAS_CACHED_PROTO(JSProto_JSON)
|
||||
};
|
||||
|
||||
static inline bool
|
||||
IsQuoteSpecialCharacter(char16_t c)
|
||||
/* ES5 15.12.3 Quote.
|
||||
* Requires that the destination has enough space allocated for src after escaping
|
||||
* (that is, `2 + 6 * (srcEnd - srcBegin)` characters).
|
||||
*/
|
||||
template <typename SrcCharT, typename DstCharT>
|
||||
static MOZ_ALWAYS_INLINE RangedPtr<DstCharT>
|
||||
InfallibleQuote(RangedPtr<const SrcCharT> srcBegin, RangedPtr<const SrcCharT> srcEnd, RangedPtr<DstCharT> dstPtr)
|
||||
{
|
||||
static_assert('\b' < ' ', "'\\b' must be treated as special below");
|
||||
static_assert('\f' < ' ', "'\\f' must be treated as special below");
|
||||
static_assert('\n' < ' ', "'\\n' must be treated as special below");
|
||||
static_assert('\r' < ' ', "'\\r' must be treated as special below");
|
||||
static_assert('\t' < ' ', "'\\t' must be treated as special below");
|
||||
|
||||
return c == '"' || c == '\\' || c < ' ';
|
||||
}
|
||||
|
||||
/* ES5 15.12.3 Quote. */
|
||||
template <typename CharT>
|
||||
static bool
|
||||
Quote(StringBuffer& sb, JSLinearString* str)
|
||||
{
|
||||
size_t len = str->length();
|
||||
// Maps characters < 256 to the value that must follow the '\\' in the quoted string.
|
||||
// Entries with 'u' are handled as \\u00xy, and entries with 0 are not escaped in any way.
|
||||
// Characters >= 256 are all assumed to be unescaped.
|
||||
static const Latin1Char escapeLookup[256] = {
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't',
|
||||
'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 0, 0, '\"', 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, '\\', // rest are all zeros
|
||||
};
|
||||
|
||||
/* Step 1. */
|
||||
if (!sb.append('"'))
|
||||
return false;
|
||||
*dstPtr++ = '"';
|
||||
|
||||
// XXX: This is a rather ugly in-line definition. Move it somewhere better?
|
||||
auto ToLowerHex = [](uint8_t u) {
|
||||
MOZ_ASSERT(u <= 0xF);
|
||||
return "0123456789abcdef"[u];
|
||||
};
|
||||
|
||||
/* Step 2. */
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
const RangedPtr<const CharT> buf(str->chars<CharT>(nogc), len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
/* Batch-append maximal character sequences containing no escapes. */
|
||||
size_t mark = i;
|
||||
do {
|
||||
if (IsQuoteSpecialCharacter(buf[i]))
|
||||
break;
|
||||
} while (++i < len);
|
||||
if (i > mark) {
|
||||
if (!sb.appendSubstring(str, mark, i - mark))
|
||||
return false;
|
||||
if (i == len)
|
||||
break;
|
||||
while (srcBegin != srcEnd) {
|
||||
const SrcCharT c = *srcBegin++;
|
||||
|
||||
// Handle the Latin-1 cases.
|
||||
if (MOZ_LIKELY(c < sizeof(escapeLookup))) {
|
||||
Latin1Char escaped = escapeLookup[c];
|
||||
|
||||
// Directly copy non-escaped code points.
|
||||
if (escaped == 0) {
|
||||
*dstPtr++ = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Escape the rest, elaborating Unicode escapes when needed.
|
||||
*dstPtr++ = '\\';
|
||||
*dstPtr++ = escaped;
|
||||
if (escaped == 'u') {
|
||||
*dstPtr++ = '0';
|
||||
*dstPtr++ = '0';
|
||||
|
||||
uint8_t x = c >> 4;
|
||||
MOZ_ASSERT(x < 10);
|
||||
*dstPtr++ = '0' + x;
|
||||
|
||||
*dstPtr++ = ToLowerHex(c & 0xF);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
char16_t c = buf[i];
|
||||
if (c == '"' || c == '\\') {
|
||||
if (!sb.append('\\') || !sb.append(c))
|
||||
return false;
|
||||
} else if (c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') {
|
||||
char16_t abbrev = (c == '\b')
|
||||
? 'b'
|
||||
: (c == '\f')
|
||||
? 'f'
|
||||
: (c == '\n')
|
||||
? 'n'
|
||||
: (c == '\r')
|
||||
? 'r'
|
||||
: 't';
|
||||
if (!sb.append('\\') || !sb.append(abbrev))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(c < ' ');
|
||||
if (!sb.append("\\u00"))
|
||||
return false;
|
||||
MOZ_ASSERT((c >> 4) < 10);
|
||||
uint8_t x = c >> 4, y = c % 16;
|
||||
if (!sb.append(Latin1Char('0' + x)) ||
|
||||
!sb.append(Latin1Char(y < 10 ? '0' + y : 'a' + (y - 10))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Non-ASCII non-surrogates are directly copied.
|
||||
if (!unicode::IsSurrogate(c)) {
|
||||
*dstPtr++ = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// So too for complete surrogate pairs.
|
||||
if (MOZ_LIKELY(unicode::IsLeadSurrogate(c) &&
|
||||
srcBegin < srcEnd &&
|
||||
unicode::IsTrailSurrogate(*srcBegin)))
|
||||
{
|
||||
*dstPtr++ = c;
|
||||
*dstPtr++ = *srcBegin++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// But lone surrogates are Unicode-escaped.
|
||||
char32_t as32 = char32_t(c);
|
||||
*dstPtr++ = '\\';
|
||||
*dstPtr++ = 'u';
|
||||
*dstPtr++ = ToLowerHex(as32 >> 12);
|
||||
*dstPtr++ = ToLowerHex((as32 >> 8) & 0xF);
|
||||
*dstPtr++ = ToLowerHex((as32 >> 4) & 0xF);
|
||||
*dstPtr++ = ToLowerHex(as32 & 0xF);
|
||||
}
|
||||
|
||||
/* Steps 3-4. */
|
||||
return sb.append('"');
|
||||
*dstPtr++ = '"';
|
||||
return dstPtr;
|
||||
}
|
||||
|
||||
template <typename SrcCharT, typename CharVectorT>
|
||||
static bool
|
||||
Quote(CharVectorT& sb, JSLinearString* str)
|
||||
{
|
||||
// We resize the backing buffer to the maximum size we could possibly need,
|
||||
// write the escaped string into it, and shrink it back to the size we ended
|
||||
// up needing.
|
||||
size_t len = str->length();
|
||||
size_t sbInitialLen = sb.length();
|
||||
if (!sb.growByUninitialized(len * 6 + 2))
|
||||
return false;
|
||||
|
||||
typedef typename CharVectorT::ElementType DstCharT;
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
RangedPtr<const SrcCharT> srcBegin{str->chars<SrcCharT>(nogc), len};
|
||||
RangedPtr<DstCharT> dstBegin{sb.begin(), sb.begin(), sb.end()};
|
||||
RangedPtr<DstCharT> dstEnd = InfallibleQuote(srcBegin, srcBegin + len, dstBegin + sbInitialLen);
|
||||
size_t newSize = dstEnd - dstBegin;
|
||||
sb.shrinkTo(newSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -120,14 +164,23 @@ Quote(JSContext* cx, StringBuffer& sb, JSString* str)
|
|||
if (!linear)
|
||||
return false;
|
||||
|
||||
return linear->hasLatin1Chars()
|
||||
? Quote<Latin1Char>(sb, linear)
|
||||
: Quote<char16_t>(sb, linear);
|
||||
// Check if either has non-latin1 before calling ensure, so that the buffer's
|
||||
// hasEnsured flag is set if the converstion to twoByte was automatic.
|
||||
if (!sb.isUnderlyingBufferLatin1() || linear->hasTwoByteChars()) {
|
||||
if (!sb.ensureTwoByteChars())
|
||||
return false;
|
||||
}
|
||||
if (linear->hasTwoByteChars())
|
||||
return Quote<char16_t>(sb.rawTwoByteBuffer(), linear);
|
||||
|
||||
return sb.isUnderlyingBufferLatin1()
|
||||
? Quote<Latin1Char>(sb.latin1Chars(), linear)
|
||||
: Quote<Latin1Char>(sb.rawTwoByteBuffer(), linear);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using ObjectSet = GCHashSet<JSObject*, MovableCellHasher<JSObject*>, SystemAllocPolicy>;
|
||||
using ObjectVector = GCVector<JSObject*, 8>;
|
||||
|
||||
class StringifyContext
|
||||
{
|
||||
|
|
@ -138,7 +191,7 @@ class StringifyContext
|
|||
: sb(sb),
|
||||
gap(gap),
|
||||
replacer(cx, replacer),
|
||||
stack(cx),
|
||||
stack(cx, ObjectVector(cx)),
|
||||
propertyList(propertyList),
|
||||
depth(0),
|
||||
maybeSafely(maybeSafely)
|
||||
|
|
@ -147,14 +200,10 @@ class StringifyContext
|
|||
MOZ_ASSERT_IF(maybeSafely, gap.empty());
|
||||
}
|
||||
|
||||
bool init() {
|
||||
return stack.init(8);
|
||||
}
|
||||
|
||||
StringBuffer& sb;
|
||||
const StringBuffer& gap;
|
||||
RootedObject replacer;
|
||||
Rooted<ObjectSet> stack;
|
||||
Rooted<ObjectVector> stack;
|
||||
const AutoIdVector& propertyList;
|
||||
uint32_t depth;
|
||||
bool maybeSafely;
|
||||
|
|
@ -302,29 +351,34 @@ class CycleDetector
|
|||
{
|
||||
public:
|
||||
CycleDetector(StringifyContext* scx, HandleObject obj)
|
||||
: stack(&scx->stack), obj_(obj) {
|
||||
}
|
||||
: stack_(&scx->stack)
|
||||
, obj_(obj)
|
||||
, appended_(false)
|
||||
{}
|
||||
|
||||
bool foundCycle(JSContext* cx) {
|
||||
auto addPtr = stack.lookupForAdd(obj_);
|
||||
if (addPtr) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_JSON_CYCLIC_VALUE);
|
||||
return false;
|
||||
MOZ_ALWAYS_INLINE bool foundCycle(JSContext* cx) {
|
||||
JSObject* obj = obj_;
|
||||
for (JSObject* obj2 : stack_) {
|
||||
if (MOZ_UNLIKELY(obj == obj2)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_JSON_CYCLIC_VALUE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!stack.add(addPtr, obj_)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
appended_ = stack_.append(obj);
|
||||
return appended_;
|
||||
}
|
||||
|
||||
~CycleDetector() {
|
||||
stack.remove(obj_);
|
||||
if (MOZ_LIKELY(appended_)) {
|
||||
MOZ_ASSERT(stack_.back() == obj_);
|
||||
stack_.popBack();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MutableHandle<ObjectSet> stack;
|
||||
MutableHandle<ObjectVector> stack_;
|
||||
HandleObject obj_;
|
||||
bool appended_;
|
||||
};
|
||||
|
||||
/* ES5 15.12.3 JO. */
|
||||
|
|
@ -747,8 +801,6 @@ js::Stringify(JSContext* cx, MutableHandleValue vp, JSObject* replacer_, const V
|
|||
/* Step 12. */
|
||||
StringifyContext scx(cx, sb, gap, replacer, propertyList,
|
||||
stringifyBehavior == StringifyBehavior::RestrictedSafe);
|
||||
if (!scx.init())
|
||||
return false;
|
||||
if (!PreprocessValue(cx, wrapper, HandleId(emptyId), vp, &scx))
|
||||
return false;
|
||||
if (IsFilteredValue(vp))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
// tzdata version = 2019c
|
||||
// tzdata version = 2021a
|
||||
|
||||
const tzMapper = [
|
||||
x => x,
|
||||
|
|
@ -17,6 +17,7 @@ const links = {
|
|||
"America/Catamarca": "America/Argentina/Catamarca",
|
||||
"America/Cordoba": "America/Argentina/Cordoba",
|
||||
"America/Fort_Wayne": "America/Indiana/Indianapolis",
|
||||
"America/Godthab": "America/Nuuk",
|
||||
"America/Indianapolis": "America/Indiana/Indianapolis",
|
||||
"America/Jujuy": "America/Argentina/Jujuy",
|
||||
"America/Knox_IN": "America/Indiana/Knox",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
// tzdata version = 2019c
|
||||
// tzdata version = 2021a
|
||||
|
||||
const tzMapper = [
|
||||
x => x,
|
||||
|
|
@ -79,6 +79,7 @@ const links = {
|
|||
"Asia/Vientiane": "Asia/Vientiane",
|
||||
"Atlantic/Jan_Mayen": "Atlantic/Jan_Mayen",
|
||||
"Atlantic/St_Helena": "Atlantic/St_Helena",
|
||||
"Australia/Currie": "Australia/Currie",
|
||||
"Europe/Belfast": "Europe/Belfast",
|
||||
"Europe/Guernsey": "Europe/Guernsey",
|
||||
"Europe/Isle_of_Man": "Europe/Isle_of_Man",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
// tzdata version = 2019c
|
||||
// tzdata version = 2021a
|
||||
|
||||
const tzMapper = [
|
||||
x => x,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
// tzdata version = 2019c
|
||||
// tzdata version = 2021a
|
||||
|
||||
const tzMapper = [
|
||||
x => x,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ assertStringify({'mmm\\mmm':"hmm"}, '{"mmm\\\\mmm":"hmm"}');
|
|||
assertStringify({'mmm\\mmm\\mmm':"hmm"}, '{"mmm\\\\mmm\\\\mmm":"hmm"}');
|
||||
assertStringify({"mm\u000bmm":"hmm"}, '{"mm\\u000bmm":"hmm"}');
|
||||
assertStringify({"mm\u0000mm":"hmm"}, '{"mm\\u0000mm":"hmm"}');
|
||||
assertStringify({"\u0000\u000b":""}, '{"\\u0000\\u000b":""}');
|
||||
assertStringify({"\u000b\ufdfd":"hmm"}, '{"\\u000b\ufdfd":"hmm"}');
|
||||
assertStringify({"\u000b\ufdfd":"h\xfc\ufdfdm"}, '{"\\u000b\ufdfd":"h\xfc\ufdfdm"}');
|
||||
|
||||
var x = {"free":"variable"};
|
||||
assertStringify(x, '{"free":"variable"}');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 657367;
|
||||
var summary = "eval must not parse strings containing U+2028 or U+2029";
|
||||
var summary =
|
||||
"eval via the JSON parser should parse strings containing U+2028/U+2029 " +
|
||||
"(as of <https://tc39.github.io/proposal-json-superset/>, that is)";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
|
|
@ -11,59 +13,8 @@ print(BUGNUMBER + ": " + summary);
|
|||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
function esc(s)
|
||||
{
|
||||
return s.split("").map(function(v)
|
||||
{
|
||||
var code =
|
||||
("000" + v.charCodeAt(0).toString(16)).slice(-4);
|
||||
return "\\u" + code;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = eval('"\u2028"');
|
||||
throw new Error("\"\\u2028\" didn't throw, returned " + esc(r));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"U+2028 is not a valid string character");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = eval('("\u2028")');
|
||||
throw new Error("(\"\\u2028\") didn't throw, returned " + esc(r));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"U+2028 is not a valid string character");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = eval('"\u2029"');
|
||||
throw new Error("\"\\u2029\" didn't throw, returned " + esc(r));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"U+2029 is not a valid string character");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var r = eval('("\u2029")');
|
||||
throw new Error("(\"\\u2029\") didn't throw, returned " + esc(r));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof SyntaxError, true,
|
||||
"U+2029 is not a valid string character");
|
||||
}
|
||||
assertEq(eval('("\u2028")'), "\u2028");
|
||||
assertEq(eval('("\u2029")'), "\u2029");
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -61,12 +61,8 @@ class StringBuffer
|
|||
MOZ_ALWAYS_INLINE bool isLatin1() const { return cb.constructed<Latin1CharBuffer>(); }
|
||||
MOZ_ALWAYS_INLINE bool isTwoByte() const { return !isLatin1(); }
|
||||
|
||||
MOZ_ALWAYS_INLINE Latin1CharBuffer& latin1Chars() { return cb.ref<Latin1CharBuffer>(); }
|
||||
MOZ_ALWAYS_INLINE TwoByteCharBuffer& twoByteChars() { return cb.ref<TwoByteCharBuffer>(); }
|
||||
|
||||
MOZ_ALWAYS_INLINE const Latin1CharBuffer& latin1Chars() const {
|
||||
return cb.ref<Latin1CharBuffer>();
|
||||
}
|
||||
MOZ_ALWAYS_INLINE const TwoByteCharBuffer& twoByteChars() const {
|
||||
return cb.ref<TwoByteCharBuffer>();
|
||||
}
|
||||
|
|
@ -84,6 +80,12 @@ class StringBuffer
|
|||
cb.construct<Latin1CharBuffer>(cx);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE Latin1CharBuffer& latin1Chars() { return cb.ref<Latin1CharBuffer>(); }
|
||||
|
||||
MOZ_ALWAYS_INLINE const Latin1CharBuffer& latin1Chars() const {
|
||||
return cb.ref<Latin1CharBuffer>();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (isLatin1())
|
||||
latin1Chars().clear();
|
||||
|
|
@ -134,6 +136,11 @@ class StringBuffer
|
|||
return append(Latin1Char(c));
|
||||
}
|
||||
|
||||
TwoByteCharBuffer& rawTwoByteBuffer() {
|
||||
MOZ_ASSERT(hasEnsuredTwoByteChars_);
|
||||
return twoByteChars();
|
||||
}
|
||||
|
||||
inline MOZ_MUST_USE bool append(const char16_t* begin, const char16_t* end);
|
||||
|
||||
MOZ_MUST_USE bool append(const char16_t* chars, size_t len) {
|
||||
|
|
|
|||
|
|
@ -466,6 +466,19 @@ IsTrailSurrogate(uint32_t codePoint)
|
|||
return codePoint >= TrailSurrogateMin && codePoint <= TrailSurrogateMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given value is a UTF-16 surrogate.
|
||||
*
|
||||
* This function is intended for use in contexts where 32-bit values may need
|
||||
* to be tested to see if they reside in the surrogate range, so it doesn't
|
||||
* just take char16_t.
|
||||
*/
|
||||
inline bool
|
||||
IsSurrogate(uint32_t codePoint)
|
||||
{
|
||||
return LeadSurrogateMin <= codePoint && codePoint <= TrailSurrogateMax;
|
||||
}
|
||||
|
||||
inline char16_t
|
||||
LeadSurrogate(uint32_t codePoint)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue