X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FKM_util.h;h=b209d27841a890814e1841885a5e1abae6ed4f4d;hb=7ce81497e2592d5787b9a4285d6a89ae09f79022;hp=a27296bc694409dcd4b838e8a7282f171d1859ae;hpb=bfedf725dac9d13f3a02fe69f45c302ab29d2b1e;p=asdcplib.git diff --git a/src/KM_util.h b/src/KM_util.h index a27296b..b209d27 100755 --- a/src/KM_util.h +++ b/src/KM_util.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2006, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -34,24 +34,38 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include -#include +#include namespace Kumu { + // The version number declaration and explanation are in ../configure.ac + const char* Version(); + // a class that represents the string form of a value template 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 +120,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. // @@ -140,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); @@ -152,18 +170,128 @@ 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 ArchivableList : public std::list, 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::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(static_cast(this->size())) ) return false; + typename ArchivableList::const_iterator i = this->begin(); + for ( ; i != this->end(); i++ ) + if ( ! i->Archive(Writer) ) return false; + + return true; + } }; + // archivable version of std::string // - // the base of all identifier classes + 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(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 StringList; + + // + // the base of all identifier classes, Identifier is not usually used directly + // see UUID and SymmetricKey below for more detail. + // template class Identifier : public IArchive { @@ -173,92 +301,90 @@ 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) : IArchive() { + 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 ); + if ( m_HasValue && char_count != SIZE ) + m_HasValue = false; + 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 ); + if ( m_HasValue && char_count != SIZE ) + m_HasValue = false; + 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,15 +395,21 @@ namespace Kumu UUID(const byte_t* value) : Identifier(value) {} UUID(const UUID& rhs) : Identifier(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&); + typedef ArchivableList UUIDList; + // a self-wiping key container // const ui32_t SymmetricKey_Length = 16; @@ -298,50 +430,73 @@ namespace Kumu void GenRandomValue(SymmetricKey&); // - // 2004-05-01T13:20:00-00:00 + // 2004-05-01T13:20:00+00:00 const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds) // 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); bool operator<(const Timestamp& rhs) const; + bool operator>(const Timestamp& rhs) const; bool operator==(const Timestamp& rhs) const; bool operator!=(const Timestamp& rhs) const; - // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00-00:00 + // 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; // decode and set value from string formatted by EncodeString - Result_t SetFromString(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 - 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); + bool DecodeString(const char* datestr); + + // Add the given number of days, hours, minutes, or seconds to the timestamp value. + // Values less than zero will cause the timestamp to decrease + 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); } + + // 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) | + // + 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 +510,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 +520,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,8 +534,65 @@ 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 sizeof(ui32_t) + 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; + } }; + 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 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 + 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