/*
-Copyright (c) 2005-2009, John Hurst
+Copyright (c) 2005-2011, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <KM_fileio.h>
#include <KM_log.h>
#include <KM_tai.h>
+#include <KM_mutex.h>
#include <ctype.h>
#include <list>
#include <map>
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;
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 char* s, const char* l) : value(v), symbol(s), label(l)
{
assert(l);
- assert(value < (int)MapMax);
+ assert(s);
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;
+
+ assert(s_MapLock);
+ AutoMutex L(*s_MapLock);
- ui32_t i = 0;
- while ( s_ResultMap[i].result != 0 && i < MapMax )
+ 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;
}
//------------------------------------------------------------------------------------------
-// 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;
}
}
}
}
+//
+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);
+ }
+}
+
#else // KM_WIN32
#include <time.h>
}
}
+//
+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)
+ }
+}
+
#endif // KM_WIN32
Second = rhs.Second;
}
+//
+Kumu::Timestamp::Timestamp(const char* datestr) : IArchive()
+{
+ if ( ! DecodeString(datestr) )
+ {
+ *this = Timestamp();
+ }
+}
+
+//
Kumu::Timestamp::~Timestamp()
{
}
//
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;
}
char_count += 6;
- i32_t TZ_mm = 60 * atoi(datestr + 20);
- TZ_mm += atoi(datestr + 23);
- if (datestr[19] == '-')
- TZ_mm = -TZ_mm;
-
- if ((TZ_mm > 14 * 60) || (TZ_mm < -14 * 60))
+ ui32_t TZ_hh = atoi(datestr + 20);
+ ui32_t TZ_mm = atoi(datestr + 23);
+ if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
return false;
- else
- TmpStamp.AddMinutes(-TZ_mm);
+ 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')
{
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)