mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 666448: Remove 2nd argument to escape() for ECMA/Test262 compliance (r=jwalden)
This commit is contained in:
parent
7d4f970e4a
commit
a39ec83520
1
js/src/jit-test/tests/bug666448.js
Normal file
1
js/src/jit-test/tests/bug666448.js
Normal file
@ -0,0 +1 @@
|
||||
assertEq(["a"].map(escape)[0], ["a"].map(function(s) {return escape(s);})[0]);
|
@ -75,8 +75,12 @@
|
||||
*
|
||||
* "Rhino is not a member of the Monkey family"
|
||||
*
|
||||
* Before adding a new MSG_DEF at the end, look for JSMSG_UNUSED<n> free
|
||||
* index placeholders in the middle of the list.
|
||||
* When removing MSG_DEFs, convert them to JSMSG_UNUSED<n> placeholders:
|
||||
*
|
||||
* MSG_DEF(JSMSG_UNUSED7, 7, 0, JSEXN_NONE, "")
|
||||
*
|
||||
* Before adding a new MSG_DEF at the end, look for existing JSMSG_UNUSED<n>
|
||||
* free index placeholders in the middle of the list.
|
||||
*/
|
||||
|
||||
MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "<Error #0 is reserved>")
|
||||
@ -140,7 +144,7 @@ MSG_DEF(JSMSG_BAD_CLASS_RANGE, 57, 0, JSEXN_SYNTAXERR, "invalid range in
|
||||
MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
|
||||
MSG_DEF(JSMSG_NO_INPUT, 59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
|
||||
MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_ERR, "can't open {0}: {1}")
|
||||
MSG_DEF(JSMSG_BAD_STRING_MASK, 61, 1, JSEXN_ERR, "invalid string escape mask {0}")
|
||||
MSG_DEF(JSMSG_UNUSED61, 61, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
|
||||
MSG_DEF(JSMSG_END_OF_DATA, 63, 0, JSEXN_INTERNALERR, "unexpected end of data")
|
||||
MSG_DEF(JSMSG_SEEK_BEYOND_START, 64, 0, JSEXN_INTERNALERR, "illegal seek beyond start")
|
||||
|
122
js/src/jsstr.cpp
122
js/src/jsstr.cpp
@ -148,68 +148,17 @@ static uint32
|
||||
Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
|
||||
|
||||
/*
|
||||
* Contributions from the String class to the set of methods defined for the
|
||||
* global object. escape and unescape used to be defined in the Mocha library,
|
||||
* but as ECMA decided to spec them, they've been moved to the core engine
|
||||
* and made ECMA-compliant. (Incomplete escapes are interpreted as literal
|
||||
* characters by unescape.)
|
||||
* Global string methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stuff to emulate the old libmocha escape, which took a second argument
|
||||
* giving the type of escape to perform. Retained for compatibility, and
|
||||
* copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
|
||||
*/
|
||||
|
||||
#define URL_XALPHAS ((uint8) 1)
|
||||
#define URL_XPALPHAS ((uint8) 2)
|
||||
#define URL_PATH ((uint8) 4)
|
||||
|
||||
static const uint8 urlCharType[256] =
|
||||
/* Bit 0 xalpha -- the alphas
|
||||
* Bit 1 xpalpha -- as xalpha but
|
||||
* converts spaces to plus and plus to %20
|
||||
* Bit 2 ... path -- as xalphas but doesn't escape '/'
|
||||
*/
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
|
||||
0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
|
||||
7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
|
||||
7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
|
||||
0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
|
||||
7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
|
||||
0, };
|
||||
|
||||
/* This matches the ECMA escape set when mask is 7 (default.) */
|
||||
|
||||
#define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
|
||||
|
||||
/* See ECMA-262 Edition 3 B.2.1 */
|
||||
JSBool
|
||||
js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
|
||||
/* ES5 B.2.1 */
|
||||
static JSBool
|
||||
str_escape(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
jsint mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
|
||||
if (argc > 1) {
|
||||
double d;
|
||||
if (!ValueToNumber(cx, vp[3], &d))
|
||||
return JS_FALSE;
|
||||
if (!JSDOUBLE_IS_FINITE(d) ||
|
||||
(mask = (jsint)d) != d ||
|
||||
mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
|
||||
{
|
||||
char numBuf[12];
|
||||
JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_STRING_MASK, numBuf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
@ -217,19 +166,38 @@ js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
|
||||
size_t length = str->length();
|
||||
const jschar *chars = str->chars();
|
||||
|
||||
static const uint8 shouldPassThrough[256] = {
|
||||
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,1,1,0,1,1,1, /* !"#$%&'()*+,-./ */
|
||||
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 0123456789:;<=>? */
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* @ABCDEFGHIJKLMNO */
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* PQRSTUVWXYZ[\]^_ */
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* `abcdefghijklmno */
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* pqrstuvwxyz{\}~ DEL */
|
||||
};
|
||||
|
||||
/* In step 7, exactly 69 characters should pass through unencoded. */
|
||||
#ifdef DEBUG
|
||||
int count = 0;
|
||||
for (uint i = 0; i < sizeof(shouldPassThrough); i++) {
|
||||
if (shouldPassThrough[i]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
JS_ASSERT(count == 69);
|
||||
#endif
|
||||
|
||||
|
||||
/* Take a first pass and see how big the result string will need to be. */
|
||||
size_t newlength = length;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
jschar ch;
|
||||
if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
|
||||
jschar ch = chars[i];
|
||||
if (ch < 128 && shouldPassThrough[ch])
|
||||
continue;
|
||||
if (ch < 256) {
|
||||
if (mask == URL_XPALPHAS && ch == ' ')
|
||||
continue; /* The character will be encoded as '+' */
|
||||
newlength += 2; /* The character will be encoded as %XX */
|
||||
} else {
|
||||
newlength += 5; /* The character will be encoded as %uXXXX */
|
||||
}
|
||||
|
||||
/* The character will be encoded as %XX or %uXXXX. */
|
||||
newlength += (ch < 256) ? 2 : 5;
|
||||
|
||||
/*
|
||||
* This overflow test works because newlength is incremented by at
|
||||
@ -251,17 +219,13 @@ js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
|
||||
return JS_FALSE;
|
||||
size_t i, ni;
|
||||
for (i = 0, ni = 0; i < length; i++) {
|
||||
jschar ch;
|
||||
if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
|
||||
jschar ch = chars[i];
|
||||
if (ch < 128 && shouldPassThrough[ch]) {
|
||||
newchars[ni++] = ch;
|
||||
} else if (ch < 256) {
|
||||
if (mask == URL_XPALPHAS && ch == ' ') {
|
||||
newchars[ni++] = '+'; /* convert spaces to pluses */
|
||||
} else {
|
||||
newchars[ni++] = '%';
|
||||
newchars[ni++] = digits[ch >> 4];
|
||||
newchars[ni++] = digits[ch & 0xF];
|
||||
}
|
||||
newchars[ni++] = '%';
|
||||
newchars[ni++] = digits[ch >> 4];
|
||||
newchars[ni++] = digits[ch & 0xF];
|
||||
} else {
|
||||
newchars[ni++] = '%';
|
||||
newchars[ni++] = 'u';
|
||||
@ -279,18 +243,11 @@ js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
|
||||
cx->free_(newchars);
|
||||
return JS_FALSE;
|
||||
}
|
||||
rval->setString(retstr);
|
||||
vp->setString(retstr);
|
||||
return JS_TRUE;
|
||||
}
|
||||
#undef IS_OK
|
||||
|
||||
static JSBool
|
||||
str_escape(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
return js_str_escape(cx, argc, vp, vp);
|
||||
}
|
||||
|
||||
/* See ECMA-262 Edition 3 B.2.2 */
|
||||
/* ES5 B.2.2 */
|
||||
static JSBool
|
||||
str_unescape(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
@ -309,6 +266,7 @@ str_unescape(JSContext *cx, uintN argc, Value *vp)
|
||||
while (i < length) {
|
||||
jschar ch = chars[i++];
|
||||
if (ch == '%') {
|
||||
/* Incomplete escapes are interpreted as literal characters. */
|
||||
if (i + 1 < length &&
|
||||
JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
|
||||
{
|
||||
|
@ -486,10 +486,6 @@ DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/* Export a few natives and a helper to other files in SpiderMonkey. */
|
||||
extern JSBool
|
||||
js_str_escape(JSContext *cx, uintN argc, js::Value *argv, js::Value *rval);
|
||||
|
||||
/*
|
||||
* The String.prototype.replace fast-native entry point is exported for joined
|
||||
* function optimization in js{interp,tracer}.cpp.
|
||||
|
Loading…
Reference in New Issue
Block a user