diff options
Diffstat (limited to 'WebCore/html/DateComponents.cpp')
-rw-r--r-- | WebCore/html/DateComponents.cpp | 107 |
1 files changed, 77 insertions, 30 deletions
diff --git a/WebCore/html/DateComponents.cpp b/WebCore/html/DateComponents.cpp index 39dd733..8dced1d 100644 --- a/WebCore/html/DateComponents.cpp +++ b/WebCore/html/DateComponents.cpp @@ -41,10 +41,15 @@ using namespace std; namespace WebCore { -// The oldest day of Gregorian Calendar is 1582-10-15. We don't support dates older than it. -static const int gregorianStartYear = 1582; -static const int gregorianStartMonth = 9; // This is October, since months are 0 based. -static const int gregorianStartDay = 15; +// HTML5 uses ISO-8601 format with year >= 1. Gregorian calendar started in +// 1582. However, we need to support 0001-01-01 in Gregorian calendar rule. +static const int minimumYear = 1; +// Date in ECMAScript can't represent dates later than 275760-09-13T00:00Z. +// So, we have the same upper limit in HTML5 dates. +static const int maximumYear = 275760; +static const int maximumMonthInMaximumYear = 8; // This is September, since months are 0 based. +static const int maximumDayInMaximumMonth = 13; +static const int maximumWeekInMaximumYear = 37; // The week of 275760-09-13 static const int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -134,19 +139,47 @@ bool DateComponents::parseYear(const UChar* src, unsigned length, unsigned start int year; if (!toInt(src, length, start, digitsLength, year)) return false; - // No support for years before Gregorian calendar. - if (year < gregorianStartYear) + if (year < minimumYear || year > maximumYear) return false; m_year = year; end = start + digitsLength; return true; } -static bool beforeGregorianStartDate(int year, int month, int monthDay) +static bool withinHTMLDateLimits(int year, int month) { - return year < gregorianStartYear - || (year == gregorianStartYear && month < gregorianStartMonth) - || (year == gregorianStartYear && month == gregorianStartMonth && monthDay < gregorianStartDay); + if (year < minimumYear) + return false; + if (year < maximumYear) + return true; + return month <= maximumMonthInMaximumYear; +} + +static bool withinHTMLDateLimits(int year, int month, int monthDay) +{ + if (year < minimumYear) + return false; + if (year < maximumYear) + return true; + if (month < maximumMonthInMaximumYear) + return true; + return monthDay <= maximumDayInMaximumMonth; +} + +static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, int minute, int second, int millisecond) +{ + if (year < minimumYear) + return false; + if (year < maximumYear) + return true; + if (month < maximumMonthInMaximumYear) + return true; + if (monthDay < maximumDayInMaximumMonth) + return true; + if (monthDay > maximumDayInMaximumMonth) + return false; + // (year, month, monthDay) = (maximumYear, maximumMonthInMaximumYear, maximumDayInMaximumMonth) + return !hour && !minute && !second && !millisecond; } bool DateComponents::addDay(int dayDiff) @@ -167,12 +200,12 @@ bool DateComponents::addDay(int dayDiff) if (month >= 12) { // month is 0-origin. month = 0; ++year; - if (year < 0) // Check for overflow. - return false; } maxDay = maxDayOfMonth(year, month); } } + if (!withinHTMLDateLimits(year, month, day)) + return false; m_year = year; m_month = month; } else if (day < 1) { @@ -189,11 +222,14 @@ bool DateComponents::addDay(int dayDiff) } day = maxDayOfMonth(year, month); } - if (beforeGregorianStartDate(year, month, day)) - return false; } + if (!withinHTMLDateLimits(year, month, day)) + return false; m_year = year; m_month = month; + } else { + if (!withinHTMLDateLimits(m_year, m_month, day)) + return false; } m_monthDay = day; return true; @@ -201,8 +237,12 @@ bool DateComponents::addDay(int dayDiff) bool DateComponents::addMinute(int minute) { + // This function is used to adjust timezone offset. So m_year, m_month, + // m_monthDay have values between the lower and higher limits. + ASSERT(withinHTMLDateLimits(m_year, m_month, m_monthDay)); + int carry; - // min can be negative or greater than 59. + // minute can be negative or greater than 59. minute += m_minute; if (minute > 59) { carry = minute / 60; @@ -213,6 +253,8 @@ bool DateComponents::addMinute(int minute) carry = -carry; ASSERT(minute >= 0 && minute <= 59); } else { + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, minute, m_second, m_millisecond)) + return false; m_minute = minute; return true; } @@ -227,12 +269,16 @@ bool DateComponents::addMinute(int minute) carry = -carry; ASSERT(hour >= 0 && hour <= 23); } else { + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond)) + return false; m_minute = minute; m_hour = hour; return true; } if (!addDay(carry)) return false; + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond)) + return false; m_minute = minute; m_hour = hour; return true; @@ -298,8 +344,7 @@ bool DateComponents::parseMonth(const UChar* src, unsigned length, unsigned star if (!toInt(src, length, index, 2, month) || month < 1 || month > 12) return false; --month; - // No support for months before Gregorian calendar. - if (beforeGregorianStartDate(m_year, month, gregorianStartDay)) + if (!withinHTMLDateLimits(m_year, month)) return false; m_month = month; end = index + 2; @@ -323,8 +368,7 @@ bool DateComponents::parseDate(const UChar* src, unsigned length, unsigned start int day; if (!toInt(src, length, index, 2, day) || day < 1 || day > maxDayOfMonth(m_year, m_month)) return false; - // No support for dates before Gregorian calendar. - if (m_year == gregorianStartYear && m_month == gregorianStartMonth && day < gregorianStartDay) + if (!withinHTMLDateLimits(m_year, m_month, day)) return false; m_monthDay = day; end = index + 2; @@ -352,8 +396,7 @@ bool DateComponents::parseWeek(const UChar* src, unsigned length, unsigned start int week; if (!toInt(src, length, index, 2, week) || week < 1 || week > maxWeekNumberInYear()) return false; - // No support for years older than or equals to Gregorian calendar start year. - if (m_year <= gregorianStartYear) + if (m_year == maximumYear && week > maximumWeekInMaximumYear) return false; m_week = week; end = index + 2; @@ -429,6 +472,8 @@ bool DateComponents::parseDateTimeLocal(const UChar* src, unsigned length, unsig ++index; if (!parseTime(src, length, index, end)) return false; + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond)) + return false; m_type = DateTimeLocal; return true; } @@ -448,6 +493,8 @@ bool DateComponents::parseDateTime(const UChar* src, unsigned length, unsigned s return false; if (!parseTimeZone(src, length, index, end)) return false; + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond)) + return false; m_type = DateTime; return true; } @@ -485,7 +532,7 @@ bool DateComponents::setMillisecondsSinceEpochForDate(double ms) return false; if (!setMillisecondsSinceEpochForDateInternal(round(ms))) return false; - if (beforeGregorianStartDate(m_year, m_month, m_monthDay)) + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay)) return false; m_type = Date; return true; @@ -500,7 +547,7 @@ bool DateComponents::setMillisecondsSinceEpochForDateTime(double ms) setMillisecondsSinceMidnightInternal(positiveFmod(ms, msPerDay)); if (!setMillisecondsSinceEpochForDateInternal(ms)) return false; - if (beforeGregorianStartDate(m_year, m_month, m_monthDay)) + if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond)) return false; m_type = DateTime; return true; @@ -522,8 +569,7 @@ bool DateComponents::setMillisecondsSinceEpochForMonth(double ms) return false; if (!setMillisecondsSinceEpochForDateInternal(round(ms))) return false; - // Ignore m_monthDay updated by setMillisecondsSinceEpochForDateInternal(). - if (beforeGregorianStartDate(m_year, m_month, gregorianStartDay)) + if (!withinHTMLDateLimits(m_year, m_month)) return false; m_type = Month; return true; @@ -546,11 +592,11 @@ bool DateComponents::setMonthsSinceEpoch(double months) months = round(months); double doubleMonth = positiveFmod(months, 12); double doubleYear = 1970 + (months - doubleMonth) / 12; - if (doubleYear < gregorianStartYear || numeric_limits<int>::max() < doubleYear) + if (doubleYear < minimumYear || maximumYear < doubleYear) return false; int year = static_cast<int>(doubleYear); int month = static_cast<int>(doubleMonth); - if (beforeGregorianStartDate(year, month, gregorianStartDay)) + if (!withinHTMLDateLimits(year, month)) return false; m_year = year; m_month = month; @@ -576,8 +622,7 @@ bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) ms = round(ms); m_year = msToYear(ms); - // We don't support gregorianStartYear. Week numbers are undefined in that year. - if (m_year <= gregorianStartYear) + if (m_year < minimumYear || m_year > maximumYear) return false; int yearDay = dayInYear(ms, m_year); @@ -585,7 +630,7 @@ bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) if (yearDay < offset) { // The day belongs to the last week of the previous year. m_year--; - if (m_year <= gregorianStartYear) + if (m_year <= minimumYear) return false; m_week = maxWeekNumberInYear(); } else { @@ -594,6 +639,8 @@ bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) m_year++; m_week = 1; } + if (m_year > maximumYear || (m_year == maximumYear && m_week > maximumWeekInMaximumYear)) + return false; } m_type = Week; return true; |