X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FKM_util.cpp;h=d263d6e47bcfd416b30ddf71a164a594a78890cf;hb=5d86f368b2bade7bca7700c74f198ef7f4129b44;hp=76b793901a5eb4e2efc0ad7d85169e5872c3d69d;hpb=aff131e971b71a648caaae20b6a9c84207085321;p=asdcplib.git diff --git a/src/KM_util.cpp b/src/KM_util.cpp index 76b7939..d263d6e 100755 --- a/src/KM_util.cpp +++ b/src/KM_util.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2006, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -34,25 +34,38 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include #include +const char* +Kumu::Version() +{ + return PACKAGE_VERSION; +} + + //------------------------------------------------------------------------------------------ // Result_t Internals struct map_entry_t { - int rcode; + int rcode; Kumu::Result_t* result; }; -const ui32_t MapMax = 512; -const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t)); -static bool s_MapInit = false; -static struct map_entry_t s_ResultMap[MapSize]; + +// WIN32 does not init this in time for use with Result_t(...) below, so it is +// now a pointer that Result_t(...) fills in when it needs it. +static Kumu::Mutex* s_MapLock = 0; + +static ui32_t s_MapSize = 0; +static const ui32_t MapMax = 2048; +static struct map_entry_t s_ResultMap[MapMax]; + // const Kumu::Result_t& @@ -61,54 +74,153 @@ Kumu::Result_t::Find(int v) if ( v == 0 ) return RESULT_OK; - for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ ) + assert(s_MapLock); + AutoMutex L(*s_MapLock); + + for ( ui32_t i = 0; i < s_MapSize; ++i ) { if ( s_ResultMap[i].rcode == v ) return *s_ResultMap[i].result; } - DefaultLogSink().Error("Unknown result code: %ld\n", v); - return RESULT_FAIL; + return RESULT_UNKNOWN; } // -Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l) +Kumu::Result_t +Kumu::Result_t::Delete(int v) { - assert(l); + if ( v < -99 || v > 99 ) + { + DefaultLogSink().Error("Cannot delete core result code: %ld\n", v); + return RESULT_FAIL; + } - if ( v == 0 ) - return; + assert(s_MapLock); + AutoMutex L(*s_MapLock); - if ( ! s_MapInit ) + for ( ui32_t i = 0; i < s_MapSize; ++i ) { - s_MapInit = true; - s_ResultMap[0].rcode = v; - s_ResultMap[0].result = this; - s_ResultMap[1].rcode = 0; - s_ResultMap[1].result = 0; - return; + if ( s_ResultMap[i].rcode == v ) + { + for ( ++i; i < s_MapSize; ++i ) + s_ResultMap[i-1] = s_ResultMap[i]; + + --s_MapSize; + return RESULT_OK; + } } - ui32_t i = 0; - while ( s_ResultMap[i].result != 0 && i < MapMax ) + return RESULT_FALSE; +} + +// +unsigned int +Kumu::Result_t::End() +{ + return s_MapSize; +} + +// +const Kumu::Result_t& +Kumu::Result_t::Get(unsigned int i) +{ + return *s_ResultMap[i].result; +} + +// +Kumu::Result_t::Result_t(int v, const std::string& s, const std::string& l) : value(v), symbol(s), label(l) +{ + assert(!l.empty()); + assert(!s.empty()); + + if ( v == 0 ) + return; + + // This may seem tricky, but it is certain that the static values declared in KM_error.h will + // be created (and thus this method will be called) before main(...) is called. It is not + // until then that threads could be created, thus the mutex will exist before multi-threaded + // access could occur. + if ( s_MapLock == 0 ) + s_MapLock = new Kumu::Mutex; + + assert(s_MapLock); + AutoMutex L(*s_MapLock); + + for ( ui32_t i = 0; i < s_MapSize; ++i ) { - if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 ) + if ( s_ResultMap[i].rcode == v ) return; - - i++; } - assert(i+2 < MapMax); + assert(s_MapSize+1 < MapMax); + + s_ResultMap[s_MapSize].rcode = v; + s_ResultMap[s_MapSize].result = this; + ++s_MapSize; - s_ResultMap[i].rcode = v; - s_ResultMap[i].result = this; - s_ResultMap[i+1].rcode = 0; - s_ResultMap[i+1].result = 0; return; } + +Kumu::Result_t::Result_t(const Result_t& rhs) +{ + value = rhs.value; + symbol = rhs.symbol; + label = rhs.label; + message = rhs.message; +} + Kumu::Result_t::~Result_t() {} +// +const Kumu::Result_t& +Kumu::Result_t::operator=(const Result_t& rhs) +{ + value = rhs.value; + symbol = rhs.symbol; + label = rhs.label; + message = rhs.message; + return *this; +} + +// +const Kumu::Result_t +Kumu::Result_t::operator()(const std::string& message) const +{ + Result_t result = *this; + result.message = message; + return result; +} + +static int const MESSAGE_BUF_MAX = 2048; + +// +const Kumu::Result_t +Kumu::Result_t::operator()(const int& line, const char* filename) const +{ + assert(filename); + char buf[MESSAGE_BUF_MAX]; + snprintf(buf, MESSAGE_BUF_MAX-1, "%s, line %d", filename, line); + + Result_t result = *this; + result.message = buf; + return result; +} + +// +const Kumu::Result_t +Kumu::Result_t::operator()(const std::string& message, const int& line, const char* filename) const +{ + assert(filename); + char buf[MESSAGE_BUF_MAX]; + snprintf(buf, MESSAGE_BUF_MAX-1, "%s, line %d", filename, line); + + Result_t result = *this; + result.message = message + buf; + return result; +} + //------------------------------------------------------------------------------------------ // DTrace internals @@ -336,6 +448,38 @@ Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size) return 0; } +#ifdef CONFIG_RANDOM_UUID + +// convert a memory region to a NULL-terminated hexadecimal string +// +static const char* +bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + if ( bin_buf == 0 + || str_buf == 0 + || ((bin_len * 2) + 1) > str_len ) + return 0; + + char* p = str_buf; + Kumu::mem_ptr rand_buf = new byte_t[bin_len]; + Kumu::FortunaRNG RNG; + RNG.FillRandom(rand_buf, bin_len); + + for ( ui32_t i = 0; i < bin_len; i++ ) + { + *p = (bin_buf[i] >> 4) & 0x0f; + *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10); + p++; + + *p = bin_buf[i] & 0x0f; + *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10); + p++; + } + + *p = '\0'; + return str_buf; +} +#endif // convert a memory region to a NULL-terminated hexadecimal string // @@ -347,6 +491,12 @@ Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_l || ((bin_len * 2) + 1) > str_len ) return 0; +#ifdef CONFIG_RANDOM_UUID + const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID"); + if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' ) + return bin2hex_rand(bin_buf, bin_len, str_buf, str_len); +#endif + char* p = str_buf; for ( ui32_t i = 0; i < bin_len; i++ ) @@ -463,9 +613,6 @@ Kumu::GenRandomValue(SymmetricKey& Key) //------------------------------------------------------------------------------------------ -// read a ber value from the buffer and compare with test value. -// Advances buffer to first character after BER value. - // read a ber value from the buffer and compare with test value. // Advances buffer to first character after BER value. // @@ -531,6 +678,20 @@ static const ui64_t ber_masks[9] = 0 }; +// +ui32_t +Kumu::get_BER_length_for_value(ui64_t val) +{ + for ( ui32_t i = 0; i < 9; i++ ) + { + if ( ( val & ber_masks[i] ) == 0 ) + return i + 1; + } + + ui64Printer tmp_i(val); + DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str()); + return 0; +} // bool @@ -552,14 +713,14 @@ Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len) { // sanity check BER length if ( ber_len > 9 ) { - DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len); + DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len); return false; } - if ( val & ber_masks[ber_len - 1] ) + if ( ( val & ber_masks[ber_len - 1] ) != 0 ) { ui64Printer tmp_i(val); - DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str()); + DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str()); return false; } } @@ -577,248 +738,96 @@ Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len) //------------------------------------------------------------------------------------------ -#ifdef KM_WIN32 - -#define TIMESTAMP_TO_SYSTIME(ts, t) \ - (t)->wYear = (ts).Year; /* year */ \ - (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \ - (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \ - (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \ - (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \ - (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \ - (t)->wDayOfWeek = 0; \ - (t)->wMilliseconds = 0 - -#define SYSTIME_TO_TIMESTAMP(t, ts) \ - (ts).Year = (t)->wYear; /* year */ \ - (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \ - (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \ - (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \ - (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \ - (ts).Second = (t)->wSecond; /* seconds (0 - 60) */ -// -Kumu::Timestamp::Timestamp() : - Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) -{ - SYSTEMTIME sys_time; - GetSystemTime(&sys_time); - SYSTIME_TO_TIMESTAMP(&sys_time, *this); -} +#ifndef KM_WIN32 +#include +#endif // -bool -Kumu::Timestamp::operator<(const Timestamp& rhs) const -{ - SYSTEMTIME lhst, rhst; - FILETIME lft, rft; - - TIMESTAMP_TO_SYSTIME(*this, &lhst); - TIMESTAMP_TO_SYSTIME(rhs, &rhst); - SystemTimeToFileTime(&lhst, &lft); - SystemTimeToFileTime(&rhst, &rft); - return ( CompareFileTime(&lft, &rft) == -1 ); +Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) { + m_Timestamp.now(); } -// -bool -Kumu::Timestamp::operator>(const Timestamp& rhs) const -{ - SYSTEMTIME lhst, rhst; - FILETIME lft, rft; - - TIMESTAMP_TO_SYSTIME(*this, &lhst); - TIMESTAMP_TO_SYSTIME(rhs, &rhst); - SystemTimeToFileTime(&lhst, &lft); - SystemTimeToFileTime(&rhst, &rft); - return ( CompareFileTime(&lft, &rft) == 1 ); +Kumu::Timestamp::Timestamp(const Timestamp& rhs) { + m_Timestamp = rhs.m_Timestamp; + m_TZOffsetMinutes = rhs.m_TZOffsetMinutes; } -inline ui64_t -seconds_to_ns100(ui32_t seconds) -{ - return ((ui64_t)seconds * 10000000); +Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) { + DecodeString(datestr); } -// -void -Kumu::Timestamp::AddDays(i32_t days) -{ - SYSTEMTIME current_st; - FILETIME current_ft; - ULARGE_INTEGER current_ul; - - if ( days != 0 ) - { - TIMESTAMP_TO_SYSTIME(*this, ¤t_st); - SystemTimeToFileTime(¤t_st, ¤t_ft); - memcpy(¤t_ul, ¤t_ft, sizeof(current_ul)); - current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days ); - memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); - FileTimeToSystemTime(¤t_ft, ¤t_st); - SYSTIME_TO_TIMESTAMP(¤t_st, *this); - } +Kumu::Timestamp::~Timestamp() { } // -void -Kumu::Timestamp::AddHours(i32_t hours) +const Kumu::Timestamp& +Kumu::Timestamp::operator=(const Timestamp& rhs) { - SYSTEMTIME current_st; - FILETIME current_ft; - ULARGE_INTEGER current_ul; - - if ( hours != 0 ) - { - TIMESTAMP_TO_SYSTIME(*this, ¤t_st); - SystemTimeToFileTime(¤t_st, ¤t_ft); - memcpy(¤t_ul, ¤t_ft, sizeof(current_ul)); - current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours ); - memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); - FileTimeToSystemTime(¤t_ft, ¤t_st); - SYSTIME_TO_TIMESTAMP(¤t_st, *this); - } + m_Timestamp = rhs.m_Timestamp; + m_TZOffsetMinutes = rhs.m_TZOffsetMinutes; + return *this; } -#else // KM_WIN32 - -#include - -#define TIMESTAMP_TO_TM(ts, t) \ - (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \ - (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \ - (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \ - (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \ - (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \ - (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */ - -#define TM_TO_TIMESTAMP(t, ts) \ - (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \ - (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \ - (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \ - (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \ - (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \ - (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */ - -// -Kumu::Timestamp::Timestamp() : - Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) -{ - time_t t_now = time(0); - struct tm* now = gmtime(&t_now); - TM_TO_TIMESTAMP(now, *this); +bool Kumu::Timestamp::operator<(const Timestamp& rhs) const { + return m_Timestamp.x < rhs.m_Timestamp.x; } -// -bool -Kumu::Timestamp::operator<(const Timestamp& rhs) const -{ - struct tm lhtm, rhtm; - TIMESTAMP_TO_TM(*this, &lhtm); - TIMESTAMP_TO_TM(rhs, &rhtm); - return ( timegm(&lhtm) < timegm(&rhtm) ); +bool Kumu::Timestamp::operator>(const Timestamp& rhs) const { + return m_Timestamp.x > rhs.m_Timestamp.x; } -// -bool -Kumu::Timestamp::operator>(const Timestamp& rhs) const -{ - struct tm lhtm, rhtm; - TIMESTAMP_TO_TM(*this, &lhtm); - TIMESTAMP_TO_TM(rhs, &rhtm); - return ( timegm(&lhtm) > timegm(&rhtm) ); +bool Kumu::Timestamp::operator==(const Timestamp& rhs) const { + return m_Timestamp.x == rhs.m_Timestamp.x; } -// -void -Kumu::Timestamp::AddDays(i32_t days) -{ - struct tm current; - - if ( days != 0 ) - { - TIMESTAMP_TO_TM(*this, ¤t); - time_t adj_time = timegm(¤t); - adj_time += 86400 * days; - struct tm* now = gmtime(&adj_time); - TM_TO_TIMESTAMP(now, *this); - } +bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const { + return m_Timestamp.x != rhs.m_Timestamp.x; } // void -Kumu::Timestamp::AddHours(i32_t hours) -{ - struct tm current; - - if ( hours != 0 ) - { - TIMESTAMP_TO_TM(*this, ¤t); - time_t adj_time = timegm(¤t); - adj_time += 3600 * hours; - struct tm* now = gmtime(&adj_time); - TM_TO_TIMESTAMP(now, *this); - } -} - -#endif // KM_WIN32 - - -Kumu::Timestamp::Timestamp(const Timestamp& rhs) -{ - Year = rhs.Year; - Month = rhs.Month; - Day = rhs.Day; - Hour = rhs.Hour; - Minute = rhs.Minute; - Second = rhs.Second; -} - -Kumu::Timestamp::~Timestamp() +Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day, + ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const { + TAI::caltime ct; + ct = m_Timestamp; + Year = ct.date.year; + Month = ct.date.month; + Day = ct.date.day; + Hour = ct.hour; + Minute = ct.minute; + Second = ct.second; } // -const Kumu::Timestamp& -Kumu::Timestamp::operator=(const Timestamp& rhs) +void +Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day, + const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second) { - Year = rhs.Year; - Month = rhs.Month; - Day = rhs.Day; - Hour = rhs.Hour; - Minute = rhs.Minute; - Second = rhs.Second; - return *this; + TAI::caltime ct; + ct.date.year = Year; + ct.date.month = Month; + ct.date.day = Day; + ct.hour = Hour; + ct.minute = Minute; + ct.second = Second; + ct.offset = 0; + m_Timestamp = ct; + m_TZOffsetMinutes = 0; } -// +// returns false if the requested adjustment is out of range bool -Kumu::Timestamp::operator==(const Timestamp& rhs) const +Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes) { - if ( Year == rhs.Year - && Month == rhs.Month - && Day == rhs.Day - && Hour == rhs.Hour - && Minute == rhs.Minute - && Second == rhs.Second ) - return true; - - return false; -} + static const i32_t tz_limit = 14 * 60 * 60; -// -bool -Kumu::Timestamp::operator!=(const Timestamp& rhs) const -{ - if ( Year != rhs.Year - || Month != rhs.Month - || Day != rhs.Day - || Hour != rhs.Hour - || Minute != rhs.Minute - || Second != rhs.Second ) - return true; - - return false; + if ( minutes < ( - tz_limit) || minutes > tz_limit ) + return false; + + m_TZOffsetMinutes = minutes; + return true; } // @@ -828,20 +837,42 @@ Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const if ( buf_len < ( DateTimeLen + 1 ) ) return 0; - // 2004-05-01T13:20:00-00:00 - snprintf(str_buf, buf_len, - "%04hu-%02hu-%02huT%02hu:%02hu:%02hu-00:00", - Year, Month, Day, Hour, Minute, Second); + ui16_t year; + ui8_t month, day, hour, minute, second; + ui32_t ofst_hours = 0, ofst_minutes = 0; + char direction = '+'; + + if ( m_TZOffsetMinutes == 0 ) + { + GetComponents(year, month, day, hour, minute, second); + } + else + { + // calculate local time + Kumu::Timestamp tmp_t(*this); + tmp_t.AddMinutes(m_TZOffsetMinutes); + tmp_t.GetComponents(year, month, day, hour, minute, second); + + ofst_hours = Kumu::xabs(m_TZOffsetMinutes) / 60; + ofst_minutes = Kumu::xabs(m_TZOffsetMinutes) % 60; + + if ( m_TZOffsetMinutes < 0 ) + direction = '-'; + } + // 2004-05-01T13:20:00+00:00 + snprintf(str_buf, buf_len, + "%04hu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu%c%02u:%02u", + year, month, day, hour, minute, second, + direction, ofst_hours, ofst_minutes); + return str_buf; } -// +// ^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(?:([+-]\d{2}):(\d{2}))?)?$ bool Kumu::Timestamp::DecodeString(const char* datestr) { - Timestamp TmpStamp; - if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) ) || datestr[4] != '-' || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) ) @@ -850,10 +881,14 @@ Kumu::Timestamp::DecodeString(const char* datestr) return false; ui32_t char_count = 10; - TmpStamp.Year = atoi(datestr); - TmpStamp.Month = atoi(datestr + 5); - TmpStamp.Day = atoi(datestr + 8); - TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0; + TAI::caltime YMDhms; + YMDhms.hour = 0; + YMDhms.minute = 0; + YMDhms.second = 0; + YMDhms.offset = 0; + YMDhms.date.year = strtol(datestr, 0, 10); + YMDhms.date.month = strtol(datestr + 5, 0, 10); + YMDhms.date.day = strtol(datestr + 8, 0, 10); if ( datestr[10] == 'T' ) { @@ -863,8 +898,8 @@ Kumu::Timestamp::DecodeString(const char* datestr) return false; char_count += 6; - TmpStamp.Hour = atoi(datestr + 11); - TmpStamp.Minute = atoi(datestr + 14); + YMDhms.hour = strtol(datestr + 11, 0, 10); + YMDhms.minute = strtol(datestr + 14, 0, 10); if ( datestr[16] == ':' ) { @@ -872,7 +907,23 @@ Kumu::Timestamp::DecodeString(const char* datestr) return false; char_count += 3; - TmpStamp.Second = atoi(datestr + 17); + YMDhms.second = strtol(datestr + 17, 0, 10); + } + + if ( datestr[19] == '.' ) + { + if ( ! isdigit(datestr[20]) ) + { + return false; + } + + // we don't carry the ms value + while ( isdigit(datestr[20]) ) + { + ++datestr; + } + + ++datestr; } if ( datestr[19] == '-' || datestr[19] == '+' ) @@ -883,42 +934,37 @@ Kumu::Timestamp::DecodeString(const char* datestr) return false; char_count += 6; - ui32_t TZ_hh = atoi(datestr + 20); - ui32_t TZ_mm = atoi(datestr + 23); - - if ( TZ_mm != 0 ) - DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm); - - if ( TZ_hh > 12 ) + + ui32_t TZ_hh = strtol(datestr + 20, 0, 10); + ui32_t TZ_mm = strtol(datestr + 23, 0, 10); + if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0))) return false; - else - AddHours( (datestr[19] == '-' ? (-TZ_hh) : TZ_hh)); + i32_t TZ_offset = 60 * TZ_hh + TZ_mm; + if (datestr[19] == '-') + TZ_offset = -TZ_offset; + /* at this point, TZ_offset reflects the contents of the string */ + + /* a negative offset is behind UTC and so needs to increment to + * convert, while a positive offset must do the reverse */ + YMDhms.offset = TZ_offset; + } + else if (datestr[19] == 'Z') + { + /* act as if the offset were +00:00 */ + char_count++; } } if ( datestr[char_count] != 0 ) { - DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n", - datestr, char_count); + Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n", + datestr, char_count); return false; } - -#ifdef KM_WIN32 - SYSTEMTIME st; - FILETIME ft; - TIMESTAMP_TO_SYSTIME(TmpStamp, &st); - if ( SystemTimeToFileTime(&st, &ft) == 0 ) - return false; - SYSTIME_TO_TIMESTAMP(&st, *this); -#else - struct tm stm; - TIMESTAMP_TO_TM(TmpStamp, &stm); - if ( timegm(&stm) == 0 ) - return false; - TM_TO_TIMESTAMP(&stm, *this); -#endif - + + m_Timestamp = YMDhms; + m_TZOffsetMinutes = YMDhms.offset; return true; } @@ -926,19 +972,25 @@ Kumu::Timestamp::DecodeString(const char* datestr) bool Kumu::Timestamp::HasValue() const { - if ( Year || Month || Day || Hour || Minute || Second ) - return true; - - return false; + return true; } // bool Kumu::Timestamp::Unarchive(MemIOReader* Reader) { + ui16_t year; + ui8_t month, day, hour, minute, second, tick; + assert(Reader); - if ( ! Reader->ReadUi16BE(&Year) ) return false; - if ( ! Reader->ReadRaw(&Month, 6) ) return false; + if ( ! Reader->ReadUi16BE(&year) ) return false; + if ( ! Reader->ReadUi8(&month) ) return false; + if ( ! Reader->ReadUi8(&day) ) return false; + if ( ! Reader->ReadUi8(&hour) ) return false; + if ( ! Reader->ReadUi8(&minute) ) return false; + if ( ! Reader->ReadUi8(&second) ) return false; + if ( ! Reader->ReadUi8(&tick) ) return false; + SetComponents(year, month, day, hour, minute, second); return true; } @@ -947,11 +999,38 @@ bool Kumu::Timestamp::Archive(MemIOWriter* Writer) const { assert(Writer); - if ( ! Writer->WriteUi16BE(Year) ) return false; - if ( ! Writer->WriteRaw(&Month, 6) ) return false; + + ui16_t year; + ui8_t month, day, hour, minute, second, tick = 0; + GetComponents(year, month, day, hour, minute, second); + + if ( ! Writer->WriteUi16BE(year) ) return false; + if ( ! Writer->WriteUi8(month) ) return false; + if ( ! Writer->WriteUi8(day) ) return false; + if ( ! Writer->WriteUi8(hour) ) return false; + if ( ! Writer->WriteUi8(minute) ) return false; + if ( ! Writer->WriteUi8(second) ) return false; + if ( ! Writer->WriteUi8(tick) ) return false; return true; } +// +ui64_t +Kumu::Timestamp::GetCTime() const +{ + return m_Timestamp.x - ui64_C(4611686018427387914); +} + +// +void +Kumu::Timestamp::SetCTime(const ui64_t& ctime) +{ + m_Timestamp.x = ctime + ui64_C(4611686018427387914); +} + + + + //------------------------------------------------------------------------------------------ Kumu::MemIOWriter::MemIOWriter(ByteString* Buf) @@ -1047,24 +1126,32 @@ Kumu::ByteString::Set(const ByteString& Buf) // Sets the size of the internally allocate buffer. -// Resets content length to zero. Kumu::Result_t Kumu::ByteString::Capacity(ui32_t cap_size) { - if ( m_Capacity < cap_size ) + if ( m_Capacity >= cap_size ) + return RESULT_OK; + + byte_t* tmp_data = 0; + if ( m_Data != 0 ) { - if ( m_Data != 0 ) + if ( m_Length > 0 ) + tmp_data = m_Data; + else free(m_Data); + } - m_Data = (byte_t*)malloc(cap_size); - - if ( m_Data == 0 ) - return RESULT_ALLOC; - - m_Capacity = cap_size; - m_Length = 0; + if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 ) + return RESULT_ALLOC; + + if ( tmp_data != 0 ) + { + assert(m_Length > 0); + memcpy(m_Data, tmp_data, m_Length); + free(tmp_data); } - + + m_Capacity = cap_size; return RESULT_OK; } @@ -1106,6 +1193,58 @@ Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len) return result; } +//------------------------------------------------------------------------------------------ + +// +const char* +Kumu::km_strnstr(const char *s, const char *find, size_t slen) +{ + char c, sc; + size_t len; + + if ( ( c = *find++ ) != '\0' ) + { + len = strlen(find); + do + { + do + { + if ( slen-- < 1 || ( sc = *s++ ) == '\0' ) + return 0; + } + while ( sc != c ); + + if ( len > slen ) + return 0; + } + while ( strncmp(s, find, len) != 0 ); + --s; + } + + return s; +} + +// +std::list +Kumu::km_token_split(const std::string& str, const std::string& separator) +{ + std::list components; + const char* pstr = str.c_str(); + const char* r = strstr(pstr, separator.c_str()); + + while ( r != 0 ) + { + assert(r >= pstr); + std::string tmp_str; + tmp_str.assign(pstr, r - pstr); + components.push_back(tmp_str); + pstr = r + separator.size(); + r = strstr(pstr, separator.c_str()); + } + + components.push_back(std::string(pstr)); + return components; +} // // end KM_util.cpp