nsresult SVGPointList::SetValueFromString(const nsAString& aValue) { // The spec says that the list is parsed and accepted up to the first error // encountered, so we must call CopyFrom even if an error occurs. We still // want to throw any error code from setAttribute if there's a problem // though, so we must take care to return any error code. nsresult rv = NS_OK; SVGPointList temp; nsCharSeparatedTokenizerTemplate<IsSVGWhitespace> tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL); while (tokenizer.hasMoreTokens()) { const nsAString& token = tokenizer.nextToken(); RangedPtr<const PRUnichar> iter = SVGContentUtils::GetStartRangedPtr(token); const RangedPtr<const PRUnichar> end = SVGContentUtils::GetEndRangedPtr(token); float x; if (!SVGContentUtils::ParseNumber(iter, end, x)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } float y; if (iter == end) { if (!tokenizer.hasMoreTokens() || !SVGContentUtils::ParseNumber(tokenizer.nextToken(), y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } } else { // It's possible for the token to be 10-30 which has // no separator but needs to be parsed as 10, -30 const nsAString& leftOver = Substring(iter.get(), end.get()); if (leftOver[0] != '-' || !SVGContentUtils::ParseNumber(leftOver, y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } } temp.AppendItem(SVGPoint(x, y)); } if (tokenizer.separatorAfterCurrentToken()) { rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma } nsresult rv2 = CopyFrom(temp); if (NS_FAILED(rv2)) { return rv2; // prioritize OOM error code over syntax errors } return rv; }
bool js::IndexToIdSlow(ExclusiveContext *cx, uint32_t index, MutableHandleId idp) { MOZ_ASSERT(index > JSID_INT_MAX); char16_t buf[UINT32_CHAR_BUFFER_LENGTH]; RangedPtr<char16_t> end(ArrayEnd(buf), buf, ArrayEnd(buf)); RangedPtr<char16_t> start = BackfillIndexInCharBuffer(index, end); JSAtom *atom = AtomizeChars(cx, start.get(), end - start); if (!atom) return false; idp.set(JSID_FROM_BITS((size_t)atom)); return true; }
bool js::IndexToIdSlow(JSContext *cx, uint32_t index, typename MaybeRooted<jsid, allowGC>::MutableHandleType idp) { JS_ASSERT(index > JSID_INT_MAX); jschar buf[UINT32_CHAR_BUFFER_LENGTH]; RangedPtr<jschar> end(ArrayEnd(buf), buf, ArrayEnd(buf)); RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end); JSAtom *atom = AtomizeChars<allowGC>(cx, start.get(), end - start); if (!atom) return false; idp.set(JSID_FROM_BITS((size_t)atom)); return true; }
static bool GetValueFromString(const nsAString& aString, float& aValue, uint16_t* aUnitType) { RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString); const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(aString); if (!SVGContentUtils::ParseNumber(iter, end, aValue)) { return false; } const nsAString& units = Substring(iter.get(), end.get()); *aUnitType = GetUnitTypeForString(units); return IsValidUnitType(*aUnitType); }
bool IndexToIdSlow(JSContext *cx, uint32 index, jsid *idp) { JS_ASSERT(index > JSID_INT_MAX); jschar buf[UINT32_CHAR_BUFFER_LENGTH]; RangedPtr<jschar> end(buf + JS_ARRAY_LENGTH(buf), buf, buf + JS_ARRAY_LENGTH(buf)); RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end); JSAtom *atom = js_AtomizeChars(cx, start.get(), end - start); if (!atom) return false; *idp = ATOM_TO_JSID(atom); JS_ASSERT(js_CheckForStringIndex(*idp) == *idp); return true; }
bool SVGLength::SetValueFromString(const nsAString &aString) { RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString); const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(aString); float value; if (!SVGContentUtils::ParseNumber(iter, end, value)) { return false; } const nsAString& units = Substring(iter.get(), end.get()); uint16_t unitType = GetUnitTypeForString(units); if (!IsValidUnitType(unitType)) { return false; } mValue = value; mUnit = uint8_t(unitType); return true; }
static bool GetValueFromString(const nsAString& aString, bool aPercentagesAllowed, float& aValue) { RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString); const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(aString); if (!SVGContentUtils::ParseNumber(iter, end, aValue)) { return false; } if (aPercentagesAllowed) { const nsAString& units = Substring(iter.get(), end.get()); if (units.EqualsLiteral("%")) { aValue /= 100; return true; } } return iter == end; }
JSONParser::Token JSONParser::readNumber() { JS_ASSERT(current < end); JS_ASSERT(JS7_ISDEC(*current) || *current == '-'); /* * JSONNumber: * /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/ */ bool negative = *current == '-'; /* -? */ if (negative && ++current == end) { error("no number after minus sign"); return token(Error); } const RangedPtr<const jschar> digitStart = current; /* 0|[1-9][0-9]+ */ if (!JS7_ISDEC(*current)) { error("unexpected non-digit"); return token(Error); } if (*current++ != '0') { for (; current < end; current++) { if (!JS7_ISDEC(*current)) break; } } /* Fast path: no fractional or exponent part. */ if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) { TwoByteChars chars(digitStart.get(), current - digitStart); if (chars.length() < strlen("9007199254740992")) { // If the decimal number is shorter than the length of 2**53, (the // largest number a double can represent with integral precision), // parse it using a decimal-only parser. This comparison is // conservative but faster than a fully-precise check. double d = ParseDecimalNumber(chars); return numberToken(negative ? -d : d); } double d; const jschar *dummy; if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d)) return token(OOM); JS_ASSERT(current == dummy); return numberToken(negative ? -d : d); } /* (\.[0-9]+)? */ if (current < end && *current == '.') { if (++current == end) { error("missing digits after decimal point"); return token(Error); } if (!JS7_ISDEC(*current)) { error("unterminated fractional number"); return token(Error); } while (++current < end) { if (!JS7_ISDEC(*current)) break; } } /* ([eE][\+\-]?[0-9]+)? */ if (current < end && (*current == 'e' || *current == 'E')) { if (++current == end) { error("missing digits after exponent indicator"); return token(Error); } if (*current == '+' || *current == '-') { if (++current == end) { error("missing digits after exponent sign"); return token(Error); } } if (!JS7_ISDEC(*current)) { error("exponent part is missing a number"); return token(Error); } while (++current < end) { if (!JS7_ISDEC(*current)) break; } } double d; const jschar *finish; if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d)) return token(OOM); JS_ASSERT(current == finish); return numberToken(negative ? -d : d); }
JSONParser::Token JSONParser::readString() { JS_ASSERT(current < end); JS_ASSERT(*current == '"'); /* * JSONString: * /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/ */ if (++current == end) { error("unterminated string literal"); return token(Error); } /* * Optimization: if the source contains no escaped characters, create the * string directly from the source text. */ RangedPtr<const jschar> start = current; for (; current < end; current++) { if (*current == '"') { size_t length = current - start; current++; JSFlatString *str = (ST == JSONParser::PropertyName) ? AtomizeChars(cx, start.get(), length) : js_NewStringCopyN<CanGC>(cx, start.get(), length); if (!str) return token(OOM); return stringToken(str); } if (*current == '\\') break; if (*current <= 0x001F) { error("bad control character in string literal"); return token(Error); } } /* * Slow case: string contains escaped characters. Copy a maximal sequence * of unescaped characters into a temporary buffer, then an escaped * character, and repeat until the entire string is consumed. */ StringBuffer buffer(cx); do { if (start < current && !buffer.append(start.get(), current.get())) return token(OOM); if (current >= end) break; jschar c = *current++; if (c == '"') { JSFlatString *str = (ST == JSONParser::PropertyName) ? buffer.finishAtom() : buffer.finishString(); if (!str) return token(OOM); return stringToken(str); } if (c != '\\') { --current; error("bad character in string literal"); return token(Error); } if (current >= end) break; switch (*current++) { case '"': c = '"'; break; case '/': c = '/'; break; case '\\': c = '\\'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'u': if (end - current < 4 || !(JS7_ISHEX(current[0]) && JS7_ISHEX(current[1]) && JS7_ISHEX(current[2]) && JS7_ISHEX(current[3]))) { // Point to the first non-hexadecimal character (which may be // missing). if (current == end || !JS7_ISHEX(current[0])) ; // already at correct location else if (current + 1 == end || !JS7_ISHEX(current[1])) current += 1; else if (current + 2 == end || !JS7_ISHEX(current[2])) current += 2; else if (current + 3 == end || !JS7_ISHEX(current[3])) current += 3; else MOZ_ASSUME_UNREACHABLE("logic error determining first erroneous character"); error("bad Unicode escape"); return token(Error); } c = (JS7_UNHEX(current[0]) << 12) | (JS7_UNHEX(current[1]) << 8) | (JS7_UNHEX(current[2]) << 4) | (JS7_UNHEX(current[3])); current += 4; break; default: current--; error("bad escaped character"); return token(Error); } if (!buffer.append(c)) return token(OOM); start = current; for (; current < end; current++) { if (*current == '"' || *current == '\\' || *current <= 0x001F) break; } } while (current < end); error("unterminated string"); return token(Error); }
JSONParser::Token JSONParser::readString() { JS_ASSERT(current < end); JS_ASSERT(*current == '"'); /* * JSONString: * /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/ */ if (++current == end) { error("unterminated string literal"); return token(Error); } /* * Optimization: if the source contains no escaped characters, create the * string directly from the source text. */ RangedPtr<const jschar> start = current; for (; current < end; current++) { if (*current == '"') { size_t length = current - start; current++; JSFlatString *str = (ST == JSONParser::PropertyName) ? AtomizeChars(cx, start.get(), length) : js_NewStringCopyN(cx, start.get(), length); if (!str) return token(OOM); return stringToken(str); } if (*current == '\\') break; if (*current <= 0x001F) { error("bad control character in string literal"); return token(Error); } } /* * Slow case: string contains escaped characters. Copy a maximal sequence * of unescaped characters into a temporary buffer, then an escaped * character, and repeat until the entire string is consumed. */ StringBuffer buffer(cx); do { if (start < current && !buffer.append(start.get(), current.get())) return token(OOM); if (current >= end) break; jschar c = *current++; if (c == '"') { UnrootedFlatString str = (ST == JSONParser::PropertyName) ? UnrootedFlatString(buffer.finishAtom()) : buffer.finishString(); if (!str) return token(OOM); return stringToken(str); } if (c != '\\') { error("bad character in string literal"); return token(Error); } if (current >= end) break; switch (*current++) { case '"': c = '"'; break; case '/': c = '/'; break; case '\\': c = '\\'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'u': if (end - current < 4) { error("bad Unicode escape"); return token(Error); } if (JS7_ISHEX(current[0]) && JS7_ISHEX(current[1]) && JS7_ISHEX(current[2]) && JS7_ISHEX(current[3])) { c = (JS7_UNHEX(current[0]) << 12) | (JS7_UNHEX(current[1]) << 8) | (JS7_UNHEX(current[2]) << 4) | (JS7_UNHEX(current[3])); current += 4; break; } /* FALL THROUGH */ default: error("bad escaped character"); return token(Error); } if (!buffer.append(c)) return token(OOM); start = current; for (; current < end; current++) { if (*current == '"' || *current == '\\' || *current <= 0x001F) break; } } while (current < end); error("unterminated string"); return token(Error); }
JSONParser::Token JSONParser::readNumber() { JS_ASSERT(current < end); JS_ASSERT(JS7_ISDEC(*current) || *current == '-'); /* * JSONNumber: * /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/ */ bool negative = *current == '-'; /* -? */ if (negative && ++current == end) { error("no number after minus sign"); return token(Error); } const RangedPtr<const jschar> digitStart = current; /* 0|[1-9][0-9]+ */ if (!JS7_ISDEC(*current)) { error("unexpected non-digit"); return token(Error); } if (*current++ != '0') { for (; current < end; current++) { if (!JS7_ISDEC(*current)) break; } } /* Fast path: no fractional or exponent part. */ if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) { const jschar *dummy; double d; if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d)) return token(OOM); JS_ASSERT(current == dummy); return numberToken(negative ? -d : d); } /* (\.[0-9]+)? */ if (current < end && *current == '.') { if (++current == end) { error("missing digits after decimal point"); return token(Error); } if (!JS7_ISDEC(*current)) { error("unterminated fractional number"); return token(Error); } while (++current < end) { if (!JS7_ISDEC(*current)) break; } } /* ([eE][\+\-]?[0-9]+)? */ if (current < end && (*current == 'e' || *current == 'E')) { if (++current == end) { error("missing digits after exponent indicator"); return token(Error); } if (*current == '+' || *current == '-') { if (++current == end) { error("missing digits after exponent sign"); return token(Error); } } if (!JS7_ISDEC(*current)) { error("exponent part is missing a number"); return token(Error); } while (++current < end) { if (!JS7_ISDEC(*current)) break; } } double d; const jschar *finish; if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d)) return token(OOM); JS_ASSERT(current == finish); return numberToken(negative ? -d : d); }