diff options
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptTime.cpp')
-rwxr-xr-x | lib/libUPnP/Neptune/Source/Core/NptTime.cpp | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/NptTime.cpp b/lib/libUPnP/Neptune/Source/Core/NptTime.cpp new file mode 100755 index 0000000..d842259 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTime.cpp @@ -0,0 +1,714 @@ +/***************************************************************** +| +| Neptune - Time +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTime.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const char* const NPT_TIME_DAYS_SHORT[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const char* const NPT_TIME_DAYS_LONG[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; +const char* const NPT_TIME_MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +static const NPT_Int32 NPT_TIME_MONTH_DAY[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; +static const NPT_Int32 NPT_TIME_MONTH_DAY_LEAP[] = {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +static const NPT_Int32 NPT_TIME_ELAPSED_DAYS_AT_MONTH[13] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + +const NPT_Int32 NPT_SECONDS_PER_DAY = (24L * 60L * 60L); +const NPT_Int32 NPT_SECONDS_PER_YEAR = (365L * NPT_SECONDS_PER_DAY); + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define NPT_TIME_YEAR_IS_LEAP(_y) ((((_y)%4 == 0) && ((_y)%100 != 0)) || ((_y)%400 == 0)) +#define NPT_TIME_CHECK_BOUNDS(_var, _low, _high) do { \ + if (((_var)<(_low)) || ((_var)>(_high))) { \ + return NPT_ERROR_OUT_OF_RANGE; \ + } \ +} while (0) + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::NPT_TimeStamp ++---------------------------------------------------------------------*/ +NPT_TimeStamp::NPT_TimeStamp(const NPT_TimeStamp& timestamp) +{ + m_NanoSeconds = timestamp.m_NanoSeconds; +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::NPT_TimeStamp ++---------------------------------------------------------------------*/ +NPT_TimeStamp::NPT_TimeStamp(double seconds) +{ + m_NanoSeconds = (NPT_Int64)(seconds * 1e9); +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::operator+= ++---------------------------------------------------------------------*/ +NPT_TimeStamp& +NPT_TimeStamp::operator+=(const NPT_TimeStamp& t) +{ + m_NanoSeconds += t.m_NanoSeconds; + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::operator-= ++---------------------------------------------------------------------*/ +NPT_TimeStamp& +NPT_TimeStamp::operator-=(const NPT_TimeStamp& t) +{ + m_NanoSeconds -= t.m_NanoSeconds; + return *this; +} + +/*---------------------------------------------------------------------- +| MatchString ++---------------------------------------------------------------------*/ +static int +MatchString(const char* string, const char* const* list, unsigned int list_length) +{ + for (unsigned int i=0; i<list_length; i++) { + if (NPT_StringsEqual(string, list[i])) return i; + } + + return -1; +} + +/*---------------------------------------------------------------------- +| ElapsedLeapYearsSince1900 ++---------------------------------------------------------------------*/ +static NPT_UInt32 +ElapsedLeapYearsSince1900(NPT_UInt32 year) +{ + if (year < 1901) return 0; + NPT_UInt32 years_since_1900 = year-1-1900; // not including the current year + return years_since_1900/4 - + years_since_1900/100 + + (years_since_1900+300)/400; +} + +/*---------------------------------------------------------------------- +| ElapsedDaysSince1900 ++---------------------------------------------------------------------*/ +static NPT_UInt32 +ElapsedDaysSince1900(const NPT_DateTime& date) +{ + // compute the number of days elapsed in the year + NPT_UInt32 day_count = NPT_TIME_ELAPSED_DAYS_AT_MONTH[date.m_Month-1] + date.m_Day - 1; + + // adjust for leap years after february + if (NPT_TIME_YEAR_IS_LEAP(date.m_Year) && (date.m_Month > 2)) ++day_count; + + // compute the total number of elapsed days + NPT_UInt32 leap_year_count = ElapsedLeapYearsSince1900(date.m_Year); + day_count += (date.m_Year-1900)*365 + leap_year_count; + + return day_count; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::NPT_DateTime ++---------------------------------------------------------------------*/ +NPT_DateTime::NPT_DateTime() : + m_Year(1970), + m_Month(1), + m_Day(1), + m_Hours(0), + m_Minutes(0), + m_Seconds(0), + m_NanoSeconds(0), + m_TimeZone(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::NPT_DateTime ++---------------------------------------------------------------------*/ +NPT_DateTime::NPT_DateTime(const NPT_TimeStamp& timestamp, bool local) +{ + FromTimeStamp(timestamp, local); +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ChangeTimeZone ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::ChangeTimeZone(NPT_Int32 timezone) +{ + if (timezone < -12*60 || timezone > 12*60) { + return NPT_ERROR_OUT_OF_RANGE; + } + NPT_TimeStamp ts; + NPT_Result result = ToTimeStamp(ts); + if (NPT_FAILED(result)) return result; + ts.SetNanos(ts.ToNanos()+(NPT_Int64)timezone*(NPT_Int64)60*(NPT_Int64)1000000000); + + result = FromTimeStamp(ts); + m_TimeZone = timezone; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::FromTimeStamp ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::FromTimeStamp(const NPT_TimeStamp& ts, bool local) +{ + // number of seconds from the epoch (positive or negative) + NPT_Int64 seconds = ts.ToSeconds(); + + // check the range (we only allow up to 31 bits of negative range for seconds + // in order to have the same lower bound as the 32-bit gmtime() function) + if (seconds < 0 && (NPT_Int32)seconds != seconds) return NPT_ERROR_OUT_OF_RANGE; + + // adjust for the timezone if necessary + NPT_Int32 timezone = 0; + if (local) { + timezone = GetLocalTimeZone(); + seconds += timezone*60; + } + + // adjust to the number of seconds since 1900 + seconds += (NPT_Int64)NPT_SECONDS_PER_YEAR*70 + + (NPT_Int64)(17*NPT_SECONDS_PER_DAY); // 17 leap year between 1900 and 1970 + + // compute the years since 1900, not adjusting for leap years + NPT_UInt32 years_since_1900 = (NPT_UInt32)(seconds/NPT_SECONDS_PER_YEAR); + + // compute the number of seconds elapsed in the current year + seconds -= (NPT_Int64)years_since_1900 * NPT_SECONDS_PER_YEAR; + + // adjust for leap years + bool is_leap_year = false; + NPT_Int64 leap_years_since_1900 = ElapsedLeapYearsSince1900(years_since_1900+1900); + if (seconds < (leap_years_since_1900 * NPT_SECONDS_PER_DAY)) { + // not enough seconds in the current year to compensate, move one year back + seconds += NPT_SECONDS_PER_YEAR; + seconds -= leap_years_since_1900 * NPT_SECONDS_PER_DAY; + --years_since_1900; + if (NPT_TIME_YEAR_IS_LEAP(years_since_1900+1900) ) { + seconds += NPT_SECONDS_PER_DAY; + is_leap_year = true; + } + } else { + seconds -= leap_years_since_1900 * NPT_SECONDS_PER_DAY; + if (NPT_TIME_YEAR_IS_LEAP(years_since_1900+1900) ) { + is_leap_year = true; + } + } + + // now we know the year + m_Year = years_since_1900+1900; + + // compute the number of days since January 1 (0 - 365) + NPT_UInt32 day_of_the_year = (NPT_UInt32)(seconds/NPT_SECONDS_PER_DAY); + + // compute the number of seconds in the current day + seconds -= day_of_the_year * NPT_SECONDS_PER_DAY; + + // compute the number of months since January (0 - 11) and the day of month (1 - 31) */ + const NPT_Int32* month_day = is_leap_year?NPT_TIME_MONTH_DAY_LEAP:NPT_TIME_MONTH_DAY; + NPT_UInt32 month; + for (month = 1; month_day[month] < (NPT_Int32)day_of_the_year ; month++) {} + + // now we know the month and day + m_Month = month; + m_Day = day_of_the_year - month_day[month-1]; + + // compute the number of hours since midnight (0 - 23), minutes after the hour + // (0 - 59), seconds after the minute (0 - 59) and nanoseconds + m_Hours = (NPT_Int32)seconds/3600; + seconds -= m_Hours * 3600L; + m_Minutes = (NPT_Int32)seconds / 60; + m_Seconds = (NPT_Int32)seconds - m_Minutes * 60; + m_NanoSeconds = (NPT_Int32)(ts.ToNanos()%1000000000); + if (local) { + m_TimeZone = timezone; + } else { + m_TimeZone = 0; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| CheckDate ++---------------------------------------------------------------------*/ +static NPT_Result +CheckDate(const NPT_DateTime& date) +{ + NPT_TIME_CHECK_BOUNDS(date.m_Year, NPT_DATETIME_YEAR_MIN, NPT_DATETIME_YEAR_MAX); + NPT_TIME_CHECK_BOUNDS(date.m_Month, 1, 12); + NPT_TIME_CHECK_BOUNDS(date.m_Day, 1, 31); + NPT_TIME_CHECK_BOUNDS(date.m_Hours, 0, 23); + NPT_TIME_CHECK_BOUNDS(date.m_Minutes, 0, 59); + NPT_TIME_CHECK_BOUNDS(date.m_Seconds, 0, 59); + NPT_TIME_CHECK_BOUNDS(date.m_NanoSeconds, 0, 999999999); + NPT_TIME_CHECK_BOUNDS(date.m_TimeZone, -12*60, 12*60); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ToTimeStamp ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::ToTimeStamp(NPT_TimeStamp& timestamp) const +{ + // default value + timestamp.SetNanos(0); + + // check bounds + NPT_Result result = CheckDate(*this); + if (NPT_FAILED(result)) return result; + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + // compute the number of nanoseconds + NPT_Int64 seconds = (NPT_Int64)days * (24*60*60) + + (NPT_Int64)m_Hours * (60*60) + + (NPT_Int64)m_Minutes * (60) + + (NPT_Int64)m_Seconds; + seconds -= (NPT_Int64)m_TimeZone*60; + + // adjust to the number of seconds since 1900 + seconds -= (NPT_Int64)NPT_SECONDS_PER_YEAR*70 + + (NPT_Int64)(17*NPT_SECONDS_PER_DAY); // 17 leap year between 1900 and 1970 + + timestamp.FromNanos(seconds * 1000000000 + m_NanoSeconds); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AppendNumber ++---------------------------------------------------------------------*/ +static void +AppendNumber(NPT_String& output, NPT_UInt32 number, unsigned int digit_count) +{ + NPT_Size new_length = output.GetLength()+digit_count; + output.SetLength(new_length); + char* dest = output.UseChars()+new_length; + while (digit_count--) { + *--dest = '0'+(number%10); + number /= 10; + } +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_DateTime::ToString(Format format, NPT_Flags flags) const +{ + NPT_String result; + + if (NPT_FAILED(CheckDate(*this))) return result; + + switch (format) { + case FORMAT_W3C: + AppendNumber(result, m_Year, 4); + result += '-'; + AppendNumber(result, m_Month, 2); + result += '-'; + AppendNumber(result, m_Day, 2); + result += 'T'; + AppendNumber(result, m_Hours, 2); + result += ':'; + AppendNumber(result, m_Minutes, 2); + result += ':'; + AppendNumber(result, m_Seconds, 2); + if (flags & FLAG_EMIT_FRACTION) { + result += '.'; + if (flags & FLAG_EXTENDED_PRECISION) { + // nanoseconds precision + AppendNumber(result, m_NanoSeconds, 9); + } else { + // only miliseconds precision + AppendNumber(result, m_NanoSeconds/1000000, 3); + } + } + if (m_TimeZone) { + NPT_UInt32 tz; + if (m_TimeZone > 0) { + result += '+'; + tz = m_TimeZone; + } else { + result += '-'; + tz = -m_TimeZone; + } + AppendNumber(result, tz/60, 2); + result += ':'; + AppendNumber(result, tz%60, 2); + } else { + result += 'Z'; + } + break; + + case FORMAT_ANSI: { + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + // format the result + result.SetLength(24); + NPT_FormatString(result.UseChars(), result.GetLength()+1, + "%.3s %.3s%3d %.2d:%.2d:%.2d %d", + NPT_TIME_DAYS_SHORT[(days+1)%7], + NPT_TIME_MONTHS[m_Month-1], + m_Day, + m_Hours, + m_Minutes, + m_Seconds, + m_Year); + break; + } + + case FORMAT_RFC_1036: + case FORMAT_RFC_1123: { + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + if (format == FORMAT_RFC_1036) { + result += NPT_TIME_DAYS_LONG[(days+1)%7]; + result += ", "; + AppendNumber(result, m_Day, 2); + result += '-'; + result += NPT_TIME_MONTHS[m_Month-1]; + result += '-'; + AppendNumber(result, m_Year%100, 2); + } else { + result += NPT_TIME_DAYS_SHORT[(days+1)%7]; + result += ", "; + AppendNumber(result, m_Day, 2); + result += ' '; + result += NPT_TIME_MONTHS[m_Month-1]; + result += ' '; + AppendNumber(result, m_Year, 4); + } + result += ' '; + AppendNumber(result, m_Hours, 2); + result += ':'; + AppendNumber(result, m_Minutes, 2); + result += ':'; + AppendNumber(result, m_Seconds, 2); + if (m_TimeZone) { + if (m_TimeZone > 0) { + result += " +"; + AppendNumber(result, m_TimeZone/60, 2); + AppendNumber(result, m_TimeZone%60, 2); + } else { + result += " -"; + AppendNumber(result, -m_TimeZone/60, 2); + AppendNumber(result, -m_TimeZone%60, 2); + } + } else { + result += " GMT"; + } + break; + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::FromString ++--------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::FromString(const char* date, Format format) +{ + if (date == NULL || date[0] == '\0') return NPT_ERROR_INVALID_PARAMETERS; + + // create a local copy to work with + NPT_String workspace(date); + char* input = workspace.UseChars(); + NPT_Size input_size = workspace.GetLength(); + + switch (format) { + case FORMAT_W3C: { + if (input_size < 17 && input_size != 10) return NPT_ERROR_INVALID_SYNTAX; + + // check separators + if (input[4] != '-' || + input[7] != '-') { + return NPT_ERROR_INVALID_SYNTAX; + } + + // replace separators with terminators + input[4] = input[7] = '\0'; + + bool no_seconds = true; + if (input_size > 10) { + if (input[10] != 'T' || + input[13] != ':') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[10] = input[13] = '\0'; + if (input[16] == ':') { + input[16] = '\0'; + no_seconds = false; + if (input_size < 20) return NPT_ERROR_INVALID_SYNTAX; + } else { + m_Seconds = 0; + } + } + + + // parse CCYY-MM-DD fields + if (NPT_FAILED(NPT_ParseInteger(input, m_Year, false)) || + NPT_FAILED(NPT_ParseInteger(input+5, m_Month, false)) || + NPT_FAILED(NPT_ParseInteger(input+8, m_Day, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // parse remaining fields if any + if (input_size > 10) { + // parse the timezone part + if (input[input_size-1] == 'Z') { + m_TimeZone = 0; + input[input_size-1] = '\0'; + } else if (input[input_size-6] == '+' || input[input_size-6] == '-') { + if (input[input_size-3] != ':') return NPT_ERROR_INVALID_SYNTAX; + input[input_size-3] = '\0'; + unsigned int hh, mm; + if (NPT_FAILED(NPT_ParseInteger(input+input_size-5, hh, false)) || + NPT_FAILED(NPT_ParseInteger(input+input_size-2, mm, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + if (hh > 59 || mm > 59) return NPT_ERROR_INVALID_SYNTAX; + m_TimeZone = hh*60+mm; + if (input[input_size-6] == '-') m_TimeZone = -m_TimeZone; + input[input_size-6] = '\0'; + } + + // parse fields + if (NPT_FAILED(NPT_ParseInteger(input+11, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+14, m_Minutes, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + if (!no_seconds && input[19] == '.') { + char fraction[10]; + fraction[9] = '\0'; + unsigned int fraction_size = NPT_StringLength(&input[20]); + if (fraction_size == 0) return NPT_ERROR_INVALID_SYNTAX; + for (unsigned int i=0; i<9; i++) { + if (i < fraction_size) { + fraction[i] = input[20+i]; + } else { + fraction[i] = '0'; + } + } + if (NPT_FAILED(NPT_ParseInteger(fraction, m_NanoSeconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + input[19] = '\0'; + } else { + m_NanoSeconds = 0; + } + if (!no_seconds) { + if (NPT_FAILED(NPT_ParseInteger(input+17, m_Seconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + } + } + break; + } + + case FORMAT_RFC_1036: + case FORMAT_RFC_1123: { + if (input_size < 26) return NPT_ERROR_INVALID_SYNTAX; + // look for the weekday and separtor + const char* wday = input; + while (*input && *input != ',') { + ++input; + --input_size; + } + if (*input == '\0' || *wday == ',') return NPT_ERROR_INVALID_SYNTAX; + *input++ = '\0'; + --input_size; + + // look for the timezone + char* timezone = input+input_size-1; + unsigned int timezone_size = 0; + while (input_size && *timezone != ' ') { + --timezone; + ++timezone_size; + --input_size; + } + if (input_size == 0) return NPT_ERROR_INVALID_SYNTAX; + *timezone++ = '\0'; + + // check separators + if (input_size < 20) return NPT_ERROR_INVALID_SYNTAX; + unsigned int yl = input_size-18; + if (yl != 2 && yl != 4) return NPT_ERROR_INVALID_SYNTAX; + char sep; + int wday_index; + if (format == FORMAT_RFC_1036) { + sep = '-'; + wday_index = MatchString(wday, NPT_TIME_DAYS_LONG, 7); + } else { + sep = ' '; + wday_index = MatchString(wday, NPT_TIME_DAYS_SHORT, 7); + } + if (input[0] != ' ' || + input[3] != sep || + input[7] != sep || + input[8+yl] != ' ' || + input[11+yl] != ':' || + input[14+yl] != ':') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[3] = input[7] = input[8+yl] = input[11+yl] = input[14+yl] = '\0'; + + // parse fields + m_Month = 1+MatchString(input+4, NPT_TIME_MONTHS, 12); + if (NPT_FAILED(NPT_ParseInteger(input+1, m_Day, false)) || + NPT_FAILED(NPT_ParseInteger(input+8, m_Year, false)) || + NPT_FAILED(NPT_ParseInteger(input+9+yl, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+12+yl, m_Minutes, false)) || + NPT_FAILED(NPT_ParseInteger(input+15+yl, m_Seconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // adjust short year lengths + if (yl == 2) m_Year += 1900; + + // parse the timezone + if (NPT_StringsEqual(timezone, "GMT") || + NPT_StringsEqual(timezone, "UT") || + NPT_StringsEqual(timezone, "Z")) { + m_TimeZone = 0; + } else if (NPT_StringsEqual(timezone, "EDT")) { + m_TimeZone = -4*60; + } else if (NPT_StringsEqual(timezone, "EST") || + NPT_StringsEqual(timezone, "CDT")) { + m_TimeZone = -5*60; + } else if (NPT_StringsEqual(timezone, "CST") || + NPT_StringsEqual(timezone, "MDT")) { + m_TimeZone = -6*60; + } else if (NPT_StringsEqual(timezone, "MST") || + NPT_StringsEqual(timezone, "PDT")) { + m_TimeZone = -7*60; + } else if (NPT_StringsEqual(timezone, "PST")) { + m_TimeZone = -8*60; + } else if (timezone_size == 1) { + if (timezone[0] >= 'A' && timezone[0] <= 'I') { + m_TimeZone = -60*(1+timezone[0]-'A'); + } else if (timezone[0] >= 'K' && timezone[0] <= 'M') { + m_TimeZone = -60*(timezone[0]-'A'); + } else if (timezone[0] >= 'N' && timezone[0] <= 'Y') { + m_TimeZone = 60*(1+timezone[0]-'N'); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + } else if (timezone_size == 5) { + int sign; + if (timezone[0] == '-') { + sign = -1; + } else if (timezone[0] == '+') { + sign = 1; + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + NPT_UInt32 tz; + if (NPT_FAILED(NPT_ParseInteger(timezone+1, tz, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + unsigned int hh = (tz/100); + unsigned int mm = (tz%100); + if (hh > 59 || mm > 59) return NPT_ERROR_INVALID_SYNTAX; + m_TimeZone = sign*(hh*60+mm); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + if ((int)((days+1)%7) != wday_index) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + m_NanoSeconds = 0; + + break; + } + + case FORMAT_ANSI: { + if (input_size != 24) return NPT_ERROR_INVALID_SYNTAX; + + // check separators + if (input[3] != ' ' || + input[7] != ' ' || + input[10] != ' ' || + input[13] != ':' || + input[16] != ':' || + input[19] != ' ') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[3] = input[7] = input[10] = input[13] = input[16] = input[19] = '\0'; + if (input[8] == ' ') input[8] = '0'; + + m_Month = 1+MatchString(input+4, NPT_TIME_MONTHS, 12); + if (NPT_FAILED(NPT_ParseInteger(input+8, m_Day, false)) || + NPT_FAILED(NPT_ParseInteger(input+11, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+14, m_Minutes, false)) || + NPT_FAILED(NPT_ParseInteger(input+17, m_Seconds, false)) || + NPT_FAILED(NPT_ParseInteger(input+20, m_Year, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + if ((int)((days+1)%7) != MatchString(input, NPT_TIME_DAYS_SHORT, 7)) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + m_TimeZone = 0; + m_NanoSeconds = 0; + break; + } + + default: + return NPT_ERROR_INVALID_PARAMETERS; + } + + return CheckDate(*this); +} |