From 0df1c48f427c3b73dcc72a4d069264db515168a6 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Sun, 5 Jul 2015 15:29:41 -0400 Subject: [PATCH] ISO8601: Added range checking for various date elements --- src/ISO8601.cpp | 93 ++++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/ISO8601.cpp b/src/ISO8601.cpp index 8aaa80465..57b1d0ff8 100644 --- a/src/ISO8601.cpp +++ b/src/ISO8601.cpp @@ -27,6 +27,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////////////////// ISO8601d::ISO8601d () @@ -95,7 +96,7 @@ bool ISO8601d::parse (const std::string& input, std::string::size_type& start) auto i = start; Nibbler n (input.substr (i)); - if (parse_date_time (n) || // Most complex first. + if (parse_date_time (n) || // Strictest first. parse_date_time_ext (n) || parse_date_ext (n) || parse_time_utc_ext (n) || @@ -144,12 +145,12 @@ bool ISO8601d::parse_date_time (Nibbler& n) n.save (); int year, month, day, hour, minute, second; if (n.getDigit4 (year) && - n.getDigit2 (month) && - n.getDigit2 (day) && + n.getDigit2 (month) && month && + n.getDigit2 (day) && day && n.skip ('T') && n.getDigit2 (hour) && - n.getDigit2 (minute) && - n.getDigit2 (second)) + n.getDigit2 (minute) && minute < 60 && + n.getDigit2 (second) && second < 60) { if (n.skip ('Z')) _utc = true; @@ -220,7 +221,7 @@ bool ISO8601d::parse_date_ext (Nibbler& n) int month; int day; if (n.skip ('W') && - n.getDigit2 (_week)) + n.getDigit2 (_week) && _week) { if (n.skip ('-') && n.getDigit (_weekday)) @@ -231,15 +232,15 @@ bool ISO8601d::parse_date_ext (Nibbler& n) if (!Lexer::isDigit (n.next ())) return true; } - else if (n.getDigit3 (_julian)) + else if (n.getDigit3 (_julian) && _julian) { _year = year; if (!Lexer::isDigit (n.next ())) return true; } - else if (n.getDigit2 (month) && + else if (n.getDigit2 (month) && month && n.skip ('-') && - n.getDigit2 (day)) + n.getDigit2 (day) && day) { _year = year; _month = month; @@ -259,25 +260,32 @@ bool ISO8601d::parse_off_ext (Nibbler& n) { Nibbler backup (n); std::string sign; - if (n.getN (1, sign)) + if (n.getN (1, sign) && (sign == "+" || sign == "-")) { - if (sign == "+" || sign == "-") + int offset; + int hh; + int mm; + if (n.getDigit2 (hh) && hh <= 12 && + !n.getDigit (mm)) { - int offset; - int hh; - int mm; - if (n.getDigit2 (hh) && - !n.getDigit (mm)) - { - offset = hh * 3600; - if (n.skip (':') && - n.getDigit2 (mm)) - offset += mm * 60; + offset = hh * 3600; - _offset = (sign == "-") ? -offset : offset; - if (!Lexer::isDigit (n.next ())) - return true; + if (n.skip (':')) + { + if (n.getDigit2 (mm) && mm < 60) + { + offset += mm * 60; + } + else + { + n = backup; + return false; + } } + + _offset = (sign == "-") ? -offset : offset; + if (!Lexer::isDigit (n.next ())) + return true; } } @@ -294,20 +302,25 @@ bool ISO8601d::parse_time_ext (Nibbler& n) int hh; int mm; int ss; - if (n.getDigit2 (hh) && + if (n.getDigit2 (hh) && hh <= 24 && n.skip (':') && - n.getDigit2 (mm)) + n.getDigit2 (mm) && mm < 60) { seconds = (hh * 3600) + (mm * 60); - if (n.skip (':') && - n.getDigit2 (ss)) + if (n.skip (':')) { - seconds += ss; - _seconds = seconds; + if (n.getDigit2 (ss) && ss < 60) + { + seconds += ss; + _seconds = seconds; - if (!Lexer::isDigit (n.next ())) - return true; + if (!Lexer::isDigit (n.next ())) + return true; + } + + n = backup; + return false; } _seconds = seconds; @@ -367,14 +380,14 @@ int ISO8601d::dayOfWeek (int year, int month, int day) bool ISO8601d::validate () { // _year; - if ((_year && (_year < 1900 || _year > 2100)) || - (_month && (_month < 1 || _month > 12)) || - (_week && (_week < 1 || _week > 53)) || - (_weekday && (_weekday < 0 || _weekday > 6)) || - (_julian && (_julian < 0 || _julian > 366)) || - (_day && (_day < 1 || _day > 31)) || - (_seconds && (_seconds < 1 || _seconds > 86400)) || - (_offset && (_offset < -86400 || _offset > 86400))) + if ((_year && (_year < 1900 || _year > 2100)) || + (_month && (_month < 1 || _month > 12)) || + (_week && (_week < 1 || _week > 53)) || + (_weekday && (_weekday < 0 || _weekday > 6)) || + (_julian && (_julian < 1 || _julian > Date::daysInYear (_year))) || + (_day && (_day < 1 || _day > Date::daysInMonth (_month, _year))) || + (_seconds && (_seconds < 1 || _seconds > 86400)) || + (_offset && (_offset < -86400 || _offset > 86400))) return false; return true;