JS_ReportError(cx, "invalid string escape mask %x", mask);
char numBuf[12]; sprintf(numBuf, "%x", mask); JS_ReportErrorNumber(cx, NULL, JSMSG_BAD_STRING_MASK, numBuf);
str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){    JSString *str;    size_t i, ni, newlength;    const jschar *chars;    jschar *newchars;    jschar ch;    jsint mask;    jsdouble d;    const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',                           '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };    if (argc > 1) {        if (!js_ValueToNumber(cx, argv[1], &d))            return JS_FALSE;        if (!JSDOUBLE_IS_FINITE(d) ||            (mask = (jsint)d) != d ||            mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))        {            JS_ReportError(cx, "invalid string escape mask %x", mask);            return JS_FALSE;        }    } else {        mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;    }    str = js_ValueToString(cx, argv[0]);    if (!str)        return JS_FALSE;    argv[0] = STRING_TO_JSVAL(str);    chars = str->chars;    newlength = str->length;    /* Take a first pass and see how big the result string will need to be. */    for (i = 0; i < str->length; i++) {        if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {            continue;        } else if (ch < 256) {            if (mask == URL_XPALPHAS && ch == ' ')                continue;   /* The character will be encoded as '+' */            else                newlength += 2; /* The character will be encoded as %XX */        } else {            newlength += 5; /* The character will be encoded as %uXXXX */        }    }    newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));    for (i = 0, ni = 0; i < str->length; i++) {        if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {            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];            }        } 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];        }    }    PR_ASSERT(ni == newlength);    newchars[newlength] = 0;    str = js_NewString(cx, newchars, newlength, 0);    if (!str) {        JS_free(cx, newchars);        return JS_FALSE;    }    *rval = STRING_TO_JSVAL(str);    return JS_TRUE;}