Forgot a fix.
[asdcplib.git] / src / KM_util.cpp
index c8cbb1c649901656f413e8fc0dfe80adcca8bd0c..0f8976a159a8ad9cb58a40034b3903d75af5572b 100755 (executable)
@@ -36,10 +36,131 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_log.h>
 #include <ctype.h>
 #include <list>
+#include <map>
 #include <string>
 
 //------------------------------------------------------------------------------------------
 
+// Result_t Internals
+
+struct map_entry_t
+{
+  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];
+
+//
+const Kumu::Result_t&
+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++ )
+    {
+      if ( s_ResultMap[i].rcode == v )
+       return *s_ResultMap[i].result;
+    }
+
+  DefaultLogSink().Error("Unknown result code: %ld\n", v);
+  return RESULT_FAIL;
+}
+
+//
+Kumu::Result_t
+Kumu::Result_t::Delete(int v)
+{
+  if ( v >= RESULT_NOTAFILE.Value() )
+    {
+      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++ )
+    {
+      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++ )
+           s_ResultMap[i-1] = s_ResultMap[i];
+
+         return RESULT_OK;
+       }
+    }
+
+  return RESULT_FALSE;
+}
+
+
+//
+Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l)
+{
+  assert(l);
+  assert(value < (int)MapMax);
+
+  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;
+    }
+
+  ui32_t i = 0;
+  while ( s_ResultMap[i].result != 0 && i < MapMax )
+    {
+      if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
+       return;
+
+      i++;
+    }
+
+  assert(i+2 < MapMax);
+
+  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() {}
+
+
+//------------------------------------------------------------------------------------------
+// DTrace internals
+
+static int s_DTraceSequence = 0;
+
+Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
+  : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
+{
+  m_Sequence = s_DTraceSequence++;
+  DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
+}
+
+Kumu::DTrace_t::~DTrace_t()
+{
+  if ( m_Watch != 0  )
+    DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
+  else
+    DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
+}
+
+//------------------------------------------------------------------------------------------
+
 
 const char  fill = '=';
 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -195,9 +316,9 @@ Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_co
 i32_t
 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
 {
-  KM_TEST_NULL(str);
-  KM_TEST_NULL(buf);
-  KM_TEST_NULL(conv_size);
+  KM_TEST_NULL_L(str);
+  KM_TEST_NULL_L(buf);
+  KM_TEST_NULL_L(conv_size);
 
   *conv_size = 0;
 
@@ -361,12 +482,12 @@ Kumu::GenRandomUUID(byte_t* buf)
 
 //
 void
-Kumu::GenRandomValue(SymmetricKey& ID)
+Kumu::GenRandomValue(SymmetricKey& Key)
 {
   byte_t tmp_buf[SymmetricKey_Length];
   FortunaRNG RNG;
   RNG.FillRandom(tmp_buf, SymmetricKey_Length);
-  ID.Set(tmp_buf);
+  Key.Set(tmp_buf);
 }
 
 
@@ -460,14 +581,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 %lu exceeds maximum size of 9\n", ber_len);
+          DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
           return false;
         }
       
       if ( val & ber_masks[ber_len - 1] )
         {
          ui64Printer tmp_i(val);
-          DefaultLogSink().Error("BER size %lu too small for value %s\n", tmp_i.c_str());
+          DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
           return false;
         }
     }
@@ -528,6 +649,20 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
   return ( CompareFileTime(&lft, &rft) == -1 );
 }
 
+//
+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 );
+}
+
 inline ui64_t
 seconds_to_ns100(ui32_t seconds)
 {
@@ -613,6 +748,16 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
   return ( timegm(&lhtm) < timegm(&rhtm) );
 }
 
+//
+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) );
+}
+
 //
 void
 Kumu::Timestamp::AddDays(i32_t days)
@@ -720,6 +865,101 @@ Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
   return str_buf;
 }
 
+//
+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]) )
+       || datestr[7] != '-'
+       || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
+    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;
+  if ( datestr[10] == 'T' )
+    {
+      if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
+          || datestr[13] != ':'
+          || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
+       return false;
+
+      char_count += 6;
+      TmpStamp.Hour = atoi(datestr + 11);
+      TmpStamp.Minute = atoi(datestr + 14);
+
+      if ( datestr[16] == ':' )
+       {
+         if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
+           return false;
+
+         char_count += 3;
+         TmpStamp.Second = atoi(datestr + 17);
+       }
+
+      if ( datestr[19] == '.' )
+       {
+         if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
+           return false;
+         
+         // we don't carry the ms value
+         datestr += 4;
+       }
+
+      if ( datestr[19] == '-' || datestr[19] == '+' )
+       {
+         if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
+              || datestr[22] != ':'
+              || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
+           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 )
+           return false;
+
+         else 
+           AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
+       }
+    }
+
+  if ( datestr[char_count] != 0 )
+    {
+      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
+
+  return true;
+}
+
 //
 bool
 Kumu::Timestamp::HasValue() const
@@ -750,31 +990,6 @@ Kumu::Timestamp::Archive(MemIOWriter* Writer) const
   return true;
 }
 
-#if 0
-//
-bool
-Kumu::UnarchiveString(MemIOReader* Reader, std::string&)
-{
-  assert(Reader);
-  ui32_t str_length;
-  if ( ! Reader->ReadUi32BE(&str_length) ) return false;
-  assign((const char*)Reader->CurrentData(), str_length);
-  if ( ! Reader->SkipOffset(str_length) ) return false;
-  return true;
-}
-
-//
-bool
-Kumu::String::Archive(MemIOWriter* Writer) const
-{
-  assert(Writer);
-  if ( ! Writer->WriteUi32BE(length()) ) return false;
-  if ( ! Writer->WriteRaw((const byte_t*)c_str(), length()) ) return false;
-
-  return true;
-}
-#endif
-
 //------------------------------------------------------------------------------------------
 
 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
@@ -803,7 +1018,7 @@ Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
   : m_p(0), m_capacity(0), m_size(0)
 {
   m_p = Buf->RoData();
-  m_capacity = Buf->Capacity();
+  m_capacity = Buf->Length();
   assert(m_p); assert(m_capacity);
 }
 
@@ -855,25 +1070,47 @@ Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
 }
 
 
+// copy the given data into the ByteString, set Length value.
+// Returns error if the ByteString is too small.
+Kumu::Result_t
+Kumu::ByteString::Set(const ByteString& Buf)
+{
+  if ( m_Capacity < Buf.m_Capacity )
+    return RESULT_ALLOC;
+
+  memcpy(m_Data, Buf.m_Data, Buf.m_Length);
+  m_Length = Buf.m_Length;
+  return RESULT_OK;
+}
+
+
 // 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;
 }