فهرست منبع

LibWeb: Add `parse_integer_digits` methods

The rules for parsing integers don't specify an upper bound on the
value that can be returned, so the `parse_integer_digits` method can be
used to check whether the given arbitrarily-large StringView is valid
according to these rules. The `parse_integer` and
`parse_non_negative_integer` methods would fail for values larger than
2147483647 when they shouldn't have.
Tim Ledbetter 7 ماه پیش
والد
کامیت
d02b763cd6
2فایلهای تغییر یافته به همراه38 افزوده شده و 13 حذف شده
  1. 36 13
      Libraries/LibWeb/HTML/Numbers.cpp
  2. 2 0
      Libraries/LibWeb/HTML/Numbers.h

+ 36 - 13
Libraries/LibWeb/HTML/Numbers.cpp

@@ -12,7 +12,7 @@
 namespace Web::HTML {
 
 // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
-Optional<i32> parse_integer(StringView string)
+Optional<StringView> parse_integer_digits(StringView string)
 {
     // 1. Let input be the string being parsed.
     // 2. Let position be a pointer into input, initially pointing at the start of the string.
@@ -26,7 +26,7 @@ Optional<i32> parse_integer(StringView string)
 
     // 5. If position is past the end of input, return an error.
     if (lexer.is_eof()) {
-        return {};
+        return OptionalNone {};
     }
 
     // 6. If the character indicated by position (the first character) is a U+002D HYPHEN-MINUS character (-):
@@ -40,23 +40,33 @@ Optional<i32> parse_integer(StringView string)
 
     // 7. If the character indicated by position is not an ASCII digit, then return an error.
     if (!lexer.next_is(is_ascii_digit)) {
-        return {};
+        return OptionalNone {};
     }
 
     // 8. Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Let value be that integer.
+    // NOTE: Integer conversion is performed by the caller.
     lexer.consume_while(is_ascii_digit);
     size_t end_index = lexer.tell();
     auto digits = lexer.input().substring_view(start_index, end_index - start_index);
-    auto optional_value = AK::StringUtils::convert_to_int<i32>(digits);
 
     // 9. If sign is "positive", return value, otherwise return the result of subtracting value from zero.
     // NOTE: Skipped, see comment on step 6.
 
-    return optional_value;
+    return digits;
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
+Optional<i32> parse_integer(StringView string)
+{
+    auto optional_digits = parse_integer_digits(string);
+    if (!optional_digits.has_value())
+        return {};
+
+    return optional_digits->to_number<i32>(TrimWhitespace::No);
 }
 
 // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
-Optional<u32> parse_non_negative_integer(StringView string)
+Optional<StringView> parse_non_negative_integer_digits(StringView string)
 {
     // 1. Let input be the string being parsed.
     // 2. Let value be the result of parsing input using the rules for parsing integers.
@@ -64,19 +74,32 @@ Optional<u32> parse_non_negative_integer(StringView string)
     // NOTE: Because we call `parse_integer`, we parse all integers as signed. If we need the extra
     //       size that an unsigned integer offers, then this would need to be improved. That said,
     //       I don't think we need to support such large integers at the moment.
-    auto optional_value = parse_integer(string);
 
+    auto optional_integer_digits = parse_integer_digits(string);
     // 3. If value is an error, return an error.
-    if (!optional_value.has_value()) {
-        return {};
-    }
+    if (!optional_integer_digits.has_value())
+        return OptionalNone {};
 
     // 4. If value is less than zero, return an error.
-    if (optional_value.value() < 0) {
-        return {};
-    }
+    if (optional_integer_digits->length() > 1 && optional_integer_digits->starts_with('-') && optional_integer_digits->bytes().at(1) != '0')
+        return OptionalNone {};
 
     // 5. Return value.
+    // NOTE: Integer conversion is performed by the caller.
+    return optional_integer_digits;
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
+Optional<u32> parse_non_negative_integer(StringView string)
+{
+    auto optional_digits = parse_non_negative_integer_digits(string);
+    if (!optional_digits.has_value())
+        return {};
+
+    auto optional_value = optional_digits->to_number<i64>(TrimWhitespace::No);
+    if (!optional_value.has_value() || *optional_value > NumericLimits<u32>::max())
+        return {};
+
     return static_cast<u32>(optional_value.value());
 }
 

+ 2 - 0
Libraries/LibWeb/HTML/Numbers.h

@@ -14,8 +14,10 @@
 namespace Web::HTML {
 
 Optional<i32> parse_integer(StringView string);
+Optional<StringView> parse_integer_digits(StringView string);
 
 Optional<u32> parse_non_negative_integer(StringView string);
+Optional<StringView> parse_non_negative_integer_digits(StringView string);
 
 Optional<double> parse_floating_point_number(StringView string);