From 387d98b80d9f383c4c7708a42444472cb89dd42b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 20 Mar 2023 14:25:05 +0200 Subject: Add extra validation for date, dateTime, and gMonthDay per XML Schema 1.1 --- libxsde/xsde/cxx/parser/validating/date-time.cxx | 36 +++++++++++++++++++--- libxsde/xsde/cxx/parser/validating/date.cxx | 36 +++++++++++++++++++--- libxsde/xsde/cxx/parser/validating/gmonth-day.cxx | 23 +++++++++++++- .../xsde/cxx/serializer/validating/date-time.cxx | 26 +++++++++++++++- libxsde/xsde/cxx/serializer/validating/date.cxx | 26 +++++++++++++++- .../xsde/cxx/serializer/validating/gmonth-day.cxx | 23 +++++++++++++- 6 files changed, 156 insertions(+), 14 deletions(-) diff --git a/libxsde/xsde/cxx/parser/validating/date-time.cxx b/libxsde/xsde/cxx/parser/validating/date-time.cxx index 06d66e9..268d270 100644 --- a/libxsde/xsde/cxx/parser/validating/date-time.cxx +++ b/libxsde/xsde/cxx/parser/validating/date-time.cxx @@ -193,11 +193,7 @@ namespace xsde day_ = 10 * (d1 - '0') + (d2 - '0'); - if (day_ < 1 || day_ > 31) - { - _schema_error (schema_error::invalid_date_time_value); - return; - } + // Note: day validated below. // month // @@ -241,6 +237,36 @@ namespace xsde ? (-2147483647 - 1) : -static_cast (ul)) : static_cast (ul); + + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, no more than 28 if month is 2 and year is not divisible by + // 4, or is divisible by 100 but not by 400, and no more than 29 if + // month is 2 and year is divisible by 400, or by 4 but not by 100. + // + unsigned short max_day = 31; + switch (month_) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = ((year_ % 400 == 0) || + (year_ % 4 == 0 && year_ % 100 != 0) ? 29 : 28); + break; + default: + break; + } + + if (day_ < 1 || day_ > max_day) + { + _schema_error (schema_error::invalid_date_time_value); + return; + } } date_time date_time_pimpl:: diff --git a/libxsde/xsde/cxx/parser/validating/date.cxx b/libxsde/xsde/cxx/parser/validating/date.cxx index a021e4c..ec38f09 100644 --- a/libxsde/xsde/cxx/parser/validating/date.cxx +++ b/libxsde/xsde/cxx/parser/validating/date.cxx @@ -120,11 +120,7 @@ namespace xsde day_ = 10 * (d1 - '0') + (d2 - '0'); - if (day_ < 1 || day_ > 31) - { - _schema_error (schema_error::invalid_date_value); - return; - } + // Note: day validated below. // zone // @@ -165,6 +161,36 @@ namespace xsde ? (-2147483647 - 1) : -static_cast (ul)) : static_cast (ul); + + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, no more than 28 if month is 2 and year is not divisible by + // 4, or is divisible by 100 but not by 400, and no more than 29 if + // month is 2 and year is divisible by 400, or by 4 but not by 100. + // + unsigned short max_day = 31; + switch (month_) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = ((year_ % 400 == 0) || + (year_ % 4 == 0 && year_ % 100 != 0) ? 29 : 28); + break; + default: + break; + } + + if (day_ < 1 || day_ > max_day) + { + _schema_error (schema_error::invalid_date_value); + return; + } } date date_pimpl:: diff --git a/libxsde/xsde/cxx/parser/validating/gmonth-day.cxx b/libxsde/xsde/cxx/parser/validating/gmonth-day.cxx index a972855..5d5efd7 100644 --- a/libxsde/xsde/cxx/parser/validating/gmonth-day.cxx +++ b/libxsde/xsde/cxx/parser/validating/gmonth-day.cxx @@ -100,7 +100,28 @@ namespace xsde day_ = 10 * (d1 - '0') + (d2 - '0'); - if (day_ < 1 || day_ > 31) + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, and no more than 29 if month is 2. + // + unsigned short max_day = 31; + switch (month_) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = 29; + break; + default: + break; + } + + if (day_ < 1 || day_ > max_day) { _schema_error (schema_error::invalid_gmonth_day_value); return; diff --git a/libxsde/xsde/cxx/serializer/validating/date-time.cxx b/libxsde/xsde/cxx/serializer/validating/date-time.cxx index 7d9db17..d5069be 100644 --- a/libxsde/xsde/cxx/serializer/validating/date-time.cxx +++ b/libxsde/xsde/cxx/serializer/validating/date-time.cxx @@ -38,7 +38,31 @@ namespace xsde unsigned short tm = value_.minutes (); double s = value_.seconds (); - if (y != 0 && m > 0 && m < 13 && d > 0 && d < 32 && + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, no more than 28 if month is 2 and year is not divisible by + // 4, or is divisible by 100 but not by 400, and no more than 29 if + // month is 2 and year is divisible by 400, or by 4 but not by 100. + // + unsigned short max_day = 31; + switch (m) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = ((y % 400 == 0) || + (y % 4 == 0 && y % 100 != 0) ? 29 : 28); + break; + default: + break; + } + + if (y != 0 && m > 0 && m < 13 && d > 0 && d <= max_day && ((h < 24 && tm < 60 && s >= 0.0 && s < 60.0) || (h == 24 && tm == 0 && s == 0.0)) && (!value_.zone_present () || bits::valid_time_zone (value_))) diff --git a/libxsde/xsde/cxx/serializer/validating/date.cxx b/libxsde/xsde/cxx/serializer/validating/date.cxx index 27beb79..fd1c8d6 100644 --- a/libxsde/xsde/cxx/serializer/validating/date.cxx +++ b/libxsde/xsde/cxx/serializer/validating/date.cxx @@ -32,7 +32,31 @@ namespace xsde unsigned short m = value_.month (); unsigned short d = value_.day (); - if (y != 0 && m > 0 && m < 13 && d > 0 && d < 32 && + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, no more than 28 if month is 2 and year is not divisible by + // 4, or is divisible by 100 but not by 400, and no more than 29 if + // month is 2 and year is divisible by 400, or by 4 but not by 100. + // + unsigned short max_day = 31; + switch (m) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = ((y % 400 == 0) || + (y % 4 == 0 && y % 100 != 0) ? 29 : 28); + break; + default: + break; + } + + if (y != 0 && m > 0 && m < 13 && d > 0 && d <= max_day && (!value_.zone_present () || bits::valid_time_zone (value_))) { #ifdef XSDE_SNPRINTF diff --git a/libxsde/xsde/cxx/serializer/validating/gmonth-day.cxx b/libxsde/xsde/cxx/serializer/validating/gmonth-day.cxx index dc044fd..ea83451 100644 --- a/libxsde/xsde/cxx/serializer/validating/gmonth-day.cxx +++ b/libxsde/xsde/cxx/serializer/validating/gmonth-day.cxx @@ -31,7 +31,28 @@ namespace xsde unsigned short m = value_.month (); unsigned short d = value_.day (); - if (m > 0 && m < 13 && d > 0 && d < 32 && + // Validate day according to the XML Schema 1.1 specification: + // + // The day value must be no more than 30 if month is one of 4, 6, 9, + // or 11, and no more than 29 if month is 2. + // + unsigned short max_day = 31; + switch (m) + { + case 4: + case 6: + case 9: + case 11: + max_day = 30; + break; + case 2: + max_day = 29; + break; + default: + break; + } + + if (m > 0 && m < 13 && d > 0 && d <= max_day && (!value_.zone_present () || bits::valid_time_zone (value_))) { #ifdef XSDE_SNPRINTF -- cgit v1.1