logging re-write
[asdcplib.git] / src / KM_util.h
index 900962459933fb18d86d635e37ab598072fd5fa3..f7176f6aa04457a6017bafa3322668b198fa94cf 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2007, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -36,22 +36,34 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_error.h>
 #include <string.h>
 #include <string>
+#include <list>
 
 namespace Kumu
 {
 
+  // a class that represents the string form of a value
   template <class T, int SIZE = 16>
     class IntPrinter : public std::string
   {
-    protected:
+    KM_NO_COPY_CONSTRUCT(IntPrinter);
     IntPrinter();
+
+    protected:
+    const char* m_format;
     char m_strbuf[SIZE];
     
     public:
-    inline const char* c_str() { return m_strbuf; }
-    
     IntPrinter(const char* format, T value) {
-      snprintf(m_strbuf, SIZE, format, value);
+      assert(format);
+      m_format = format;
+      snprintf(m_strbuf, SIZE, m_format, value);
+    }
+
+    inline operator const char*() { return m_strbuf; }
+    inline const char* c_str() { return m_strbuf; }
+    inline const char* set_value(T value) {
+      snprintf(m_strbuf, SIZE, m_format, value);
+      return m_strbuf;
     }
   };
 
@@ -106,7 +118,7 @@ namespace Kumu
   i32_t       hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
 
   // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
-  // if the binary buffer was large enough to hold the result. If the output buffer
+  // if the output buffer was large enough to hold the result. If the output buffer
   // is too small or any of the pointer arguments are NULL, the subroutine will
   // return 0.
   //
@@ -152,18 +164,70 @@ namespace Kumu
   //----------------------------------------------------------------
   //
 
+  // an abstract base class that objects implement to serialize state
+  // to and from a binary stream.
   class IArchive
     {
     public:
       virtual ~IArchive(){}
-      virtual bool HasValue() const = 0;
-      virtual bool Archive(MemIOWriter* Writer) const = 0;
-      virtual bool Unarchive(MemIOReader* Reader) = 0;
+      virtual bool   HasValue() const = 0;
+      virtual ui32_t ArchiveLength() const = 0;
+      virtual bool   Archive(MemIOWriter* Writer) const = 0;
+      virtual bool   Unarchive(MemIOReader* Reader) = 0;
     };
 
+  //
+  template <class T>
+  class ArchivableList : public std::list<T>, public IArchive
+    {
+    public:
+      ArchivableList() {}
+      virtual ~ArchivableList() {}
+
+      bool HasValue() const { return ! this->empty(); }
+
+      ui32_t ArchiveLength() const
+      {
+       ui32_t arch_size = sizeof(ui32_t);
+
+       typename ArchivableList<T>::const_iterator i = this->begin();
+       for ( ; i != this->end(); i++ )
+         arch_size += i->ArchiveLength();
+
+       return arch_size;
+      }
+
+      bool Unarchive(Kumu::MemIOReader* Reader)
+       {
+         if ( Reader == 0 ) return false;
+         ui32_t read_size = 0;
+         if ( ! Reader->ReadUi32BE(&read_size) ) return false;
+         for ( ui32_t i = 0; i < read_size; i++ )
+           {
+             T TmpTP;
+             if ( ! TmpTP.Unarchive(Reader) ) return false;
+             this->push_back(TmpTP);
+           }
+
+         return true;
+       }
+
+      bool Archive(Kumu::MemIOWriter* Writer) const
+       {
+         if ( Writer == 0 ) return false;
+         if ( ! Writer->WriteUi32BE(this->size()) ) return false;
+         typename ArchivableList<T>::const_iterator i = this->begin();
+         for ( ; i != this->end(); i++ )
+           if ( ! i->Archive(Writer) ) return false;
+
+         return true;
+       }
+    };
 
   //
-  // the base of all identifier classes
+  // the base of all identifier classes, Identifier is not usually used directly
+  // see UUID and SymmetricKey below for more detail.
+  //
   template <ui32_t SIZE>
     class Identifier : public IArchive
     {
@@ -173,92 +237,86 @@ namespace Kumu
 
     public:
       Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
-      Identifier(const byte_t* value) : m_HasValue(true)   { memcpy(m_Value, value, SIZE); }
-      Identifier(const Identifier& rhs) : m_HasValue(true) { memcpy(m_Value, rhs.m_Value, SIZE); }
+      Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
+      Identifier(const Identifier& rhs) {
+       m_HasValue = rhs.m_HasValue;
+       memcpy(m_Value, rhs.m_Value, SIZE);
+      }
+
       virtual ~Identifier() {}
 
       const Identifier& operator=(const Identifier& rhs) {
-       m_HasValue = true;
+       m_HasValue = rhs.m_HasValue;
        memcpy(m_Value, rhs.m_Value, SIZE);
-       return *this;
+        return *this;
       }
 
       inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
+      inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
       inline const byte_t* Value() const { return m_Value; }
       inline ui32_t Size() const { return SIZE; }
 
-      inline bool operator<(const Identifier& rhs) const
-       {
-         ui32_t test_size = xmin(rhs.Size(), SIZE);
-         for ( ui32_t i = 0; i < test_size; i++ )
-           {
-             if ( m_Value[i] != rhs.m_Value[i] )
-               return m_Value[i] < rhs.m_Value[i];
-           }
-
-         return false;
-       }
+      inline bool operator<(const Identifier& rhs) const {
+       ui32_t test_size = xmin(rhs.Size(), SIZE);
 
-      inline bool operator==(const Identifier& rhs) const
-       {
-         if ( rhs.Size() != SIZE ) return false;
-         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
-       }
+       for ( ui32_t i = 0; i < test_size; i++ )
+         {
+           if ( m_Value[i] != rhs.m_Value[i] )
+             return m_Value[i] < rhs.m_Value[i];
+         }
+       
+       return false;
+      }
 
-      inline bool operator!=(const Identifier& rhs) const
-       {
-         if ( rhs.Size() != SIZE ) return true;
-         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
-       }
+      inline bool operator==(const Identifier& rhs) const {
+       if ( rhs.Size() != SIZE ) return false;
+       return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
+      }
 
-      inline bool DecodeHex(const char* str)
-       {
-         ui32_t char_count;
-         if ( hex2bin(str, m_Value, SIZE, &char_count) != 0 )
-           return false;
+      inline bool operator!=(const Identifier& rhs) const {
+       if ( rhs.Size() != SIZE ) return true;
+       return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
+      }
 
-         m_HasValue = true;
-         return true;
-       }
+      inline bool DecodeHex(const char* str) {
+       ui32_t char_count;
+       m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
+       return m_HasValue;
+      }
 
-      inline const char* EncodeHex(char* buf, ui32_t buf_len) const
-       {
-         return bin2hex(m_Value, SIZE, buf, buf_len);
-       }
+      inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
+       return bin2hex(m_Value, SIZE, buf, buf_len);
+      }
 
       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
        return EncodeHex(str_buf, buf_len);
       }
 
-      inline bool DecodeBase64(const char* str)
-       {
-         ui32_t char_count;
-         if ( base64decode(str, m_Value, SIZE, &char_count) != 0 )
-           return false;
+      inline bool DecodeBase64(const char* str) {
+       ui32_t char_count;
+       m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
+       return m_HasValue;
+      }
 
-         m_HasValue = true;
-         return true;
-       }
+      inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
+       return base64encode(m_Value, SIZE, buf, buf_len);
+      }
 
-      inline const char* EncodeBase64(char* buf, ui32_t buf_len) const
-       {
-         return base64encode(m_Value, SIZE, buf, buf_len);
-       }
+      inline bool HasValue() const { return m_HasValue; }
 
-      inline virtual bool HasValue() const { return m_HasValue; }
+      inline ui32_t ArchiveLength() const { return SIZE; }
 
-      inline virtual bool Unarchive(Kumu::MemIOReader* Reader) {
-       if ( ! Reader->ReadRaw(m_Value, SIZE) ) return false;
-       m_HasValue = true;
-       return true;
+      inline bool Unarchive(Kumu::MemIOReader* Reader) {
+       m_HasValue = Reader->ReadRaw(m_Value, SIZE);
+       return m_HasValue;
       }
 
-      inline virtual bool Archive(Kumu::MemIOWriter* Writer) const {
+      inline bool Archive(Kumu::MemIOWriter* Writer) const {
        return Writer->WriteRaw(m_Value, SIZE);
       }
     };
 
-  
+
   // UUID
   //
   const ui32_t UUID_Length = 16;
@@ -269,13 +327,17 @@ namespace Kumu
       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
       virtual ~UUID() {}
-      
+
+      inline const char* EncodeString(char* buf, ui32_t buf_len) const {
+       return bin2UUIDhex(m_Value, Size(), buf, buf_len);
+      }
+
       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
        return bin2UUIDhex(m_Value, Size(), buf, buf_len);
       }
     };
   
-  void GenRandomUUID(byte_t* buf);
+  void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
   void GenRandomValue(UUID&);
   
   // a self-wiping key container
@@ -319,6 +381,7 @@ namespace Kumu
 
       const Timestamp& operator=(const Timestamp& rhs);
       bool operator<(const Timestamp& rhs) const;
+      bool operator>(const Timestamp& rhs) const;
       bool operator==(const Timestamp& rhs) const;
       bool operator!=(const Timestamp& rhs) const;
 
@@ -329,19 +392,24 @@ namespace Kumu
       // decode and set value from string formatted by EncodeString
       bool        DecodeString(const char* datestr);
 
-      // add the given number of days or hours to the timestamp value. Values less than zero
-      // will cause the value to decrease
+      // Add the given number of days or hours to the timestamp value.
+      // Values less than zero will cause the timestamp to decrease
       void AddDays(i32_t);
       void AddHours(i32_t);
 
-      // Read and write the timestamp value as a byte string
-      virtual bool HasValue() const;
-      virtual bool Archive(MemIOWriter* Writer) const;
-      virtual bool Unarchive(MemIOReader* Reader);
+      // Read and write the timestamp 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) |
+      //
+      virtual bool   HasValue() const;
+      virtual ui32_t ArchiveLength() const { return 8L; }
+      virtual bool   Archive(MemIOWriter* Writer) const;
+      virtual bool   Unarchive(MemIOReader* Reader);
     };
 
   //
-  class ByteString
+  class ByteString : public IArchive
     {
       KM_NO_COPY_CONSTRUCT(ByteString);
        
@@ -355,8 +423,7 @@ namespace Kumu
       ByteString(ui32_t cap);
       virtual ~ByteString();
 
-      // Sets the size of the internally allocated buffer.
-      // Resets content Size to zero.
+      // Sets or resets the size of the internally allocated buffer.
       Result_t Capacity(ui32_t cap);
 
       Result_t Append(const ByteString&);
@@ -366,10 +433,10 @@ namespace Kumu
       inline ui32_t  Capacity() const { return m_Capacity; }
 
       // returns a const pointer to the essence data
-      inline const byte_t* RoData() const { return m_Data; }
+      inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
        
       // returns a non-const pointer to the essence data
-      inline byte_t* Data() { return m_Data; }
+      inline byte_t* Data() { assert(m_Data); return m_Data; }
        
       // set the length of the buffer's contents
       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
@@ -380,6 +447,28 @@ namespace Kumu
       // copy the given data into the ByteString, set Length value.
       // Returns error if the ByteString is too small.
       Result_t Set(const byte_t* buf, ui32_t buf_len);
+      Result_t Set(const ByteString& Buf);
+
+      inline virtual bool HasValue() const { return m_Length > 0; }
+
+      inline virtual ui32_t ArchiveLength() const { return m_Length; }
+
+      inline virtual bool Archive(MemIOWriter* Writer) const {
+       assert(Writer);
+       if ( ! Writer->WriteUi32BE(m_Length) ) return false;
+       if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
+       return true;
+      }
+
+      inline virtual bool Unarchive(MemIOReader* Reader) {
+       assert(Reader);
+       ui32_t tmp_len;
+       if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
+       if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
+       if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
+       m_Length = tmp_len;
+       return true;
+      }
     };
 
 } // namespace Kumu