ISO8601: Added range checking for various date elements

This commit is contained in:
Paul Beckingham
2015-07-05 15:29:41 -04:00
parent a71fc887d9
commit 0df1c48f42

View File

@@ -27,6 +27,7 @@
#include <cmake.h> #include <cmake.h>
#include <Lexer.h> #include <Lexer.h>
#include <ISO8601.h> #include <ISO8601.h>
#include <Date.h>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ISO8601d::ISO8601d () ISO8601d::ISO8601d ()
@@ -95,7 +96,7 @@ bool ISO8601d::parse (const std::string& input, std::string::size_type& start)
auto i = start; auto i = start;
Nibbler n (input.substr (i)); 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_time_ext (n) ||
parse_date_ext (n) || parse_date_ext (n) ||
parse_time_utc_ext (n) || parse_time_utc_ext (n) ||
@@ -144,12 +145,12 @@ bool ISO8601d::parse_date_time (Nibbler& n)
n.save (); n.save ();
int year, month, day, hour, minute, second; int year, month, day, hour, minute, second;
if (n.getDigit4 (year) && if (n.getDigit4 (year) &&
n.getDigit2 (month) && n.getDigit2 (month) && month &&
n.getDigit2 (day) && n.getDigit2 (day) && day &&
n.skip ('T') && n.skip ('T') &&
n.getDigit2 (hour) && n.getDigit2 (hour) &&
n.getDigit2 (minute) && n.getDigit2 (minute) && minute < 60 &&
n.getDigit2 (second)) n.getDigit2 (second) && second < 60)
{ {
if (n.skip ('Z')) if (n.skip ('Z'))
_utc = true; _utc = true;
@@ -220,7 +221,7 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
int month; int month;
int day; int day;
if (n.skip ('W') && if (n.skip ('W') &&
n.getDigit2 (_week)) n.getDigit2 (_week) && _week)
{ {
if (n.skip ('-') && if (n.skip ('-') &&
n.getDigit (_weekday)) n.getDigit (_weekday))
@@ -231,15 +232,15 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
if (!Lexer::isDigit (n.next ())) if (!Lexer::isDigit (n.next ()))
return true; return true;
} }
else if (n.getDigit3 (_julian)) else if (n.getDigit3 (_julian) && _julian)
{ {
_year = year; _year = year;
if (!Lexer::isDigit (n.next ())) if (!Lexer::isDigit (n.next ()))
return true; return true;
} }
else if (n.getDigit2 (month) && else if (n.getDigit2 (month) && month &&
n.skip ('-') && n.skip ('-') &&
n.getDigit2 (day)) n.getDigit2 (day) && day)
{ {
_year = year; _year = year;
_month = month; _month = month;
@@ -259,25 +260,32 @@ bool ISO8601d::parse_off_ext (Nibbler& n)
{ {
Nibbler backup (n); Nibbler backup (n);
std::string sign; 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; offset = hh * 3600;
int hh;
int mm;
if (n.getDigit2 (hh) &&
!n.getDigit (mm))
{
offset = hh * 3600;
if (n.skip (':') &&
n.getDigit2 (mm))
offset += mm * 60;
_offset = (sign == "-") ? -offset : offset; if (n.skip (':'))
if (!Lexer::isDigit (n.next ())) {
return true; 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 hh;
int mm; int mm;
int ss; int ss;
if (n.getDigit2 (hh) && if (n.getDigit2 (hh) && hh <= 24 &&
n.skip (':') && n.skip (':') &&
n.getDigit2 (mm)) n.getDigit2 (mm) && mm < 60)
{ {
seconds = (hh * 3600) + (mm * 60); seconds = (hh * 3600) + (mm * 60);
if (n.skip (':') && if (n.skip (':'))
n.getDigit2 (ss))
{ {
seconds += ss; if (n.getDigit2 (ss) && ss < 60)
_seconds = seconds; {
seconds += ss;
_seconds = seconds;
if (!Lexer::isDigit (n.next ())) if (!Lexer::isDigit (n.next ()))
return true; return true;
}
n = backup;
return false;
} }
_seconds = seconds; _seconds = seconds;
@@ -367,14 +380,14 @@ int ISO8601d::dayOfWeek (int year, int month, int day)
bool ISO8601d::validate () bool ISO8601d::validate ()
{ {
// _year; // _year;
if ((_year && (_year < 1900 || _year > 2100)) || if ((_year && (_year < 1900 || _year > 2100)) ||
(_month && (_month < 1 || _month > 12)) || (_month && (_month < 1 || _month > 12)) ||
(_week && (_week < 1 || _week > 53)) || (_week && (_week < 1 || _week > 53)) ||
(_weekday && (_weekday < 0 || _weekday > 6)) || (_weekday && (_weekday < 0 || _weekday > 6)) ||
(_julian && (_julian < 0 || _julian > 366)) || (_julian && (_julian < 1 || _julian > Date::daysInYear (_year))) ||
(_day && (_day < 1 || _day > 31)) || (_day && (_day < 1 || _day > Date::daysInMonth (_month, _year))) ||
(_seconds && (_seconds < 1 || _seconds > 86400)) || (_seconds && (_seconds < 1 || _seconds > 86400)) ||
(_offset && (_offset < -86400 || _offset > 86400))) (_offset && (_offset < -86400 || _offset > 86400)))
return false; return false;
return true; return true;