зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1439026 - Part 2: Move the most basic text-processing routines to util/Text.cpp. r=jandem.
Many operations on strings are also moved from builtin/String.cpp to vm/StringType.cpp. --HG-- extra : rebase_source : 9239b1f1691962b5f1358d65eaae278780ae3f84 extra : source : cfd781da349e59c8d6b9fea7efed04a0b2124a61
This commit is contained in:
Родитель
53395c4474
Коммит
4d670d3ab3
|
@ -63,10 +63,8 @@ using JS::SymbolCode;
|
|||
|
||||
using mozilla::CheckedInt;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::IsNegativeZero;
|
||||
using mozilla::IsSame;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodEqual;
|
||||
using mozilla::RangedPtr;
|
||||
|
||||
using JS::AutoCheckCannotGC;
|
||||
|
@ -2416,29 +2414,6 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
|
||||
{
|
||||
MOZ_ASSERT(start + pat->length() <= text->length());
|
||||
|
||||
size_t patLen = pat->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (text->hasLatin1Chars()) {
|
||||
const Latin1Char* textChars = text->latin1Chars(nogc) + start;
|
||||
if (pat->hasLatin1Chars())
|
||||
return PodEqual(textChars, pat->latin1Chars(nogc), patLen);
|
||||
|
||||
return EqualChars(textChars, pat->twoByteChars(nogc), patLen);
|
||||
}
|
||||
|
||||
const char16_t* textChars = text->twoByteChars(nogc) + start;
|
||||
if (pat->hasTwoByteChars())
|
||||
return PodEqual(textChars, pat->twoByteChars(nogc), patLen);
|
||||
|
||||
return EqualChars(pat->latin1Chars(nogc), textChars, patLen);
|
||||
}
|
||||
|
||||
// ES2018 draft rev de77aaeffce115deaf948ed30c7dbe4c60983c0c
|
||||
// 21.1.3.20 String.prototype.startsWith ( searchString [ , position ] )
|
||||
bool
|
||||
|
@ -3707,419 +3682,6 @@ js::InitStringClass(JSContext* cx, HandleObject obj)
|
|||
return proto;
|
||||
}
|
||||
|
||||
const char*
|
||||
js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
|
||||
{
|
||||
RootedValue v(cx, vArg);
|
||||
JSString* str;
|
||||
if (asSource)
|
||||
str = ValueToSource(cx, v);
|
||||
else
|
||||
str = ToString<CanGC>(cx, v);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
str = QuoteString(cx, str, 0);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return bytes->encodeLatin1(cx, str);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSString*
|
||||
js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
|
||||
{
|
||||
/* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
|
||||
MOZ_ASSERT(!arg.isString());
|
||||
|
||||
Value v = arg;
|
||||
if (!v.isPrimitive()) {
|
||||
MOZ_ASSERT(!cx->helperThread());
|
||||
if (!allowGC)
|
||||
return nullptr;
|
||||
RootedValue v2(cx, v);
|
||||
if (!ToPrimitive(cx, JSTYPE_STRING, &v2))
|
||||
return nullptr;
|
||||
v = v2;
|
||||
}
|
||||
|
||||
JSString* str;
|
||||
if (v.isString()) {
|
||||
str = v.toString();
|
||||
} else if (v.isInt32()) {
|
||||
str = Int32ToString<allowGC>(cx, v.toInt32());
|
||||
} else if (v.isDouble()) {
|
||||
str = NumberToString<allowGC>(cx, v.toDouble());
|
||||
} else if (v.isBoolean()) {
|
||||
str = BooleanToString(cx, v.toBoolean());
|
||||
} else if (v.isNull()) {
|
||||
str = cx->names().null;
|
||||
} else if (v.isSymbol()) {
|
||||
MOZ_ASSERT(!cx->helperThread());
|
||||
if (allowGC) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SYMBOL_TO_STRING);
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
str = cx->names().undefined;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template JSString*
|
||||
js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
|
||||
|
||||
template JSString*
|
||||
js::ToStringSlow<NoGC>(JSContext* cx, const Value& arg);
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
js::ToStringSlow(JSContext* cx, HandleValue v)
|
||||
{
|
||||
return ToStringSlow<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
static JSString*
|
||||
SymbolToSource(JSContext* cx, Symbol* symbol)
|
||||
{
|
||||
RootedString desc(cx, symbol->description());
|
||||
SymbolCode code = symbol->code();
|
||||
if (code != SymbolCode::InSymbolRegistry && code != SymbolCode::UniqueSymbol) {
|
||||
// Well-known symbol.
|
||||
MOZ_ASSERT(uint32_t(code) < JS::WellKnownSymbolLimit);
|
||||
return desc;
|
||||
}
|
||||
|
||||
StringBuffer buf(cx);
|
||||
if (code == SymbolCode::InSymbolRegistry ? !buf.append("Symbol.for(") : !buf.append("Symbol("))
|
||||
return nullptr;
|
||||
if (desc) {
|
||||
desc = StringToSource(cx, desc);
|
||||
if (!desc || !buf.append(desc))
|
||||
return nullptr;
|
||||
}
|
||||
if (!buf.append(')'))
|
||||
return nullptr;
|
||||
return buf.finishString();
|
||||
}
|
||||
|
||||
JSString*
|
||||
js::ValueToSource(JSContext* cx, HandleValue v)
|
||||
{
|
||||
if (!CheckRecursionLimit(cx))
|
||||
return nullptr;
|
||||
assertSameCompartment(cx, v);
|
||||
|
||||
if (v.isUndefined())
|
||||
return cx->names().void0;
|
||||
if (v.isString())
|
||||
return StringToSource(cx, v.toString());
|
||||
if (v.isSymbol())
|
||||
return SymbolToSource(cx, v.toSymbol());
|
||||
if (v.isPrimitive()) {
|
||||
/* Special case to preserve negative zero, _contra_ toString. */
|
||||
if (v.isDouble() && IsNegativeZero(v.toDouble())) {
|
||||
static const Latin1Char negativeZero[] = {'-', '0'};
|
||||
|
||||
return NewStringCopyN<CanGC>(cx, negativeZero, mozilla::ArrayLength(negativeZero));
|
||||
}
|
||||
return ToString<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
RootedValue fval(cx);
|
||||
RootedObject obj(cx, &v.toObject());
|
||||
if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))
|
||||
return nullptr;
|
||||
if (IsCallable(fval)) {
|
||||
RootedValue v(cx);
|
||||
if (!js::Call(cx, fval, obj, &v))
|
||||
return nullptr;
|
||||
|
||||
return ToString<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
return ObjectToSource(cx, obj);
|
||||
}
|
||||
|
||||
JSString*
|
||||
js::StringToSource(JSContext* cx, JSString* str)
|
||||
{
|
||||
return QuoteString(cx, str, '"');
|
||||
}
|
||||
|
||||
bool
|
||||
js::EqualChars(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
MOZ_ASSERT(str1->length() == str2->length());
|
||||
|
||||
size_t len = str1->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (str1->hasTwoByteChars()) {
|
||||
if (str2->hasTwoByteChars())
|
||||
return PodEqual(str1->twoByteChars(nogc), str2->twoByteChars(nogc), len);
|
||||
|
||||
return EqualChars(str2->latin1Chars(nogc), str1->twoByteChars(nogc), len);
|
||||
}
|
||||
|
||||
if (str2->hasLatin1Chars())
|
||||
return PodEqual(str1->latin1Chars(nogc), str2->latin1Chars(nogc), len);
|
||||
|
||||
return EqualChars(str1->latin1Chars(nogc), str2->twoByteChars(nogc), len);
|
||||
}
|
||||
|
||||
bool
|
||||
js::EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result)
|
||||
{
|
||||
if (str1 == str2) {
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t length1 = str1->length();
|
||||
if (length1 != str2->length()) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSLinearString* linear1 = str1->ensureLinear(cx);
|
||||
if (!linear1)
|
||||
return false;
|
||||
JSLinearString* linear2 = str2->ensureLinear(cx);
|
||||
if (!linear2)
|
||||
return false;
|
||||
|
||||
*result = EqualChars(linear1, linear2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::EqualStrings(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
if (str1 == str2)
|
||||
return true;
|
||||
|
||||
size_t length1 = str1->length();
|
||||
if (length1 != str2->length())
|
||||
return false;
|
||||
|
||||
return EqualChars(str1, str2);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
CompareStringsImpl(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
size_t len1 = str1->length();
|
||||
size_t len2 = str2->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (str1->hasLatin1Chars()) {
|
||||
const Latin1Char* chars1 = str1->latin1Chars(nogc);
|
||||
return str2->hasLatin1Chars()
|
||||
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
|
||||
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
|
||||
}
|
||||
|
||||
const char16_t* chars1 = str1->twoByteChars(nogc);
|
||||
return str2->hasLatin1Chars()
|
||||
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
|
||||
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
|
||||
}
|
||||
|
||||
int32_t
|
||||
js::CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2)
|
||||
{
|
||||
AutoCheckCannotGC nogc;
|
||||
return s2->hasLatin1Chars()
|
||||
? CompareChars(s1, len1, s2->latin1Chars(nogc), s2->length())
|
||||
: CompareChars(s1, len1, s2->twoByteChars(nogc), s2->length());
|
||||
}
|
||||
|
||||
bool
|
||||
js::CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result)
|
||||
{
|
||||
MOZ_ASSERT(str1);
|
||||
MOZ_ASSERT(str2);
|
||||
|
||||
if (str1 == str2) {
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSLinearString* linear1 = str1->ensureLinear(cx);
|
||||
if (!linear1)
|
||||
return false;
|
||||
|
||||
JSLinearString* linear2 = str2->ensureLinear(cx);
|
||||
if (!linear2)
|
||||
return false;
|
||||
|
||||
*result = CompareStringsImpl(linear1, linear2);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t
|
||||
js::CompareAtoms(JSAtom* atom1, JSAtom* atom2)
|
||||
{
|
||||
return CompareStringsImpl(atom1, atom2);
|
||||
}
|
||||
|
||||
bool
|
||||
js::StringEqualsAscii(JSLinearString* str, const char* asciiBytes)
|
||||
{
|
||||
size_t length = strlen(asciiBytes);
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i != length; ++i)
|
||||
MOZ_ASSERT(unsigned(asciiBytes[i]) <= 127);
|
||||
#endif
|
||||
if (length != str->length())
|
||||
return false;
|
||||
|
||||
const Latin1Char* latin1 = reinterpret_cast<const Latin1Char*>(asciiBytes);
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
return str->hasLatin1Chars()
|
||||
? PodEqual(latin1, str->latin1Chars(nogc), length)
|
||||
: EqualChars(latin1, str->twoByteChars(nogc), length);
|
||||
}
|
||||
|
||||
int32_t
|
||||
js_fputs(const char16_t* s, FILE* f)
|
||||
{
|
||||
while (*s != 0) {
|
||||
if (fputwc(wchar_t(*s), f) == WEOF)
|
||||
return WEOF;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(JSContext* cx, const char* s)
|
||||
{
|
||||
size_t n = strlen(s) + 1;
|
||||
auto ret = cx->make_pod_array<char>(n);
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(JSContext* cx, const char16_t* s)
|
||||
{
|
||||
size_t n = js_strlen(s) + 1;
|
||||
auto ret = cx->make_pod_array<char16_t>(n);
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(const char* s)
|
||||
{
|
||||
size_t n = strlen(s) + 1;
|
||||
UniqueChars ret(js_pod_malloc<char>(n));
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(const char* s, size_t n)
|
||||
{
|
||||
UniqueChars ret(js_pod_malloc<char>(n + 1));
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(const char16_t* s)
|
||||
{
|
||||
return DuplicateString(s, js_strlen(s));
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(const char16_t* s, size_t n)
|
||||
{
|
||||
UniqueTwoByteChars ret(js_pod_malloc<char16_t>(n + 1));
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(char*)
|
||||
js_strdup(const char* s)
|
||||
{
|
||||
return DuplicateString(s).release();
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
const CharT*
|
||||
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit)
|
||||
{
|
||||
while (s < limit) {
|
||||
if (*s == c)
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template const Latin1Char*
|
||||
js_strchr_limit(const Latin1Char* s, char16_t c, const Latin1Char* limit);
|
||||
|
||||
template const char16_t*
|
||||
js_strchr_limit(const char16_t* s, char16_t c, const char16_t* limit);
|
||||
|
||||
char16_t*
|
||||
js::InflateString(JSContext* cx, const char* bytes, size_t length)
|
||||
{
|
||||
char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
|
||||
if (!chars)
|
||||
return nullptr;
|
||||
CopyAndInflateChars(chars, bytes, length);
|
||||
chars[length] = 0;
|
||||
return chars;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp)
|
||||
{
|
||||
size_t dstlen = *dstlenp;
|
||||
if (srclen > dstlen) {
|
||||
for (size_t i = 0; i < dstlen; i++)
|
||||
dst[i] = char(src[i]);
|
||||
if (maybecx) {
|
||||
AutoSuppressGC suppress(maybecx);
|
||||
JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
|
||||
JSMSG_BUFFER_TOO_SMALL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = char(src[i]);
|
||||
*dstlenp = srclen;
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp);
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp);
|
||||
|
||||
#define ____ false
|
||||
|
||||
/*
|
||||
|
@ -4475,182 +4037,6 @@ js::EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
|
||||
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
|
||||
*/
|
||||
uint32_t
|
||||
js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
|
||||
{
|
||||
MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
|
||||
|
||||
if (ucs4Char < 0x80) {
|
||||
utf8Buffer[0] = uint8_t(ucs4Char);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t a = ucs4Char >> 11;
|
||||
uint32_t utf8Length = 2;
|
||||
while (a) {
|
||||
a >>= 5;
|
||||
utf8Length++;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(utf8Length <= 4);
|
||||
|
||||
uint32_t i = utf8Length;
|
||||
while (--i) {
|
||||
utf8Buffer[i] = uint8_t((ucs4Char & 0x3F) | 0x80);
|
||||
ucs4Char >>= 6;
|
||||
}
|
||||
|
||||
utf8Buffer[0] = uint8_t(0x100 - (1 << (8 - utf8Length)) + ucs4Char);
|
||||
return utf8Length;
|
||||
}
|
||||
|
||||
size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str,
|
||||
uint32_t quote)
|
||||
{
|
||||
size_t len = str->length();
|
||||
AutoCheckCannotGC nogc;
|
||||
return str->hasLatin1Chars()
|
||||
? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote)
|
||||
: PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
|
||||
size_t length, uint32_t quote)
|
||||
{
|
||||
enum {
|
||||
STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
|
||||
} state;
|
||||
|
||||
MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"');
|
||||
MOZ_ASSERT_IF(!buffer, bufferSize == 0);
|
||||
MOZ_ASSERT_IF(out, !buffer);
|
||||
|
||||
if (bufferSize == 0)
|
||||
buffer = nullptr;
|
||||
else
|
||||
bufferSize--;
|
||||
|
||||
const CharT* charsEnd = chars + length;
|
||||
size_t n = 0;
|
||||
state = FIRST_QUOTE;
|
||||
unsigned shift = 0;
|
||||
unsigned hex = 0;
|
||||
unsigned u = 0;
|
||||
char c = 0; /* to quell GCC warnings */
|
||||
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
case STOP:
|
||||
goto stop;
|
||||
case FIRST_QUOTE:
|
||||
state = CHARS;
|
||||
goto do_quote;
|
||||
case LAST_QUOTE:
|
||||
state = STOP;
|
||||
do_quote:
|
||||
if (quote == 0)
|
||||
continue;
|
||||
c = (char)quote;
|
||||
break;
|
||||
case CHARS:
|
||||
if (chars == charsEnd) {
|
||||
state = LAST_QUOTE;
|
||||
continue;
|
||||
}
|
||||
u = *chars++;
|
||||
if (u < ' ') {
|
||||
if (u != 0) {
|
||||
const char* escape = strchr(js_EscapeMap, (int)u);
|
||||
if (escape) {
|
||||
u = escape[1];
|
||||
goto do_escape;
|
||||
}
|
||||
}
|
||||
goto do_hex_escape;
|
||||
}
|
||||
if (u < 127) {
|
||||
if (u == quote || u == '\\')
|
||||
goto do_escape;
|
||||
c = (char)u;
|
||||
} else if (u < 0x100) {
|
||||
goto do_hex_escape;
|
||||
} else {
|
||||
shift = 16;
|
||||
hex = u;
|
||||
u = 'u';
|
||||
goto do_escape;
|
||||
}
|
||||
break;
|
||||
do_hex_escape:
|
||||
shift = 8;
|
||||
hex = u;
|
||||
u = 'x';
|
||||
do_escape:
|
||||
c = '\\';
|
||||
state = ESCAPE_START;
|
||||
break;
|
||||
case ESCAPE_START:
|
||||
MOZ_ASSERT(' ' <= u && u < 127);
|
||||
c = (char)u;
|
||||
state = ESCAPE_MORE;
|
||||
break;
|
||||
case ESCAPE_MORE:
|
||||
if (shift == 0) {
|
||||
state = CHARS;
|
||||
continue;
|
||||
}
|
||||
shift -= 4;
|
||||
u = 0xF & (hex >> shift);
|
||||
c = (char)(u + (u < 10 ? '0' : 'A' - 10));
|
||||
break;
|
||||
}
|
||||
if (buffer) {
|
||||
MOZ_ASSERT(n <= bufferSize);
|
||||
if (n != bufferSize) {
|
||||
buffer[n] = c;
|
||||
} else {
|
||||
buffer[n] = '\0';
|
||||
buffer = nullptr;
|
||||
}
|
||||
} else if (out) {
|
||||
if (!out->put(&c, 1))
|
||||
return size_t(-1);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
stop:
|
||||
if (buffer)
|
||||
buffer[n] = '\0';
|
||||
return n;
|
||||
}
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
|
||||
uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
|
||||
uint32_t quote);
|
||||
|
||||
static bool
|
||||
FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match)
|
||||
{
|
||||
|
|
|
@ -22,269 +22,12 @@
|
|||
#include "util/Unicode.h"
|
||||
#include "vm/Printer.h"
|
||||
|
||||
class JSAutoByteString;
|
||||
class JSLinearString;
|
||||
|
||||
namespace js {
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
template <AllowGC allowGC>
|
||||
extern JSString*
|
||||
ConcatStrings(JSContext* cx,
|
||||
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
||||
typename MaybeRooted<JSString*, allowGC>::HandleType right);
|
||||
|
||||
// Return s advanced past any Unicode white space characters.
|
||||
template <typename CharT>
|
||||
static inline const CharT*
|
||||
SkipSpace(const CharT* s, const CharT* end)
|
||||
{
|
||||
MOZ_ASSERT(s <= end);
|
||||
|
||||
while (s < end && unicode::IsSpace(*s))
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// Return less than, equal to, or greater than zero depending on whether
|
||||
// s1 is less than, equal to, or greater than s2.
|
||||
template <typename Char1, typename Char2>
|
||||
inline int32_t
|
||||
CompareChars(const Char1* s1, size_t len1, const Char2* s2, size_t len2)
|
||||
{
|
||||
size_t n = Min(len1, len2);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (int32_t cmp = s1[i] - s2[i])
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return int32_t(len1 - len2);
|
||||
}
|
||||
|
||||
extern int32_t
|
||||
CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Shorthands for ASCII (7-bit) decimal and hex conversion.
|
||||
* Manually inline isdigit and isxdigit for performance; MSVC doesn't do this for us.
|
||||
*/
|
||||
#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9)
|
||||
#define JS7_ISA2F(c) ((((((unsigned)(c)) - 'a') <= 5) || (((unsigned)(c)) - 'A') <= 5))
|
||||
#define JS7_UNDEC(c) ((c) - '0')
|
||||
#define JS7_ISOCT(c) ((((unsigned)(c)) - '0') <= 7)
|
||||
#define JS7_UNOCT(c) (JS7_UNDEC(c))
|
||||
#define JS7_ISHEX(c) ((c) < 128 && (JS7_ISDEC(c) || JS7_ISA2F(c)))
|
||||
#define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
|
||||
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
|
||||
|
||||
static MOZ_ALWAYS_INLINE size_t
|
||||
js_strlen(const char16_t* s)
|
||||
{
|
||||
return std::char_traits<char16_t>::length(s);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
extern const CharT*
|
||||
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit);
|
||||
|
||||
extern int32_t
|
||||
js_fputs(const char16_t* s, FILE* f);
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Initialize the String class, returning its prototype object. */
|
||||
extern JSObject*
|
||||
InitStringClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
/*
|
||||
* Convert a value to a printable C string.
|
||||
*/
|
||||
extern const char*
|
||||
ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
|
||||
|
||||
extern UniqueChars
|
||||
DuplicateString(JSContext* cx, const char* s);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(JSContext* cx, const char16_t* s);
|
||||
|
||||
/*
|
||||
* These variants do not report OOMs, you must arrange for OOMs to be reported
|
||||
* yourself.
|
||||
*/
|
||||
extern UniqueChars
|
||||
DuplicateString(const char* s);
|
||||
|
||||
extern UniqueChars
|
||||
DuplicateString(const char* s, size_t n);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(const char16_t* s);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(const char16_t* s, size_t n);
|
||||
|
||||
/*
|
||||
* Convert a non-string value to a string, returning null after reporting an
|
||||
* error, otherwise returning a new string reference.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
extern JSString*
|
||||
ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
|
||||
|
||||
/*
|
||||
* Convert the given value to a string. This method includes an inline
|
||||
* fast-path for the case where the value is already a string; if the value is
|
||||
* known not to be a string, use ToStringSlow instead.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSString*
|
||||
ToString(JSContext* cx, JS::HandleValue v)
|
||||
{
|
||||
if (v.isString())
|
||||
return v.toString();
|
||||
return ToStringSlow<allowGC>(cx, v);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function implements E-262-3 section 9.8, toString. Convert the given
|
||||
* value to a string of characters appended to the given buffer. On error, the
|
||||
* passed buffer may have partial results appended.
|
||||
*/
|
||||
inline bool
|
||||
ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
|
||||
|
||||
/*
|
||||
* Convert a value to its source expression, returning null after reporting
|
||||
* an error, otherwise returning a new string reference.
|
||||
*/
|
||||
extern JSString*
|
||||
ValueToSource(JSContext* cx, HandleValue v);
|
||||
|
||||
/*
|
||||
* Convert a JSString to its source expression; returns null after reporting an
|
||||
* error, otherwise returns a new string reference. No Handle needed since the
|
||||
* input is dead after the GC.
|
||||
*/
|
||||
extern JSString*
|
||||
StringToSource(JSContext* cx, JSString* str);
|
||||
|
||||
/*
|
||||
* Test if strings are equal. The caller can call the function even if str1
|
||||
* or str2 are not GC-allocated things.
|
||||
*/
|
||||
extern bool
|
||||
EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result);
|
||||
|
||||
/* Use the infallible method instead! */
|
||||
extern bool
|
||||
EqualStrings(JSContext* cx, JSLinearString* str1, JSLinearString* str2, bool* result) = delete;
|
||||
|
||||
/* EqualStrings is infallible on linear strings. */
|
||||
extern bool
|
||||
EqualStrings(JSLinearString* str1, JSLinearString* str2);
|
||||
|
||||
extern bool
|
||||
EqualChars(JSLinearString* str1, JSLinearString* str2);
|
||||
|
||||
/*
|
||||
* Return less than, equal to, or greater than zero depending on whether
|
||||
* str1 is less than, equal to, or greater than str2.
|
||||
*/
|
||||
extern bool
|
||||
CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result);
|
||||
|
||||
/*
|
||||
* Same as CompareStrings but for atoms. Don't use this to just test
|
||||
* for equality; use this when you need an ordering on atoms.
|
||||
*/
|
||||
extern int32_t
|
||||
CompareAtoms(JSAtom* atom1, JSAtom* atom2);
|
||||
|
||||
/*
|
||||
* Return true if the string matches the given sequence of ASCII bytes.
|
||||
*/
|
||||
extern bool
|
||||
StringEqualsAscii(JSLinearString* str, const char* asciiBytes);
|
||||
|
||||
extern int
|
||||
StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
|
||||
|
||||
/* Return true if the string contains a pattern at |start|. */
|
||||
extern bool
|
||||
HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start);
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char2* s2, size_t len);
|
||||
|
||||
template <typename Char1>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char1* s2, size_t len)
|
||||
{
|
||||
return mozilla::PodEqual(s1, s2, len);
|
||||
}
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char2* s2, size_t len)
|
||||
{
|
||||
for (const Char1* s1end = s1 + len; s1 < s1end; s1++, s2++) {
|
||||
if (*s1 != *s2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes |str|'s substring for the range [beginInt, beginInt + lengthInt).
|
||||
* Negative, overlarge, swapped, etc. |beginInt| and |lengthInt| are forbidden
|
||||
* and constitute API misuse.
|
||||
*/
|
||||
JSString*
|
||||
SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt);
|
||||
|
||||
/*
|
||||
* Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
|
||||
* otherwise return the char16_t buffer that was malloc'ed. A null char is
|
||||
* appended.
|
||||
*/
|
||||
extern char16_t*
|
||||
InflateString(JSContext* cx, const char* bytes, size_t length);
|
||||
|
||||
/*
|
||||
* Inflate bytes to JS chars in an existing buffer. 'dst' must be large
|
||||
* enough for 'srclen' char16_t code units. The buffer is NOT null-terminated.
|
||||
*/
|
||||
inline void
|
||||
CopyAndInflateChars(char16_t* dst, const char* src, size_t srclen)
|
||||
{
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = (unsigned char) src[i];
|
||||
}
|
||||
|
||||
inline void
|
||||
CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
|
||||
{
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
|
||||
* 'length chars. The buffer is NOT null-terminated. The destination length
|
||||
* must to be initialized with the buffer size and will contain on return the
|
||||
* number of copied bytes.
|
||||
*/
|
||||
template <typename CharT>
|
||||
extern bool
|
||||
DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
|
||||
size_t charsLength, char* bytes, size_t* length);
|
||||
|
||||
extern bool
|
||||
str_fromCharCode(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
|
@ -414,90 +157,6 @@ str_localeCompare(JSContext* cx, unsigned argc, Value* vp);
|
|||
extern bool
|
||||
str_concat(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/*
|
||||
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
|
||||
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
|
||||
*/
|
||||
extern uint32_t
|
||||
OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
|
||||
|
||||
extern size_t
|
||||
PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str,
|
||||
uint32_t quote);
|
||||
|
||||
template <typename CharT>
|
||||
extern size_t
|
||||
PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
/*
|
||||
* Write str into buffer escaping any non-printable or non-ASCII character
|
||||
* using \escapes for JS string literals.
|
||||
* Guarantees that a NUL is at the end of the buffer unless size is 0. Returns
|
||||
* the length of the written output, NOT including the NUL. Thus, a return
|
||||
* value of size or more means that the output was truncated. If buffer
|
||||
* is null, just returns the length of the output. If quote is not 0, it must
|
||||
* be a single or double quote character that will quote the output.
|
||||
*/
|
||||
inline size_t
|
||||
PutEscapedString(char* buffer, size_t size, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
size_t n = PutEscapedStringImpl(buffer, size, nullptr, str, quote);
|
||||
|
||||
/* PutEscapedStringImpl can only fail with a file. */
|
||||
MOZ_ASSERT(n != size_t(-1));
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
inline size_t
|
||||
PutEscapedString(char* buffer, size_t bufferSize, const CharT* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
size_t n = PutEscapedStringImpl(buffer, bufferSize, nullptr, chars, length, quote);
|
||||
|
||||
/* PutEscapedStringImpl can only fail with a file. */
|
||||
MOZ_ASSERT(n != size_t(-1));
|
||||
return n;
|
||||
}
|
||||
|
||||
inline bool
|
||||
EscapedStringPrinter(GenericPrinter& out, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
return PutEscapedStringImpl(nullptr, 0, &out, str, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
inline bool
|
||||
EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
return PutEscapedStringImpl(nullptr, 0, &out, chars, length, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write str into file escaping any non-printable or non-ASCII character.
|
||||
* If quote is not 0, it must be a single or double quote character that
|
||||
* will quote the output.
|
||||
*/
|
||||
inline bool
|
||||
FileEscapedString(FILE* fp, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
Fprinter out(fp);
|
||||
bool res = EscapedStringPrinter(out, str, quote);
|
||||
out.finish();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline bool
|
||||
FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
Fprinter out(fp);
|
||||
bool res = EscapedStringPrinter(out, chars, length, quote);
|
||||
out.finish();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length);
|
||||
|
||||
ArrayObject*
|
||||
str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep,
|
||||
uint32_t limit);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "js/Vector.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/Debugger.h"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
#include "vm/JSContext-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "vm/JSFunction.h"
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "wasm/AsmJS.h"
|
||||
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "gc/GC.h"
|
||||
#include "gc/Memory.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/HelperThreads.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "gc/PublicIterators.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/JSFunction.h"
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/Shape.h"
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
#include "vtune/VTuneWrapper.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "jit/MIRGraph.h"
|
||||
#include "jit/RangeAnalysis.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "util/Text.h"
|
||||
|
||||
#include "jsboolinlines.h"
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "jit/JitcodeMap.h"
|
||||
#include "jit/JitSpewer.h"
|
||||
#include "js/TrackedOptimizationInfo.h"
|
||||
#include "util/Text.h"
|
||||
|
||||
#include "vm/ObjectGroup-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#endif
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "jit/SharedICHelpers-inl.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "js/Vector.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "threading/Thread.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/SharedImmutableStringsCache.h"
|
||||
|
||||
const int NUM_THREADS = 256;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "js/UbiNodePostOrder.h"
|
||||
#include "js/UbiNodeShortestPaths.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/SavedFrame.h"
|
||||
|
||||
using JS::RootedObject;
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "js/Utility.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/DateObject.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "js/Class.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/Iteration.h"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "vm/JSScript.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
#include "vm/ErrorObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
|
|
@ -307,6 +307,7 @@ UNIFIED_SOURCES += [
|
|||
'util/NativeStack.cpp',
|
||||
'util/Printf.cpp',
|
||||
'util/StringBuffer.cpp',
|
||||
'util/Text.cpp',
|
||||
'util/Unicode.cpp',
|
||||
'vm/ArgumentsObject.cpp',
|
||||
'vm/ArrayBufferObject.cpp',
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "js/Wrapper.h"
|
||||
#include "shell/jsshell.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
#include "threading/LockGuard.h"
|
||||
#include "threading/Thread.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Compression.h"
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "util/Text.h"
|
||||
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include "gc/GC.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
using namespace JS;
|
||||
using namespace js;
|
||||
using js::gc::AutoSuppressGC;
|
||||
using mozilla::PodCopy;
|
||||
|
||||
template <typename CharT>
|
||||
const CharT*
|
||||
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit)
|
||||
{
|
||||
while (s < limit) {
|
||||
if (*s == c)
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template const Latin1Char*
|
||||
js_strchr_limit(const Latin1Char* s, char16_t c, const Latin1Char* limit);
|
||||
|
||||
template const char16_t*
|
||||
js_strchr_limit(const char16_t* s, char16_t c, const char16_t* limit);
|
||||
|
||||
JS_PUBLIC_API(char*)
|
||||
js_strdup(const char* s)
|
||||
{
|
||||
return DuplicateString(s).release();
|
||||
}
|
||||
|
||||
int32_t
|
||||
js_fputs(const char16_t* s, FILE* f)
|
||||
{
|
||||
while (*s != 0) {
|
||||
if (fputwc(wchar_t(*s), f) == WEOF)
|
||||
return WEOF;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(JSContext* cx, const char* s)
|
||||
{
|
||||
size_t n = strlen(s) + 1;
|
||||
auto ret = cx->make_pod_array<char>(n);
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(JSContext* cx, const char16_t* s)
|
||||
{
|
||||
size_t n = js_strlen(s) + 1;
|
||||
auto ret = cx->make_pod_array<char16_t>(n);
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(const char* s)
|
||||
{
|
||||
size_t n = strlen(s) + 1;
|
||||
UniqueChars ret(js_pod_malloc<char>(n));
|
||||
if (!ret)
|
||||
return ret;
|
||||
PodCopy(ret.get(), s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueChars
|
||||
js::DuplicateString(const char* s, size_t n)
|
||||
{
|
||||
UniqueChars ret(js_pod_malloc<char>(n + 1));
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(const char16_t* s)
|
||||
{
|
||||
return DuplicateString(s, js_strlen(s));
|
||||
}
|
||||
|
||||
UniqueTwoByteChars
|
||||
js::DuplicateString(const char16_t* s, size_t n)
|
||||
{
|
||||
UniqueTwoByteChars ret(js_pod_malloc<char16_t>(n + 1));
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char16_t*
|
||||
js::InflateString(JSContext* cx, const char* bytes, size_t length)
|
||||
{
|
||||
char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
|
||||
if (!chars)
|
||||
return nullptr;
|
||||
CopyAndInflateChars(chars, bytes, length);
|
||||
chars[length] = 0;
|
||||
return chars;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp)
|
||||
{
|
||||
size_t dstlen = *dstlenp;
|
||||
if (srclen > dstlen) {
|
||||
for (size_t i = 0; i < dstlen; i++)
|
||||
dst[i] = char(src[i]);
|
||||
if (maybecx) {
|
||||
AutoSuppressGC suppress(maybecx);
|
||||
JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
|
||||
JSMSG_BUFFER_TOO_SMALL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = char(src[i]);
|
||||
*dstlenp = srclen;
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp);
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
|
||||
char* dst, size_t* dstlenp);
|
||||
|
||||
/*
|
||||
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
|
||||
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
|
||||
*/
|
||||
uint32_t
|
||||
js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
|
||||
{
|
||||
MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
|
||||
|
||||
if (ucs4Char < 0x80) {
|
||||
utf8Buffer[0] = uint8_t(ucs4Char);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t a = ucs4Char >> 11;
|
||||
uint32_t utf8Length = 2;
|
||||
while (a) {
|
||||
a >>= 5;
|
||||
utf8Length++;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(utf8Length <= 4);
|
||||
|
||||
uint32_t i = utf8Length;
|
||||
while (--i) {
|
||||
utf8Buffer[i] = uint8_t((ucs4Char & 0x3F) | 0x80);
|
||||
ucs4Char >>= 6;
|
||||
}
|
||||
|
||||
utf8Buffer[0] = uint8_t(0x100 - (1 << (8 - utf8Length)) + ucs4Char);
|
||||
return utf8Length;
|
||||
}
|
||||
|
||||
size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str,
|
||||
uint32_t quote)
|
||||
{
|
||||
size_t len = str->length();
|
||||
AutoCheckCannotGC nogc;
|
||||
return str->hasLatin1Chars()
|
||||
? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote)
|
||||
: PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
|
||||
size_t length, uint32_t quote)
|
||||
{
|
||||
enum {
|
||||
STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
|
||||
} state;
|
||||
|
||||
MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"');
|
||||
MOZ_ASSERT_IF(!buffer, bufferSize == 0);
|
||||
MOZ_ASSERT_IF(out, !buffer);
|
||||
|
||||
if (bufferSize == 0)
|
||||
buffer = nullptr;
|
||||
else
|
||||
bufferSize--;
|
||||
|
||||
const CharT* charsEnd = chars + length;
|
||||
size_t n = 0;
|
||||
state = FIRST_QUOTE;
|
||||
unsigned shift = 0;
|
||||
unsigned hex = 0;
|
||||
unsigned u = 0;
|
||||
char c = 0; /* to quell GCC warnings */
|
||||
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
case STOP:
|
||||
goto stop;
|
||||
case FIRST_QUOTE:
|
||||
state = CHARS;
|
||||
goto do_quote;
|
||||
case LAST_QUOTE:
|
||||
state = STOP;
|
||||
do_quote:
|
||||
if (quote == 0)
|
||||
continue;
|
||||
c = (char)quote;
|
||||
break;
|
||||
case CHARS:
|
||||
if (chars == charsEnd) {
|
||||
state = LAST_QUOTE;
|
||||
continue;
|
||||
}
|
||||
u = *chars++;
|
||||
if (u < ' ') {
|
||||
if (u != 0) {
|
||||
const char* escape = strchr(js_EscapeMap, (int)u);
|
||||
if (escape) {
|
||||
u = escape[1];
|
||||
goto do_escape;
|
||||
}
|
||||
}
|
||||
goto do_hex_escape;
|
||||
}
|
||||
if (u < 127) {
|
||||
if (u == quote || u == '\\')
|
||||
goto do_escape;
|
||||
c = (char)u;
|
||||
} else if (u < 0x100) {
|
||||
goto do_hex_escape;
|
||||
} else {
|
||||
shift = 16;
|
||||
hex = u;
|
||||
u = 'u';
|
||||
goto do_escape;
|
||||
}
|
||||
break;
|
||||
do_hex_escape:
|
||||
shift = 8;
|
||||
hex = u;
|
||||
u = 'x';
|
||||
do_escape:
|
||||
c = '\\';
|
||||
state = ESCAPE_START;
|
||||
break;
|
||||
case ESCAPE_START:
|
||||
MOZ_ASSERT(' ' <= u && u < 127);
|
||||
c = (char)u;
|
||||
state = ESCAPE_MORE;
|
||||
break;
|
||||
case ESCAPE_MORE:
|
||||
if (shift == 0) {
|
||||
state = CHARS;
|
||||
continue;
|
||||
}
|
||||
shift -= 4;
|
||||
u = 0xF & (hex >> shift);
|
||||
c = (char)(u + (u < 10 ? '0' : 'A' - 10));
|
||||
break;
|
||||
}
|
||||
if (buffer) {
|
||||
MOZ_ASSERT(n <= bufferSize);
|
||||
if (n != bufferSize) {
|
||||
buffer[n] = c;
|
||||
} else {
|
||||
buffer[n] = '\0';
|
||||
buffer = nullptr;
|
||||
}
|
||||
} else if (out) {
|
||||
if (!out->put(&c, 1))
|
||||
return size_t(-1);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
stop:
|
||||
if (buffer)
|
||||
buffer[n] = '\0';
|
||||
return n;
|
||||
}
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
|
||||
uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
|
||||
uint32_t quote);
|
|
@ -0,0 +1,253 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef util_Text_h
|
||||
#define util_Text_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "jsutil.h"
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
#include "util/Unicode.h"
|
||||
#include "vm/Printer.h"
|
||||
|
||||
class JSLinearString;
|
||||
|
||||
/*
|
||||
* Shorthands for ASCII (7-bit) decimal and hex conversion.
|
||||
* Manually inline isdigit and isxdigit for performance; MSVC doesn't do this for us.
|
||||
*/
|
||||
#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9)
|
||||
#define JS7_ISA2F(c) ((((((unsigned)(c)) - 'a') <= 5) || (((unsigned)(c)) - 'A') <= 5))
|
||||
#define JS7_UNDEC(c) ((c) - '0')
|
||||
#define JS7_ISOCT(c) ((((unsigned)(c)) - '0') <= 7)
|
||||
#define JS7_UNOCT(c) (JS7_UNDEC(c))
|
||||
#define JS7_ISHEX(c) ((c) < 128 && (JS7_ISDEC(c) || JS7_ISA2F(c)))
|
||||
#define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
|
||||
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
|
||||
|
||||
static MOZ_ALWAYS_INLINE size_t
|
||||
js_strlen(const char16_t* s)
|
||||
{
|
||||
return std::char_traits<char16_t>::length(s);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
extern const CharT*
|
||||
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit);
|
||||
|
||||
extern int32_t
|
||||
js_fputs(const char16_t* s, FILE* f);
|
||||
|
||||
namespace js {
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char2* s2, size_t len);
|
||||
|
||||
template <typename Char1>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char1* s2, size_t len)
|
||||
{
|
||||
return mozilla::PodEqual(s1, s2, len);
|
||||
}
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline bool
|
||||
EqualChars(const Char1* s1, const Char2* s2, size_t len)
|
||||
{
|
||||
for (const Char1* s1end = s1 + len; s1 < s1end; s1++, s2++) {
|
||||
if (*s1 != *s2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return less than, equal to, or greater than zero depending on whether
|
||||
// s1 is less than, equal to, or greater than s2.
|
||||
template <typename Char1, typename Char2>
|
||||
inline int32_t
|
||||
CompareChars(const Char1* s1, size_t len1, const Char2* s2, size_t len2)
|
||||
{
|
||||
size_t n = Min(len1, len2);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (int32_t cmp = s1[i] - s2[i])
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return int32_t(len1 - len2);
|
||||
}
|
||||
|
||||
// Return s advanced past any Unicode white space characters.
|
||||
template <typename CharT>
|
||||
static inline const CharT*
|
||||
SkipSpace(const CharT* s, const CharT* end)
|
||||
{
|
||||
MOZ_ASSERT(s <= end);
|
||||
|
||||
while (s < end && unicode::IsSpace(*s))
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
extern UniqueChars
|
||||
DuplicateString(JSContext* cx, const char* s);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(JSContext* cx, const char16_t* s);
|
||||
|
||||
/*
|
||||
* These variants do not report OOMs, you must arrange for OOMs to be reported
|
||||
* yourself.
|
||||
*/
|
||||
extern UniqueChars
|
||||
DuplicateString(const char* s);
|
||||
|
||||
extern UniqueChars
|
||||
DuplicateString(const char* s, size_t n);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(const char16_t* s);
|
||||
|
||||
extern UniqueTwoByteChars
|
||||
DuplicateString(const char16_t* s, size_t n);
|
||||
|
||||
/*
|
||||
* Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
|
||||
* otherwise return the char16_t buffer that was malloc'ed. A null char is
|
||||
* appended.
|
||||
*/
|
||||
extern char16_t*
|
||||
InflateString(JSContext* cx, const char* bytes, size_t length);
|
||||
|
||||
/*
|
||||
* Inflate bytes to JS chars in an existing buffer. 'dst' must be large
|
||||
* enough for 'srclen' char16_t code units. The buffer is NOT null-terminated.
|
||||
*/
|
||||
inline void
|
||||
CopyAndInflateChars(char16_t* dst, const char* src, size_t srclen)
|
||||
{
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = (unsigned char) src[i];
|
||||
}
|
||||
|
||||
inline void
|
||||
CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
|
||||
{
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
|
||||
* 'length chars. The buffer is NOT null-terminated. The destination length
|
||||
* must to be initialized with the buffer size and will contain on return the
|
||||
* number of copied bytes.
|
||||
*/
|
||||
template <typename CharT>
|
||||
extern bool
|
||||
DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
|
||||
size_t charsLength, char* bytes, size_t* length);
|
||||
|
||||
/*
|
||||
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
|
||||
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
|
||||
*/
|
||||
extern uint32_t
|
||||
OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
|
||||
|
||||
extern size_t
|
||||
PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str,
|
||||
uint32_t quote);
|
||||
|
||||
template <typename CharT>
|
||||
extern size_t
|
||||
PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
/*
|
||||
* Write str into buffer escaping any non-printable or non-ASCII character
|
||||
* using \escapes for JS string literals.
|
||||
* Guarantees that a NUL is at the end of the buffer unless size is 0. Returns
|
||||
* the length of the written output, NOT including the NUL. Thus, a return
|
||||
* value of size or more means that the output was truncated. If buffer
|
||||
* is null, just returns the length of the output. If quote is not 0, it must
|
||||
* be a single or double quote character that will quote the output.
|
||||
*/
|
||||
inline size_t
|
||||
PutEscapedString(char* buffer, size_t size, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
size_t n = PutEscapedStringImpl(buffer, size, nullptr, str, quote);
|
||||
|
||||
/* PutEscapedStringImpl can only fail with a file. */
|
||||
MOZ_ASSERT(n != size_t(-1));
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
inline size_t
|
||||
PutEscapedString(char* buffer, size_t bufferSize, const CharT* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
size_t n = PutEscapedStringImpl(buffer, bufferSize, nullptr, chars, length, quote);
|
||||
|
||||
/* PutEscapedStringImpl can only fail with a file. */
|
||||
MOZ_ASSERT(n != size_t(-1));
|
||||
return n;
|
||||
}
|
||||
|
||||
inline bool
|
||||
EscapedStringPrinter(GenericPrinter& out, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
return PutEscapedStringImpl(nullptr, 0, &out, str, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
inline bool
|
||||
EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
return PutEscapedStringImpl(nullptr, 0, &out, chars, length, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write str into file escaping any non-printable or non-ASCII character.
|
||||
* If quote is not 0, it must be a single or double quote character that
|
||||
* will quote the output.
|
||||
*/
|
||||
inline bool
|
||||
FileEscapedString(FILE* fp, JSLinearString* str, uint32_t quote)
|
||||
{
|
||||
Fprinter out(fp);
|
||||
bool res = EscapedStringPrinter(out, str, quote);
|
||||
out.finish();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline bool
|
||||
FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
|
||||
{
|
||||
Fprinter out(fp);
|
||||
bool res = EscapedStringPrinter(out, chars, length, quote);
|
||||
out.finish();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // util_Text_h
|
|
@ -18,6 +18,7 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "util/Text.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
#include "vm/JSCompartment.h"
|
||||
#include "vm/JSScript.h"
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "vm/Scope.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/Stopwatch.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsboolinlines.h"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "builtin/String.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/SymbolType.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "js/UbiNode.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/Text.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "js/Utility.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
#include "vm/Compression.h"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "util/StringBuffer.h"
|
||||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#ifdef DEBUG
|
||||
#include "util/Unicode.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "gc/Policy.h"
|
||||
#include "gc/PublicIterators.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/JSAtom.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSObject.h"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "vm/SharedImmutableStringsCache-inl.h"
|
||||
|
||||
#include "builtin/String.h"
|
||||
#include "util/Text.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "vm/StringType-inl.h"
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
@ -16,14 +17,17 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "gc/Nursery.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "vm/GeckoProfiler.h"
|
||||
|
||||
#include "vm/GeckoProfiler-inl.h"
|
||||
#include "vm/JSCompartment-inl.h"
|
||||
#include "vm/JSContext-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::IsNegativeZero;
|
||||
using mozilla::IsSame;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodEqual;
|
||||
|
@ -756,6 +760,165 @@ JSDependentString::dumpRepresentation(js::GenericPrinter& out, int indent) const
|
|||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
js::EqualChars(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
MOZ_ASSERT(str1->length() == str2->length());
|
||||
|
||||
size_t len = str1->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (str1->hasTwoByteChars()) {
|
||||
if (str2->hasTwoByteChars())
|
||||
return PodEqual(str1->twoByteChars(nogc), str2->twoByteChars(nogc), len);
|
||||
|
||||
return EqualChars(str2->latin1Chars(nogc), str1->twoByteChars(nogc), len);
|
||||
}
|
||||
|
||||
if (str2->hasLatin1Chars())
|
||||
return PodEqual(str1->latin1Chars(nogc), str2->latin1Chars(nogc), len);
|
||||
|
||||
return EqualChars(str1->latin1Chars(nogc), str2->twoByteChars(nogc), len);
|
||||
}
|
||||
|
||||
bool
|
||||
js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
|
||||
{
|
||||
MOZ_ASSERT(start + pat->length() <= text->length());
|
||||
|
||||
size_t patLen = pat->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (text->hasLatin1Chars()) {
|
||||
const Latin1Char* textChars = text->latin1Chars(nogc) + start;
|
||||
if (pat->hasLatin1Chars())
|
||||
return PodEqual(textChars, pat->latin1Chars(nogc), patLen);
|
||||
|
||||
return EqualChars(textChars, pat->twoByteChars(nogc), patLen);
|
||||
}
|
||||
|
||||
const char16_t* textChars = text->twoByteChars(nogc) + start;
|
||||
if (pat->hasTwoByteChars())
|
||||
return PodEqual(textChars, pat->twoByteChars(nogc), patLen);
|
||||
|
||||
return EqualChars(pat->latin1Chars(nogc), textChars, patLen);
|
||||
}
|
||||
|
||||
bool
|
||||
js::EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result)
|
||||
{
|
||||
if (str1 == str2) {
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t length1 = str1->length();
|
||||
if (length1 != str2->length()) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSLinearString* linear1 = str1->ensureLinear(cx);
|
||||
if (!linear1)
|
||||
return false;
|
||||
JSLinearString* linear2 = str2->ensureLinear(cx);
|
||||
if (!linear2)
|
||||
return false;
|
||||
|
||||
*result = EqualChars(linear1, linear2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::EqualStrings(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
if (str1 == str2)
|
||||
return true;
|
||||
|
||||
size_t length1 = str1->length();
|
||||
if (length1 != str2->length())
|
||||
return false;
|
||||
|
||||
return EqualChars(str1, str2);
|
||||
}
|
||||
|
||||
int32_t
|
||||
js::CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2)
|
||||
{
|
||||
AutoCheckCannotGC nogc;
|
||||
return s2->hasLatin1Chars()
|
||||
? CompareChars(s1, len1, s2->latin1Chars(nogc), s2->length())
|
||||
: CompareChars(s1, len1, s2->twoByteChars(nogc), s2->length());
|
||||
}
|
||||
|
||||
static int32_t
|
||||
CompareStringsImpl(JSLinearString* str1, JSLinearString* str2)
|
||||
{
|
||||
size_t len1 = str1->length();
|
||||
size_t len2 = str2->length();
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
if (str1->hasLatin1Chars()) {
|
||||
const Latin1Char* chars1 = str1->latin1Chars(nogc);
|
||||
return str2->hasLatin1Chars()
|
||||
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
|
||||
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
|
||||
}
|
||||
|
||||
const char16_t* chars1 = str1->twoByteChars(nogc);
|
||||
return str2->hasLatin1Chars()
|
||||
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
|
||||
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
|
||||
}
|
||||
|
||||
bool
|
||||
js::CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result)
|
||||
{
|
||||
MOZ_ASSERT(str1);
|
||||
MOZ_ASSERT(str2);
|
||||
|
||||
if (str1 == str2) {
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSLinearString* linear1 = str1->ensureLinear(cx);
|
||||
if (!linear1)
|
||||
return false;
|
||||
|
||||
JSLinearString* linear2 = str2->ensureLinear(cx);
|
||||
if (!linear2)
|
||||
return false;
|
||||
|
||||
*result = CompareStringsImpl(linear1, linear2);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t
|
||||
js::CompareAtoms(JSAtom* atom1, JSAtom* atom2)
|
||||
{
|
||||
return CompareStringsImpl(atom1, atom2);
|
||||
}
|
||||
|
||||
bool
|
||||
js::StringEqualsAscii(JSLinearString* str, const char* asciiBytes)
|
||||
{
|
||||
size_t length = strlen(asciiBytes);
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i != length; ++i)
|
||||
MOZ_ASSERT(unsigned(asciiBytes[i]) <= 127);
|
||||
#endif
|
||||
if (length != str->length())
|
||||
return false;
|
||||
|
||||
const Latin1Char* latin1 = reinterpret_cast<const Latin1Char*>(asciiBytes);
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
return str->hasLatin1Chars()
|
||||
? PodEqual(latin1, str->latin1Chars(nogc), length)
|
||||
: EqualChars(latin1, str->twoByteChars(nogc), length);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
/* static */ bool
|
||||
JSFlatString::isIndexSlow(const CharT* s, size_t length, uint32_t* indexp)
|
||||
|
@ -1732,3 +1895,146 @@ JSString::fillWithRepresentatives(JSContext* cx, HandleArrayObject array)
|
|||
MOZ_ASSERT(index == 22);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*** Conversions *********************************************************************************/
|
||||
|
||||
const char*
|
||||
js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
|
||||
{
|
||||
RootedValue v(cx, vArg);
|
||||
JSString* str;
|
||||
if (asSource)
|
||||
str = ValueToSource(cx, v);
|
||||
else
|
||||
str = ToString<CanGC>(cx, v);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
str = QuoteString(cx, str, 0);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return bytes->encodeLatin1(cx, str);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSString*
|
||||
js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
|
||||
{
|
||||
/* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
|
||||
MOZ_ASSERT(!arg.isString());
|
||||
|
||||
Value v = arg;
|
||||
if (!v.isPrimitive()) {
|
||||
MOZ_ASSERT(!cx->helperThread());
|
||||
if (!allowGC)
|
||||
return nullptr;
|
||||
RootedValue v2(cx, v);
|
||||
if (!ToPrimitive(cx, JSTYPE_STRING, &v2))
|
||||
return nullptr;
|
||||
v = v2;
|
||||
}
|
||||
|
||||
JSString* str;
|
||||
if (v.isString()) {
|
||||
str = v.toString();
|
||||
} else if (v.isInt32()) {
|
||||
str = Int32ToString<allowGC>(cx, v.toInt32());
|
||||
} else if (v.isDouble()) {
|
||||
str = NumberToString<allowGC>(cx, v.toDouble());
|
||||
} else if (v.isBoolean()) {
|
||||
str = BooleanToString(cx, v.toBoolean());
|
||||
} else if (v.isNull()) {
|
||||
str = cx->names().null;
|
||||
} else if (v.isSymbol()) {
|
||||
MOZ_ASSERT(!cx->helperThread());
|
||||
if (allowGC) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SYMBOL_TO_STRING);
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
str = cx->names().undefined;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template JSString*
|
||||
js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
|
||||
|
||||
template JSString*
|
||||
js::ToStringSlow<NoGC>(JSContext* cx, const Value& arg);
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
js::ToStringSlow(JSContext* cx, HandleValue v)
|
||||
{
|
||||
return ToStringSlow<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
static JSString*
|
||||
SymbolToSource(JSContext* cx, Symbol* symbol)
|
||||
{
|
||||
RootedString desc(cx, symbol->description());
|
||||
SymbolCode code = symbol->code();
|
||||
if (code != SymbolCode::InSymbolRegistry && code != SymbolCode::UniqueSymbol) {
|
||||
// Well-known symbol.
|
||||
MOZ_ASSERT(uint32_t(code) < JS::WellKnownSymbolLimit);
|
||||
return desc;
|
||||
}
|
||||
|
||||
StringBuffer buf(cx);
|
||||
if (code == SymbolCode::InSymbolRegistry ? !buf.append("Symbol.for(") : !buf.append("Symbol("))
|
||||
return nullptr;
|
||||
if (desc) {
|
||||
desc = StringToSource(cx, desc);
|
||||
if (!desc || !buf.append(desc))
|
||||
return nullptr;
|
||||
}
|
||||
if (!buf.append(')'))
|
||||
return nullptr;
|
||||
return buf.finishString();
|
||||
}
|
||||
|
||||
JSString*
|
||||
js::ValueToSource(JSContext* cx, HandleValue v)
|
||||
{
|
||||
if (!CheckRecursionLimit(cx))
|
||||
return nullptr;
|
||||
assertSameCompartment(cx, v);
|
||||
|
||||
if (v.isUndefined())
|
||||
return cx->names().void0;
|
||||
if (v.isString())
|
||||
return StringToSource(cx, v.toString());
|
||||
if (v.isSymbol())
|
||||
return SymbolToSource(cx, v.toSymbol());
|
||||
if (v.isPrimitive()) {
|
||||
/* Special case to preserve negative zero, _contra_ toString. */
|
||||
if (v.isDouble() && IsNegativeZero(v.toDouble())) {
|
||||
static const Latin1Char negativeZero[] = {'-', '0'};
|
||||
|
||||
return NewStringCopyN<CanGC>(cx, negativeZero, mozilla::ArrayLength(negativeZero));
|
||||
}
|
||||
return ToString<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
RootedValue fval(cx);
|
||||
RootedObject obj(cx, &v.toObject());
|
||||
if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))
|
||||
return nullptr;
|
||||
if (IsCallable(fval)) {
|
||||
RootedValue v(cx);
|
||||
if (!js::Call(cx, fval, obj, &v))
|
||||
return nullptr;
|
||||
|
||||
return ToString<CanGC>(cx, v);
|
||||
}
|
||||
|
||||
return ObjectToSource(cx, obj);
|
||||
}
|
||||
|
||||
JSString*
|
||||
js::StringToSource(JSContext* cx, JSString* str)
|
||||
{
|
||||
return QuoteString(cx, str, '"');
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "gc/Rooting.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
#include "util/Text.h"
|
||||
#include "vm/Printer.h"
|
||||
|
||||
class JSDependentString;
|
||||
|
@ -1491,6 +1491,137 @@ NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n, const JSStrin
|
|||
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
extern JSString*
|
||||
ConcatStrings(JSContext* cx,
|
||||
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
||||
typename MaybeRooted<JSString*, allowGC>::HandleType right);
|
||||
|
||||
/*
|
||||
* Test if strings are equal. The caller can call the function even if str1
|
||||
* or str2 are not GC-allocated things.
|
||||
*/
|
||||
extern bool
|
||||
EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result);
|
||||
|
||||
/* Use the infallible method instead! */
|
||||
extern bool
|
||||
EqualStrings(JSContext* cx, JSLinearString* str1, JSLinearString* str2, bool* result) = delete;
|
||||
|
||||
/* EqualStrings is infallible on linear strings. */
|
||||
extern bool
|
||||
EqualStrings(JSLinearString* str1, JSLinearString* str2);
|
||||
|
||||
/**
|
||||
* Compare two strings that are known to be the same length.
|
||||
* Exposed for the JITs; for ordinary uses, EqualStrings() is more sensible.
|
||||
*
|
||||
* Precondition: str1->length() == str2->length().
|
||||
*/
|
||||
extern bool
|
||||
EqualChars(JSLinearString* str1, JSLinearString* str2);
|
||||
|
||||
/*
|
||||
* Return less than, equal to, or greater than zero depending on whether
|
||||
* `s1[0..len1]` is less than, equal to, or greater than `s2`.
|
||||
*/
|
||||
extern int32_t
|
||||
CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2);
|
||||
|
||||
/*
|
||||
* Compare two strings, like CompareChars, but store the result in `*result`.
|
||||
* This flattens the strings and therefore can fail.
|
||||
*/
|
||||
extern bool
|
||||
CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result);
|
||||
|
||||
/*
|
||||
* Same as CompareStrings but for atoms. Don't use this to just test
|
||||
* for equality; use this when you need an ordering on atoms.
|
||||
*/
|
||||
extern int32_t
|
||||
CompareAtoms(JSAtom* atom1, JSAtom* atom2);
|
||||
|
||||
/*
|
||||
* Return true if the string matches the given sequence of ASCII bytes.
|
||||
*/
|
||||
extern bool
|
||||
StringEqualsAscii(JSLinearString* str, const char* asciiBytes);
|
||||
|
||||
extern int
|
||||
StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
|
||||
|
||||
/**
|
||||
* Return true if the string contains a pattern at |start|.
|
||||
*
|
||||
* Precondition: `text` is long enough that this might be true;
|
||||
* that is, it has at least `start + pat->length()` characters.
|
||||
*/
|
||||
extern bool
|
||||
HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start);
|
||||
|
||||
/*
|
||||
* Computes |str|'s substring for the range [beginInt, beginInt + lengthInt).
|
||||
* Negative, overlarge, swapped, etc. |beginInt| and |lengthInt| are forbidden
|
||||
* and constitute API misuse.
|
||||
*/
|
||||
JSString*
|
||||
SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt);
|
||||
|
||||
|
||||
/*** Conversions *********************************************************************************/
|
||||
|
||||
/*
|
||||
* Convert a value to a printable C string.
|
||||
*/
|
||||
extern const char*
|
||||
ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
|
||||
|
||||
/*
|
||||
* Convert a non-string value to a string, returning null after reporting an
|
||||
* error, otherwise returning a new string reference.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
extern JSString*
|
||||
ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
|
||||
|
||||
/*
|
||||
* Convert the given value to a string. This method includes an inline
|
||||
* fast-path for the case where the value is already a string; if the value is
|
||||
* known not to be a string, use ToStringSlow instead.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSString*
|
||||
ToString(JSContext* cx, JS::HandleValue v)
|
||||
{
|
||||
if (v.isString())
|
||||
return v.toString();
|
||||
return ToStringSlow<allowGC>(cx, v);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function implements E-262-3 section 9.8, toString. Convert the given
|
||||
* value to a string of characters appended to the given buffer. On error, the
|
||||
* passed buffer may have partial results appended.
|
||||
*/
|
||||
inline bool
|
||||
ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
|
||||
|
||||
/*
|
||||
* Convert a value to its source expression, returning null after reporting
|
||||
* an error, otherwise returning a new string reference.
|
||||
*/
|
||||
extern JSString*
|
||||
ValueToSource(JSContext* cx, HandleValue v);
|
||||
|
||||
/*
|
||||
* Convert a JSString to its source expression; returns null after reporting an
|
||||
* error, otherwise returns a new string reference. No Handle needed since the
|
||||
* input is dead after the GC.
|
||||
*/
|
||||
extern JSString*
|
||||
StringToSource(JSContext* cx, JSString* str);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
// Addon IDs are interned atoms which are never destroyed. This detail is
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "js/UniquePtr.h"
|
||||
#include "threading/LockGuard.h"
|
||||
#include "threading/Thread.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#ifndef DEFAULT_TRACE_LOG_DIR
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "vm/TraceLoggingTypes.h"
|
||||
|
||||
#include "vm/StringType.h"
|
||||
|
||||
class JSLinearString;
|
||||
|
||||
uint32_t
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "js/UbiNodeCensus.h"
|
||||
|
||||
#include "util/Text.h"
|
||||
#include "vm/JSCompartment.h"
|
||||
#include "vm/JSContext.h"
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
|
||||
#include "builtin/String.h"
|
||||
#include "util/Text.h"
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "js/Printf.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/ErrorReporting.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/Time.h"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "jit/ProcessExecutableMemory.h"
|
||||
#include "util/Text.h"
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmGenerator.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "jit/ExecutableAllocator.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "wasm/WasmBinaryToText.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "util/Text.h"
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
#include "wasm/WasmCompile.h"
|
||||
#include "wasm/WasmIonCompile.h"
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "jit/JitOptions.h"
|
||||
#include "js/Printf.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче