// Parses a date with the format YYYY[-MM[-DD]]. // Year parsing is lenient, allows any number of digits, and +/-. // Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string. static char* parseES5DatePortion(const char* currentPosition, int& year, long& month, long& day) { char* postParsePosition; // This is a bit more lenient on the year string than ES5 specifies: // instead of restricting to 4 digits (or 6 digits with mandatory +/-), // it accepts any integer value. Consider this an implementation fallback. if (!parseInt(currentPosition, &postParsePosition, 10, &year)) return 0; // Check for presence of -MM portion. if (*postParsePosition != '-') return postParsePosition; currentPosition = postParsePosition + 1; if (!isASCIIDigit(*currentPosition)) return 0; if (!parseLong(currentPosition, &postParsePosition, 10, &month)) return 0; if ((postParsePosition - currentPosition) != 2) return 0; // Check for presence of -DD portion. if (*postParsePosition != '-') return postParsePosition; currentPosition = postParsePosition + 1; if (!isASCIIDigit(*currentPosition)) return 0; if (!parseLong(currentPosition, &postParsePosition, 10, &day)) return 0; if ((postParsePosition - currentPosition) != 2) return 0; return postParsePosition; }
double WebVTTParser::collectTimeStamp(const String& line, unsigned* position) { // 4.8.10.13.3 Collect a WebVTT timestamp. // 1-4 - Initial checks, let most significant units be minutes. enum Mode { minutes, hours }; Mode mode = minutes; if (*position >= line.length() || !isASCIIDigit(line[*position])) return malformedTime; // 5-6 - Collect a sequence of characters that are 0-9. String digits1 = collectDigits(line, position); int value1 = digits1.toInt(); // 7 - If not 2 characters or value is greater than 59, interpret as hours. if (digits1.length() != 2 || value1 > 59) mode = hours; // 8-12 - Collect the next sequence of 0-9 after ':' (must be 2 chars). if (*position >= line.length() || line[(*position)++] != ':') return malformedTime; if (*position >= line.length() || !isASCIIDigit(line[(*position)])) return malformedTime; String digits2 = collectDigits(line, position); int value2 = digits2.toInt(); if (digits2.length() != 2) return malformedTime; // 13 - Detect whether this timestamp includes hours. int value3; if (mode == hours || (*position < line.length() && line[*position] == ':')) { if (*position >= line.length() || line[(*position)++] != ':') return malformedTime; if (*position >= line.length() || !isASCIIDigit(line[*position])) return malformedTime; String digits3 = collectDigits(line, position); if (digits3.length() != 2) return malformedTime; value3 = digits3.toInt(); } else { value3 = value2; value2 = value1; value1 = 0; } // 14-19 - Collect next sequence of 0-9 after '.' (must be 3 chars). if (*position >= line.length() || line[(*position)++] != '.') return malformedTime; if (*position >= line.length() || !isASCIIDigit(line[*position])) return malformedTime; String digits4 = collectDigits(line, position); if (digits4.length() != 3) return malformedTime; int value4 = digits4.toInt(); if (value2 > 59 || value3 > 59) return malformedTime; // 20-21 - Calculate result. return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (value4 * secondsPerMillisecond); }
inline bool SearchBuffer::isWordStartMatch(size_t start, size_t length) const { ASSERT(m_options & AtWordStarts); if (!start) return true; int size = m_buffer.size(); int offset = start; UChar32 firstCharacter; U16_GET(m_buffer.data(), 0, offset, size, firstCharacter); if (m_options & TreatMedialCapitalAsWordStart) { UChar32 previousCharacter; U16_PREV(m_buffer.data(), 0, offset, previousCharacter); if (isSeparator(firstCharacter)) { // The start of a separator run is a word start (".org" in "webkit.org"). if (!isSeparator(previousCharacter)) return true; } else if (isASCIIUpper(firstCharacter)) { // The start of an uppercase run is a word start ("Kit" in "WebKit"). if (!isASCIIUpper(previousCharacter)) return true; // The last character of an uppercase run followed by a non-separator, non-digit // is a word start ("Request" in "XMLHTTPRequest"). offset = start; U16_FWD_1(m_buffer.data(), offset, size); UChar32 nextCharacter = 0; if (offset < size) U16_GET(m_buffer.data(), 0, offset, size, nextCharacter); if (!isASCIIUpper(nextCharacter) && !isASCIIDigit(nextCharacter) && !isSeparator(nextCharacter)) return true; } else if (isASCIIDigit(firstCharacter)) { // The start of a digit run is a word start ("2" in "WebKit2"). if (!isASCIIDigit(previousCharacter)) return true; } else if (isSeparator(previousCharacter) || isASCIIDigit(previousCharacter)) { // The start of a non-separator, non-uppercase, non-digit run is a word start, // except after an uppercase. ("org" in "webkit.org", but not "ore" in "WebCore"). return true; } } // Chinese and Japanese lack word boundary marks, and there is no clear agreement on what constitutes // a word, so treat the position before any CJK character as a word start. if (Character::isCJKIdeographOrSymbol(firstCharacter)) return true; size_t wordBreakSearchStart = start + length; while (wordBreakSearchStart > start) wordBreakSearchStart = findNextWordFromIndex(m_buffer.data(), m_buffer.size(), wordBreakSearchStart, false /* backwards */); if (wordBreakSearchStart != start) return false; if (m_options & WholeWord) return static_cast<int>(start + length) == findWordEndBoundary(m_buffer.data(), m_buffer.size(), wordBreakSearchStart); return true; }
// http://www.w3.org/TR/css3-syntax/#starts-with-a-number bool CSSTokenizer::nextCharsAreNumber(UChar first) { UChar second = m_input.nextInputChar(); if (isASCIIDigit(first)) return true; if (first == '+' || first == '-') return ((isASCIIDigit(second)) || (second == '.' && isASCIIDigit(m_input.peek(1)))); if (first =='.') return (isASCIIDigit(second)); return false; }
static inline bool isTenthAlpha(const CharacterType* string, const int length) { // "0.X" if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2])) return true; // ".X" if (length == 2 && string[0] == '.' && isASCIIDigit(string[1])) return true; return false; }
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers bool parseHTMLInteger(const String& input, int& value) { // Step 1 // Step 2 const UChar* position = input.characters(); const UChar* end = position + input.length(); // Step 3 int sign = 1; // Step 4 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 5 if (position == end) return false; ASSERT(position < end); // Step 6 if (*position == '-') { sign = -1; ++position; } else if (*position == '+') ++position; if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok); return ok; }
static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator) { int length = end - string; if (length < 1) return 0; bool decimalMarkSeen = false; int processedLength = 0; for (int i = 0; i < length; ++i) { if (string[i] == terminator) { processedLength = i; break; } if (!isASCIIDigit(string[i])) { if (!decimalMarkSeen && string[i] == '.') decimalMarkSeen = true; else return 0; } } if (decimalMarkSeen && processedLength == 1) return 0; return processedLength; }
double Value::toNumber() const { switch (m_type) { case NodeSetValue: return Value(toString()).toNumber(); case NumberValue: return m_number; case StringValue: { const String& str = m_data->m_string.simplifyWhiteSpace(); // String::toDouble() supports exponential notation, which is not // allowed in XPath. unsigned len = str.length(); for (unsigned i = 0; i < len; ++i) { UChar c = str[i]; if (!isASCIIDigit(c) && c != '.' && c != '-') return std::numeric_limits<double>::quiet_NaN(); } bool canConvert; double value = str.toDouble(&canConvert); if (canConvert) return value; return std::numeric_limits<double>::quiet_NaN(); } case BooleanValue: return m_bool; } ASSERT_NOT_REACHED(); return 0.0; }
bool LocaleWin::isLocalizedDigit(UChar ch) { String normalizedDigit = convertFromLocalizedNumber(String(&ch, 1)); if (normalizedDigit.length() != 1) return false; return isASCIIDigit(normalizedDigit[0]); }
bool parseToDoubleForNumberType(const String& string, double* result) { // See HTML5 2.4.4.3 `Real numbers.' // String::toDouble() accepts leading + and whitespace characters, which are not valid here. UChar firstCharacter = string[0]; if (firstCharacter != '-' && !isASCIIDigit(firstCharacter)) return false; bool valid = false; double value = string.toDouble(&valid); if (!valid) return false; // NaN and infinity are considered valid by String::toDouble, but not valid here. if (!isfinite(value)) return false; if (result) { // The following expression converts -0 to +0. *result = value ? value : 0; } return true; }
String WebVTTParser::collectDigits(const String& input, unsigned* position) { StringBuilder digits; while (*position < input.length() && isASCIIDigit(input[*position])) digits.append(input[(*position)++]); return digits.toString(); }
// https://tools.ietf.org/html/rfc6455#section-4.1 // "The HTTP version MUST be at least 1.1." static inline bool headerHasValidHTTPVersion(StringView httpStatusLine) { const char* httpVersionStaticPreambleLiteral = "HTTP/"; StringView httpVersionStaticPreamble(reinterpret_cast<const LChar*>(httpVersionStaticPreambleLiteral), strlen(httpVersionStaticPreambleLiteral)); if (!httpStatusLine.startsWith(httpVersionStaticPreamble)) return false; // Check that there is a version number which should be at least three characters after "HTTP/" unsigned preambleLength = httpVersionStaticPreamble.length(); if (httpStatusLine.length() < preambleLength + 3) return false; auto dotPosition = httpStatusLine.find('.', preambleLength); if (dotPosition == notFound) return false; StringView majorVersionView = httpStatusLine.substring(preambleLength, dotPosition - preambleLength); bool isValid; int majorVersion = majorVersionView.toIntStrict(isValid); if (!isValid) return false; unsigned minorVersionLength; unsigned charactersLeftAfterDotPosition = httpStatusLine.length() - dotPosition; for (minorVersionLength = 1; minorVersionLength < charactersLeftAfterDotPosition; minorVersionLength++) { if (!isASCIIDigit(httpStatusLine[dotPosition + minorVersionLength])) break; } int minorVersion = (httpStatusLine.substring(dotPosition + 1, minorVersionLength)).toIntStrict(isValid); if (!isValid) return false; return (majorVersion >= 1 && minorVersion >= 1) || majorVersion >= 2; }
bool parseToDoubleForNumberType(const String& string, double* result) { // See HTML5 2.4.4.3 `Real numbers.' // String::toDouble() accepts leading + and whitespace characters, which are not valid here. // UChar firstCharacter = string[0]; Ricardo: comentando para poner lo sig char string1[] = ""; UChar firstCharacter = string1[0]; if (firstCharacter != '-' && !isASCIIDigit(firstCharacter)) return false; bool valid = false; double value = string.toDouble(&valid); if (!valid) return false; // NaN and infinity are considered valid by String::toDouble, but not valid here. if (!isfinite(value)) return false; // Numbers are considered finite IEEE 754 single-precision floating point values. // See HTML5 2.4.4.3 `Real numbers.' if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max()) return false; if (result) { // The following expression converts -0 to +0. *result = value ? value : 0; } return true; }
void ParsedCookie::setMaxAge(const String& maxAge) { // According to the HTTP Cookie specification (RFC6265, http://tools.ietf.org/html/rfc6265), // the first character can be a DIGIT or a "-", and the reminder // of the value can only contain DIGIT characters. if (maxAge.isEmpty() || (maxAge[0] != '-' && !isASCIIDigit(maxAge[0]))) { LOG_ERROR("Could not parse Max-Age : %s, first character can only be '-' or ascii digit.", maxAge.ascii().data()); return; } bool ok; int value = maxAge.toIntStrict(&ok); if (!ok) { LOG_ERROR("Could not parse Max-Age : %s", maxAge.ascii().data()); return; } m_expiry = value; m_isMaxAgeSet = true; m_isSession = false; // If maxAge value is not positive, let expiry-time be the earliest representable time. if (m_expiry > 0) m_expiry += currentTime(); else m_expiry = 0; }
double parseToDoubleForNumberType(const String& string, double fallbackValue) { // See HTML5 2.5.4.3 `Real numbers.' // String::toDouble() accepts leading + and whitespace characters, which are not valid here. UChar firstCharacter = string[0]; if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter)) return fallbackValue; bool valid = false; double value = string.toDouble(&valid); if (!valid) return fallbackValue; // NaN and infinity are considered valid by String::toDouble, but not valid here. if (!std::isfinite(value)) return fallbackValue; // Numbers are considered finite IEEE 754 single-precision floating point values. // See HTML5 2.5.4.3 `Real numbers.' if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max()) return fallbackValue; // The following expression converts -0 to +0. return value ? value : 0; }
static bool parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end, int& value) { // Step 3 int sign = 1; // Step 4 while (position < end) { if (!isHTMLSpace<CharacterType>(*position)) break; ++position; } // Step 5 if (position == end) return false; ASSERT(position < end); // Step 6 if (*position == '-') { sign = -1; ++position; } else if (*position == '+') ++position; if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; if (digits.is8Bit()) value = sign * charactersToIntStrict(digits.characters8(), digits.length(), &ok); else value = sign * charactersToIntStrict(digits.characters16(), digits.length(), &ok); return ok; }
static unsigned countDigits(const String& src, unsigned start) { unsigned index = start; for (; index < src.length(); ++index) { if (!isASCIIDigit(src[index])) break; } return index - start; }
static double getFraction(CSSTokenizerInputStream& input, unsigned& offset) { if (input.peek(offset) != '.' || !isASCIIDigit(input.peek(offset + 1))) return 0; unsigned startOffset = offset; offset = input.skipWhilePredicate<isASCIIDigit>(offset + 1); return input.getDouble(startOffset, offset); }
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value) { // Step 1 // Step 2 const UChar* position = input.characters(); const UChar* end = position + input.length(); // Step 3 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 4 if (position == end) return false; ASSERT(position < end); // Step 5 if (*position == '+') ++position; // Step 6 if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; value = charactersToUIntStrict(digits.characters(), digits.length(), &ok); return ok; }
static unsigned countDigits(const UChar* src, unsigned length, unsigned start) { unsigned index = start; for (; index < length; ++index) { if (!isASCIIDigit(src[index])) break; } return index - start; }
static String collectDigits(const LChar* input, unsigned length, unsigned& position) { StringBuilder digits; // http://www.ietf.org/rfc/rfc2326.txt // DIGIT ; any positive number while (position < length && isASCIIDigit(input[position])) digits.append(input[position++]); return digits.toString(); }
OriginAccessEntry::OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting subdomainSetting) : m_protocol(protocol.convertToASCIILowercase()) , m_host(host.convertToASCIILowercase()) , m_subdomainSettings(subdomainSetting) { ASSERT(subdomainSetting == AllowSubdomains || subdomainSetting == DisallowSubdomains); // Assume that any host that ends with a digit is trying to be an IP address. m_hostIsIPAddress = !m_host.isEmpty() && isASCIIDigit(m_host[m_host.length() - 1]); }
static bool parseHTMLNonNegativeIntegerInternal(const CharacterType* position, const CharacterType* end, unsigned& value) { // Step 3 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 4 if (position == end) return false; ASSERT(position < end); // Step 5 if (*position == '+') ++position; // Step 6 if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; if (digits.is8Bit()) value = charactersToUIntStrict(digits.characters8(), digits.length(), &ok); else value = charactersToUIntStrict(digits.characters16(), digits.length(), &ok); return ok; }
// Returns -1 if parsing fails. static int parseNumber(const String& input, unsigned& index) { unsigned digitsStart = index; while (index < input.length() && isASCIIDigit(input[index])) index++; if (digitsStart == index) return -1; bool ok = false; int number = input.substring(digitsStart, index - digitsStart).toInt(&ok); return ok ? number : -1; }
static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value) { while (string != end && isHTMLSpace<CharacterType>(*string)) string++; bool negative = false; if (string != end && *string == '-') { negative = true; string++; } value = 0; int length = end - string; if (length < 2) return false; if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2])) return false; if (string[0] != '0' && string[0] != '1' && string[0] != '.') { if (checkForValidDouble(string, end, terminator)) { value = negative ? 0 : 255; string = end; return true; } return false; } if (length == 2 && string[0] != '.') { value = !negative && string[0] == '1' ? 255 : 0; string = end; return true; } if (isTenthAlpha(string, length - 1)) { static const int tenthAlphaValues[] = {0, 25, 51, 76, 102, 127, 153, 179, 204, 230}; value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0']; string = end; return true; } double alpha = 0; if (!parseDouble(string, end, terminator, alpha)) return false; value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0)); string = end; return true; }
static double getFraction(MediaQueryInputStream& input, unsigned& offset, unsigned& digitsNumber) { unsigned fractionStartPos = 0; unsigned fractionEndPos = 0; if (input.peek(offset) == '.' && isASCIIDigit(input.peek(++offset))) { fractionStartPos = offset - 1; offset = input.skipWhilePredicate<isASCIIDigit>(offset); fractionEndPos = offset; } digitsNumber = fractionEndPos- fractionStartPos; return input.getDouble(fractionStartPos, fractionEndPos); }
static Length parseLength(const UChar* data, unsigned length) { if (length == 0) return Length(1, Relative); unsigned i = 0; while (i < length && isSpaceOrNewline(data[i])) ++i; if (i < length && (data[i] == '+' || data[i] == '-')) ++i; while (i < length && isASCIIDigit(data[i])) ++i; unsigned intLength = i; while (i < length && (isASCIIDigit(data[i]) || data[i] == '.')) ++i; unsigned doubleLength = i; // IE quirk: Skip whitespace between the number and the % character (20 % => 20%). while (i < length && isSpaceOrNewline(data[i])) ++i; bool ok; UChar next = (i < length) ? data[i] : ' '; if (next == '%') { // IE quirk: accept decimal fractions for percentages. double r = charactersToDouble(data, doubleLength, &ok); if (ok) return Length(r, Percent); return Length(1, Relative); } int r = charactersToIntStrict(data, intLength, &ok); if (next == '*') { if (ok) return Length(r, Relative); return Length(1, Relative); } if (ok) return Length(r, Fixed); return Length(0, Relative); }
static bool isCharacterAllowedInBase(UChar c, int base) { if (c > 0x7F) return false; if (isASCIIDigit(c)) return c - '0' < base; if (isASCIIAlpha(c)) { if (base > 36) base = 36; return (c >= 'a' && c < 'a' + base - 10) || (c >= 'A' && c < 'A' + base - 10); } return false; }
LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& token) { bool beginsWithDot = *m_ptr == '.'; ++m_ptr; while (m_ptr < m_end && isASCIIDigit(*m_ptr)) ++m_ptr; if (!beginsWithDot && m_ptr < m_end - 1 && *m_ptr == '.') { ++m_ptr; while (m_ptr < m_end && isASCIIDigit(*m_ptr)) ++m_ptr; } if (m_ptr < m_end) { if (*m_ptr == 'x' || *m_ptr == 'X' || *m_ptr == 'e' || *m_ptr == 'E') { token.type = TokError; return TokError; } } token.type = TokNumber; token.end = m_ptr; return TokNumber; }
static String collectFraction(const LChar* input, unsigned length, unsigned& position) { StringBuilder digits; // http://www.ietf.org/rfc/rfc2326.txt // [ "." *DIGIT ] if (input[position] != '.') return String(); digits.append(input[position++]); while (position < length && isASCIIDigit(input[position])) digits.append(input[position++]); return digits.toString(); }