--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -108,90 +108,109 @@ static bool
str_encodeURI_Component(JSContext *cx, unsigned argc, Value *vp);
/*
* Global string methods
*/
/* 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,
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, /* pqrstuvwxyz{\}~ DEL */
};
/* 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
* case newlength == length * 6. This can't overflow.
*/
static_assert(JSString::MAX_LENGTH < UINT32_MAX / 6,
"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";
size_t i, ni;
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;
-
- JSString *retstr = js_NewString<CanGC>(cx, newchars.get(), newlength);
- if (!retstr)
+ JS_ASSERT(ni == newLength);
+ newChars[newLength] = 0;
+
+ *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;
}
template <typename CharT>
static inline bool
Unhex4(const RangedPtr<const CharT> chars, jschar *result)
{
jschar a = chars[0],