fooey
[asdcplib.git] / src / KM_util.cpp
index 08ae2575f76ae0c3cfa971b0468c508d503677c7..b84f7f520ab044ce07e5680d5dbce60ecf97d29c 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-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
@@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_fileio.h>
 #include <KM_log.h>
 #include <KM_tai.h>
+#include <KM_mutex.h>
 #include <ctype.h>
 #include <list>
 #include <map>
@@ -53,14 +54,19 @@ Kumu::Version()
 
 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&
@@ -69,7 +75,10 @@ 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;
@@ -82,22 +91,23 @@ Kumu::Result_t::Find(int v)
 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;
        }
     }
@@ -105,41 +115,51 @@ Kumu::Result_t::Delete(int v)
   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;
 
-  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;
 }
 
@@ -537,9 +557,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.
 //
@@ -605,6 +622,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
@@ -626,14 +657,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;
         }
     }
@@ -774,6 +805,26 @@ Kumu::Timestamp::AddMinutes(i32_t minutes)
     }
 }
 
+//
+void
+Kumu::Timestamp::AddSeconds(i32_t seconds)
+{
+  SYSTEMTIME current_st;
+  FILETIME current_ft;
+  ULARGE_INTEGER current_ul;
+
+  if ( seconds != 0 )
+    {
+      TIMESTAMP_TO_SYSTIME(*this, &current_st);
+      SystemTimeToFileTime(&current_st, &current_ft);
+      memcpy(&current_ul, &current_ft, sizeof(current_ul));
+      current_ul.QuadPart += ( seconds_to_ns100(1) * (i64_t)seconds );
+      memcpy(&current_ft, &current_ul, sizeof(current_ft));
+      FileTimeToSystemTime(&current_ft, &current_st);
+      SYSTIME_TO_TIMESTAMP(&current_st, *this);
+    }
+}
+
 #else // KM_WIN32
 
 #include <time.h>
@@ -889,6 +940,23 @@ Kumu::Timestamp::AddMinutes(i32_t minutes)
     }
 }
 
+//
+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
 
 
@@ -902,6 +970,16 @@ Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
   Second = rhs.Second;
 }
 
+//
+Kumu::Timestamp::Timestamp(const char* datestr) : IArchive()
+{
+  if ( ! DecodeString(datestr) )
+    {
+      *this = Timestamp();
+    }
+}
+
+//
 Kumu::Timestamp::~Timestamp()
 {
 }
@@ -1129,12 +1207,39 @@ Kumu::Timestamp::Archive(MemIOWriter* Writer) const
 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
 }
 
 //------------------------------------------------------------------------------------------