/*
-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
#include <KM_memio.h>
#include <KM_fileio.h>
#include <KM_log.h>
+#include <KM_mutex.h>
#include <ctype.h>
#include <list>
#include <map>
#include <string>
+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 = 1024;
-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&
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
Kumu::Result_t::Delete(int v)
{
- if ( v >= RESULT_NOTAFILE.Value() )
+ if ( v < -99 || v > 99 )
{
DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
return RESULT_FAIL;
}
- 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 )
{
- s_ResultMap[i].rcode = 0;
- s_ResultMap[i++].result = 0;
-
- for ( ; s_ResultMap[i].result != 0 && i < MapMax; i++ )
+ for ( ++i; i < s_MapSize; ++i )
s_ResultMap[i-1] = s_ResultMap[i];
+ --s_MapSize;
return RESULT_OK;
}
}
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 char* l) : value(v), label(l)
+Kumu::Result_t::Result_t(int v, const std::string& s, const std::string& l) : value(v), symbol(s), label(l)
{
- assert(l);
- assert(value < (int)MapMax);
+ assert(!l.empty());
+ assert(!s.empty());
if ( v == 0 )
return;
- if ( ! s_MapInit )
- {
- s_MapInit = true;
- s_ResultMap[0].rcode = v;
- s_ResultMap[0].result = this;
- s_ResultMap[1].rcode = 0;
- s_ResultMap[1].result = 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;
- ui32_t i = 0;
- while ( s_ResultMap[i].result != 0 && i < MapMax )
+ 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
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<byte_t> 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
//
|| ((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++ )
//------------------------------------------------------------------------------------------
-// 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.
//
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
{ // 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;
}
}
//------------------------------------------------------------------------------------------
-#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 <time.h>
+#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 <time.h>
-
-#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;
}
//
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]) )
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' )
{
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] == ':' )
{
return false;
char_count += 3;
- TmpStamp.Second = atoi(datestr + 17);
+ YMDhms.second = strtol(datestr + 17, 0, 10);
}
if ( datestr[19] == '.' )
{
- if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
- return false;
-
+ if ( ! isdigit(datestr[20]) )
+ {
+ return false;
+ }
+
// we don't carry the ms value
- datestr += 4;
+ while ( isdigit(datestr[20]) )
+ {
+ ++datestr;
+ }
+
+ ++datestr;
}
if ( datestr[19] == '-' || datestr[19] == '+' )
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] == '-' ? (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 */
+ 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;
}
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;
}
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)
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<std::string>
+Kumu::km_token_split(const std::string& str, const std::string& separator)
+{
+ std::list<std::string> 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