Bug 1024518 part 2 - Make RegExp flags parser handle latin1 strings and add tests. r=bhackett

This commit is contained in:
Jan de Mooij 2014-06-16 10:48:56 +02:00
Родитель 8a12913383
Коммит ec6e1dc9bb
2 изменённых файлов: 79 добавлений и 28 удалений

Просмотреть файл

@ -0,0 +1,15 @@
// Latin1
var re = new RegExp(toLatin1("foo[bB]a\\r"), toLatin1("im"));
assertEq(isLatin1(re.source), true);
assertEq(re.source, "foo[bB]a\\r");
assertEq(re.multiline, true);
assertEq(re.ignoreCase, true);
assertEq(re.sticky, false);
// TwoByte
re = new RegExp("foo[bB]a\\r\u1200", "im");
assertEq(isLatin1(re.source), false);
assertEq(re.source, "foo[bB]a\\r\u1200");
assertEq(re.multiline, true);
assertEq(re.ignoreCase, true);
assertEq(re.sticky, false);

Просмотреть файл

@ -1062,40 +1062,76 @@ js::CloneRegExpObject(JSContext *cx, JSObject *obj_)
return res;
}
static bool
HandleRegExpFlag(RegExpFlag flag, RegExpFlag *flags)
{
if (*flags & flag)
return false;
*flags = RegExpFlag(*flags | flag);
return true;
}
template <typename CharT>
static size_t
ParseRegExpFlags(const CharT *chars, size_t length, RegExpFlag *flagsOut, jschar *lastParsedOut)
{
*flagsOut = RegExpFlag(0);
for (size_t i = 0; i < length; i++) {
*lastParsedOut = chars[i];
switch (chars[i]) {
case 'i':
if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
return false;
break;
case 'g':
if (!HandleRegExpFlag(GlobalFlag, flagsOut))
return false;
break;
case 'm':
if (!HandleRegExpFlag(MultilineFlag, flagsOut))
return false;
break;
case 'y':
if (!HandleRegExpFlag(StickyFlag, flagsOut))
return false;
break;
default:
return false;
}
}
return true;
}
bool
js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
{
size_t n = flagStr->length();
const jschar *s = flagStr->getChars(cx);
if (!s)
JSLinearString *linear = flagStr->ensureLinear(cx);
if (!linear)
return false;
*flagsOut = RegExpFlag(0);
for (size_t i = 0; i < n; i++) {
#define HANDLE_FLAG(name_) \
JS_BEGIN_MACRO \
if (*flagsOut & (name_)) \
goto bad_flag; \
*flagsOut = RegExpFlag(*flagsOut | (name_)); \
JS_END_MACRO
switch (s[i]) {
case 'i': HANDLE_FLAG(IgnoreCaseFlag); break;
case 'g': HANDLE_FLAG(GlobalFlag); break;
case 'm': HANDLE_FLAG(MultilineFlag); break;
case 'y': HANDLE_FLAG(StickyFlag); break;
default:
bad_flag:
{
size_t len = linear->length();
bool ok;
jschar lastParsed;
if (linear->hasLatin1Chars()) {
JS::AutoCheckCannotGC nogc;
ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &lastParsed);
} else {
JS::AutoCheckCannotGC nogc;
ok = ::ParseRegExpFlags(linear->twoByteChars(nogc), len, flagsOut, &lastParsed);
}
if (!ok) {
char charBuf[2];
charBuf[0] = char(s[i]);
charBuf[0] = char(lastParsed);
charBuf[1] = '\0';
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
JSMSG_BAD_REGEXP_FLAG, charBuf);
return false;
}
}
#undef HANDLE_FLAG
}
return true;
}