created new type ArchivableUi16
[asdcplib.git] / src / KM_util.h
index a9c96c66311434e3684e92e1db357d9f115ab80d..b209d27841a890814e1841885a5e1abae6ed4f4d 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2009, John Hurst
+Copyright (c) 2005-2015, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <KM_memio.h>
 #include <KM_error.h>
+#include <KM_tai.h>
 #include <string.h>
-#include <string>
 #include <list>
 
 namespace Kumu
@@ -154,6 +154,10 @@ namespace Kumu
       return (*buf & 0x0f) + 1;
     }
 
+  // Return the BER length required to encode value. A return value of zero
+  // indicates a value too large for this library.
+  ui32_t get_BER_length_for_value(ui64_t valuse);
+
   // read a BER value
   bool read_BER(const byte_t* buf, ui64_t* val);
 
@@ -217,7 +221,7 @@ namespace Kumu
       bool Archive(Kumu::MemIOWriter* Writer) const
        {
          if ( Writer == 0 ) return false;
-         if ( ! Writer->WriteUi32BE(this->size()) ) return false;
+         if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
          typename ArchivableList<T>::const_iterator i = this->begin();
          for ( ; i != this->end(); i++ )
            if ( ! i->Archive(Writer) ) return false;
@@ -226,6 +230,64 @@ namespace Kumu
        }
     };
 
+  // archivable version of std::string
+
+  //
+  class ArchivableString : public std::string, public Kumu::IArchive
+    {
+
+    public:
+      ArchivableString() {}
+      ArchivableString(const char* sz) : std::string(sz) {}
+      ArchivableString(const std::string& s) : std::string(s) {}
+      virtual ~ArchivableString() {}
+
+      bool   HasValue() const { return ! this->empty(); }
+      ui32_t ArchiveLength() const { return sizeof(ui32_t) + static_cast<ui32_t>(this->size()); }
+
+      bool   Archive(MemIOWriter* Writer) const {
+       if ( Writer == 0 ) return false;
+       return Writer->WriteString(*this);
+      }
+
+      bool   Unarchive(MemIOReader* Reader) {
+       if ( Reader == 0 ) return false;
+       return Reader->ReadString(*this);
+      }
+    };
+
+  //
+  class ArchivableUi16 : public Kumu::IArchive
+    {
+      ui16_t m_Value;
+
+    public:
+      ArchivableUi16() : m_Value(0) {}
+      ArchivableUi16(const ui16_t& value) : m_Value(value) {}
+      virtual ~ArchivableUi16() {}
+
+      bool   HasValue() const { return true; }
+      ui32_t ArchiveLength() const { return sizeof(ui16_t); }
+
+      bool   Archive(MemIOWriter* Writer) const {
+       if ( Writer == 0 ) return false;
+       return Writer->WriteUi16BE(m_Value);
+      }
+
+      bool   Unarchive(MemIOReader* Reader) {
+       if ( Reader == 0 ) return false;
+       return Reader->ReadUi16BE(&m_Value);
+      }
+
+      const char* EncodeString(char* str_buf, ui32_t buf_len) const {
+       snprintf(str_buf, buf_len, "%hu", m_Value);
+       return str_buf;
+      }
+    };
+
+  //
+  typedef Kumu::ArchivableList<ArchivableString> StringList;
+
   //
   // the base of all identifier classes, Identifier is not usually used directly
   // see UUID and SymmetricKey below for more detail.
@@ -283,6 +345,8 @@ namespace Kumu
       inline bool DecodeHex(const char* str) {
        ui32_t char_count;
        m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
+       if ( m_HasValue && char_count != SIZE )
+         m_HasValue = false;
        return m_HasValue;
       }
 
@@ -297,6 +361,8 @@ namespace Kumu
       inline bool DecodeBase64(const char* str) {
        ui32_t char_count;
        m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
+       if ( m_HasValue && char_count != SIZE )
+         m_HasValue = false;
        return m_HasValue;
       }
 
@@ -370,17 +436,16 @@ namespace Kumu
   // UTC time+date representation
   class Timestamp : public IArchive
     {
-    public:
-      ui16_t Year;
-      ui8_t  Month;
-      ui8_t  Day;
-      ui8_t  Hour;
-      ui8_t  Minute;
-      ui8_t  Second;
+      TAI::tai m_Timestamp; // always UTC
+      i32_t m_TZOffsetMinutes;
 
+   public:
       Timestamp();
       Timestamp(const Timestamp& rhs);
       Timestamp(const char* datestr);
+      Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day);
+      Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day,
+               const ui8_t&  Hour, const ui8_t&  Minute, const ui8_t&  Second);
       virtual ~Timestamp();
 
       const Timestamp& operator=(const Timestamp& rhs);
@@ -389,22 +454,37 @@ namespace Kumu
       bool operator==(const Timestamp& rhs) const;
       bool operator!=(const Timestamp& rhs) const;
 
+      // always UTC
+      void GetComponents(ui16_t& Year, ui8_t&  Month, ui8_t&  Day,
+                        ui8_t&  Hour, ui8_t&  Minute, ui8_t&  Second) const;      
+      void 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);
+
       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
       // returns 0 if the buffer is smaller than DateTimeLen
       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
-      const char* EncodeStringWithOffset(char* str_buf, ui32_t buf_len,
-                                        i32_t offset_minutes = 0) const;
 
       // decode and set value from string formatted by EncodeString
       bool        DecodeString(const char* datestr);
 
-      // Add the given number of days, hours, or minutes to the timestamp value.
+      // Add the given number of days, hours, minutes, or seconds to the timestamp value.
       // Values less than zero will cause the timestamp to decrease
-      void AddDays(i32_t);
-      void AddHours(i32_t);
-      void AddMinutes(i32_t);
+      inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
+      inline  void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
+      inline  void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
+      inline  void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
 
-      // Read and write the timestamp value as a byte string having
+      // returns false if the requested adjustment is out of range
+      bool SetTZOffsetMinutes(const i32_t& minutes);
+      inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
+
+      // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
+      ui64_t GetCTime() const;
+
+      // Set internal time to the number of seconds since the Unix epoch UTC
+      void SetCTime(const ui64_t& ctime);
+
+      // Read and write the timestamp (always UTC) value as a byte string having
       // the following format:
       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
@@ -458,7 +538,7 @@ namespace Kumu
 
       inline virtual bool HasValue() const { return m_Length > 0; }
 
-      inline virtual ui32_t ArchiveLength() const { return m_Length; }
+      inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + m_Length; }
 
       inline virtual bool Archive(MemIOWriter* Writer) const {
        assert(Writer);
@@ -478,6 +558,41 @@ namespace Kumu
       }
     };
 
+  inline void hexdump(const ByteString& buf, FILE* stream = 0) {
+    hexdump(buf.RoData(), buf.Length(), stream);
+  }
+
+  // Locates the first occurrence of the null-terminated string s2 in the string s1, where not more
+  // than n characters are searched.  Characters that appear after a `\0' character are not searched.
+  // Reproduced here from BSD for portability.
+  const char *km_strnstr(const char *s1, const char *s2, size_t n);
+
+  // Split the input string into tokens using the given separator. If the separator is not found the
+  // entire string will be returned as a single-item list.  Empty items will be recorded for
+  // adjacent instances of the separator. E.g., "/foo//bar/" will return ["", "foo", "", "bar", ""].
+  std::list<std::string> km_token_split(const std::string& str, const std::string& separator);
+
+  // Join the tokens in the given list using delimiter. If prefix is defined then each token
+  // will be concatenated with the prefix before being added to the composite string.
+  template <class T>
+    std::string
+    km_join(const T& list, const std::string& delimiter, const std::string& prefix = "")
+    {
+      std::string result;
+
+      for ( typename T::const_iterator i = list.begin(); i != list.end(); ++i )
+       {
+         if ( i != list.begin() )
+           {
+             result += delimiter;
+           }
+      
+         result += prefix + *i;
+       }
+
+      return result;
+    }
+
 } // namespace Kumu