Bug 1026680 part 5 - Make escape work with Latin1 strings. r=njn

This commit is contained in:
Jan de Mooij 2014-06-18 11:33:52 +02:00
parent 319e93f6ab
commit c4e38ae02d
2 changed files with 59 additions and 32 deletions

View File

@ -8,3 +8,11 @@ assertEq(unescape(s), "a+ def\x00A0\u1200");
// TwoByte
s += "\u1200";
assertEq(unescape(s), "a+ def\x00A0\u1200\u1200");
// Latin1
s = toLatin1("abc \u00ff");
assertEq(escape(s), "abc%20%FF");
// TwoByte
s += "\u1200";
assertEq(escape(s), "abc%20%FF%u1200");

View File

@ -113,18 +113,10 @@ str_encodeURI_Component(JSContext *cx, unsigned argc, Value *vp);
/* ES5 B.2.1 */
static bool
str_escape(JSContext *cx, unsigned argc, Value *vp)
template <typename CharT>
static jschar *
Escape(JSContext *cx, const CharT *chars, uint32_t length, uint32_t *newLengthOut)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSLinearString *str = ArgToRootedString(cx, args, 0);
if (!str)
return false;
uint32_t length = str->length();
const jschar *chars = str->chars();
static const uint8_t shouldPassThrough[128] = {
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,
@ -137,14 +129,14 @@ str_escape(JSContext *cx, unsigned argc, Value *vp)
};
/* Take a first pass and see how big the result string will need to be. */
uint32_t newlength = length;
uint32_t newLength = length;
for (size_t i = 0; i < length; i++) {
jschar ch = chars[i];
if (ch < 128 && shouldPassThrough[ch])
continue;
/* The character will be encoded as %XX or %uXXXX. */
newlength += (ch < 256) ? 2 : 5;
newLength += (ch < 256) ? 2 : 5;
/*
* newlength is incremented by at most 5 on each iteration, so worst
@ -154,9 +146,9 @@ str_escape(JSContext *cx, unsigned argc, Value *vp)
"newlength must not overflow");
}
ScopedJSFreePtr<jschar> newchars(cx->pod_malloc<jschar>(newlength + 1));
if (!newchars)
return false;
jschar *newChars = cx->pod_malloc<jschar>(newLength + 1);
if (!newChars)
return nullptr;
static const char digits[] = "0123456789ABCDEF";
@ -164,29 +156,56 @@ str_escape(JSContext *cx, unsigned argc, Value *vp)
for (i = 0, ni = 0; i < length; i++) {
jschar ch = chars[i];
if (ch < 128 && shouldPassThrough[ch]) {
newchars[ni++] = ch;
newChars[ni++] = ch;
} else if (ch < 256) {
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';
newchars[ni++] = digits[ch >> 12];
newchars[ni++] = digits[(ch & 0xF00) >> 8];
newchars[ni++] = digits[(ch & 0xF0) >> 4];
newchars[ni++] = digits[ch & 0xF];
newChars[ni++] = '%';
newChars[ni++] = 'u';
newChars[ni++] = digits[ch >> 12];
newChars[ni++] = digits[(ch & 0xF00) >> 8];
newChars[ni++] = digits[(ch & 0xF0) >> 4];
newChars[ni++] = digits[ch & 0xF];
}
}
JS_ASSERT(ni == newlength);
newchars[newlength] = 0;
JS_ASSERT(ni == newLength);
newChars[newLength] = 0;
JSString *retstr = js_NewString<CanGC>(cx, newchars.get(), newlength);
if (!retstr)
*newLengthOut = newLength;
return newChars;
}
static bool
str_escape(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSLinearString *str = ArgToRootedString(cx, args, 0);
if (!str)
return false;
newchars.forget();
args.rval().setString(retstr);
/* TODO: Once Latin1 strings are enabled, return a Latin1 string. */
ScopedJSFreePtr<jschar> newChars;
uint32_t newLength;
if (str->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
newChars = Escape(cx, str->latin1Chars(nogc), str->length(), &newLength);
} else {
AutoCheckCannotGC nogc;
newChars = Escape(cx, str->twoByteChars(nogc), str->length(), &newLength);
}
if (!newChars)
return false;
JSString *res = js_NewString<CanGC>(cx, newChars.get(), newLength);
if (!res)
return false;
newChars.forget();
args.rval().setString(res);
return true;
}