X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FKM_util.cpp;h=2624f07fcb1bf6533153c787c9892360b07e9564;hb=f6382ee078c3d7de2dbf3a01f5624345d2c61e4a;hp=b860b6436ce1ebd659b0aceca7d09f194c11cae6;hpb=7827a7e7572601440568788cb028ee883498fa15;p=asdcplib.git diff --git a/src/KM_util.cpp b/src/KM_util.cpp index b860b64..2624f07 100755 --- a/src/KM_util.cpp +++ b/src/KM_util.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2006, John Hurst +Copyright (c) 2005-2009, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -34,11 +34,19 @@ 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 @@ -67,8 +75,7 @@ Kumu::Result_t::Find(int v) return *s_ResultMap[i].result; } - DefaultLogSink().Error("Unknown result code: %ld\n", v); - return RESULT_FAIL; + return RESULT_UNKNOWN; } // @@ -365,6 +372,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 // @@ -376,6 +415,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++ ) @@ -492,9 +537,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. // @@ -560,6 +602,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 @@ -581,14 +637,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; } } @@ -682,7 +738,7 @@ Kumu::Timestamp::AddDays(i32_t days) 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 ); + current_ul.QuadPart += ( seconds_to_ns100(86400) * (i64_t)days ); memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); FileTimeToSystemTime(¤t_ft, ¤t_st); SYSTIME_TO_TIMESTAMP(¤t_st, *this); @@ -702,7 +758,47 @@ Kumu::Timestamp::AddHours(i32_t hours) 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 ); + current_ul.QuadPart += ( seconds_to_ns100(3600) * (i64_t)hours ); + memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); + FileTimeToSystemTime(¤t_ft, ¤t_st); + SYSTIME_TO_TIMESTAMP(¤t_st, *this); + } +} + +// +void +Kumu::Timestamp::AddMinutes(i32_t minutes) +{ + SYSTEMTIME current_st; + FILETIME current_ft; + ULARGE_INTEGER current_ul; + + if ( minutes != 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(60) * (i64_t)minutes ); + memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); + FileTimeToSystemTime(¤t_ft, ¤t_st); + SYSTIME_TO_TIMESTAMP(¤t_st, *this); + } +} + +// +void +Kumu::Timestamp::AddSeconds(i32_t seconds) +{ + SYSTEMTIME current_st; + FILETIME current_ft; + ULARGE_INTEGER current_ul; + + if ( seconds != 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(1) * (i64_t)seconds ); memcpy(¤t_ft, ¤t_ul, sizeof(current_ft)); FileTimeToSystemTime(¤t_ft, ¤t_st); SYSTIME_TO_TIMESTAMP(¤t_st, *this); @@ -713,64 +809,80 @@ Kumu::Timestamp::AddHours(i32_t hours) #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) */ +#define TIMESTAMP_TO_CALTIME(ts, ct) \ + (ct)->date.year = (ts).Year; /* year */ \ + (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \ + (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \ + (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \ + (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \ + (ct)->second = (ts).Second; /* seconds (0 - 60) */ \ + (ct)->offset = 0; + +#define CALTIME_TO_TIMESTAMP(ct, ts) \ + assert((ct)->offset == 0); \ + (ts).Year = (ct)->date.year; /* year */ \ + (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \ + (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \ + (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \ + (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \ + (ts).Second = (ct)->second; /* seconds (0 - 60) */ + // Kumu::Timestamp::Timestamp() : - Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) + 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); + Kumu::TAI::tai now; + Kumu::TAI::caltime ct; + now.now(); + ct = now; + CALTIME_TO_TIMESTAMP(&ct, *this) } // 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) ); + Kumu::TAI::caltime lh_ct, rh_ct; + TIMESTAMP_TO_CALTIME(*this, &lh_ct) + TIMESTAMP_TO_CALTIME(rhs, &rh_ct) + + Kumu::TAI::tai lh_tai, rh_tai; + lh_tai = lh_ct; + rh_tai = rh_ct; + + return ( lh_tai.x < rh_tai.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) ); + Kumu::TAI::caltime lh_ct, rh_ct; + TIMESTAMP_TO_CALTIME(*this, &lh_ct) + TIMESTAMP_TO_CALTIME(rhs, &rh_ct) + + Kumu::TAI::tai lh_tai, rh_tai; + lh_tai = lh_ct; + rh_tai = rh_ct; + + return ( lh_tai.x > rh_tai.x ); } // void Kumu::Timestamp::AddDays(i32_t days) { - struct tm current; + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; 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); + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_days(days); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) } } @@ -778,15 +890,50 @@ Kumu::Timestamp::AddDays(i32_t days) void Kumu::Timestamp::AddHours(i32_t hours) { - struct tm current; + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; 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); + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_hours(hours); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) + } +} + +// +void +Kumu::Timestamp::AddMinutes(i32_t minutes) +{ + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; + + if ( minutes != 0 ) + { + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_minutes(minutes); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) + } +} + +// +void +Kumu::Timestamp::AddSeconds(i32_t seconds) +{ + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; + + if ( seconds != 0 ) + { + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_seconds(seconds); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) } } @@ -853,15 +1000,42 @@ Kumu::Timestamp::operator!=(const Timestamp& rhs) const // const char* Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const +{ + return EncodeStringWithOffset(str_buf, buf_len, 0); +} + +// +const char* +Kumu::Timestamp::EncodeStringWithOffset(char* str_buf, ui32_t buf_len, + i32_t offset_minutes) const { if ( buf_len < ( DateTimeLen + 1 ) ) return 0; - // 2004-05-01T13:20:00-00:00 + // ensure offset is within +/- 14 hours + if ((offset_minutes < -14 * 60) || (offset_minutes > 14 * 60)) + return 0; + + // set the apparent time + Kumu::Timestamp tmp_t(*this); + tmp_t.AddMinutes(offset_minutes); + + char direction = '+'; + if (offset_minutes < 0) { + direction = '-'; + // need absolute offset from zero + offset_minutes = -offset_minutes; + } + + // 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); - + "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu", + tmp_t.Year, tmp_t.Month, tmp_t.Day, + tmp_t.Hour, tmp_t.Minute, tmp_t.Second, + direction, + offset_minutes / 60, + offset_minutes % 60); + return str_buf; } @@ -921,24 +1095,32 @@ 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 ) + if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0))) return false; - else - AddHours( (datestr[19] == '-' ? (0 - 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 */ + TmpStamp.AddMinutes(-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; } @@ -950,11 +1132,12 @@ Kumu::Timestamp::DecodeString(const char* datestr) 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); + Kumu::TAI::tai t; + Kumu::TAI::caltime ct; + TIMESTAMP_TO_CALTIME(TmpStamp, &ct); + t = ct; // back and forth to tai to normalize offset + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) #endif return true; @@ -990,6 +1173,45 @@ Kumu::Timestamp::Archive(MemIOWriter* Writer) const return true; } +// +long +Kumu::Timestamp::GetSecondsSinceEpoch(void) const +{ +#ifdef KM_WIN32 + SYSTEMTIME timeST; + TIMESTAMP_TO_SYSTIME(*this, &timeST); + FILETIME timeFT; + SystemTimeToFileTime(&timeST, &timeFT); + ULARGE_INTEGER timeUL; + timeUL.LowPart = timeFT.dwLowDateTime; + timeUL.HighPart = timeFT.dwHighDateTime; + + SYSTEMTIME epochST; + epochST.wYear = 1970; + epochST.wMonth = 0; + epochST.wDayOfWeek = 4; + epochST.wDay = 1; + epochST.wHour = 0; + epochST.wMinute = 0; + epochST.wSecond = 0; + epochST.wMilliseconds = 0; + FILETIME epochFT; + SystemTimeToFileTime(&epochST, &epochFT); + ULARGE_INTEGER epochUL; + epochUL.LowPart = epochFT.dwLowDateTime; + epochUL.HighPart = epochFT.dwHighDateTime; + + return (timeUL.QuadPart - epochUL.QuadPart) / 10000000; +#else + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; + TIMESTAMP_TO_CALTIME(*this, &ct); + t = ct; + + return (long) (t.x - ui64_C(4611686018427387914)); +#endif +} + //------------------------------------------------------------------------------------------ Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)