2 Copyright (c) 2005-2008, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \brief Utility functions
44 // a class that represents the string form of a value
45 template <class T, int SIZE = 16>
46 class IntPrinter : public std::string
48 KM_NO_COPY_CONSTRUCT(IntPrinter);
56 IntPrinter(const char* format, T value) {
59 snprintf(m_strbuf, SIZE, m_format, value);
62 inline operator const char*() { return m_strbuf; }
63 inline const char* c_str() { return m_strbuf; }
64 inline const char* set_value(T value) {
65 snprintf(m_strbuf, SIZE, m_format, value);
70 struct i8Printer : public IntPrinter<i8_t> {
71 i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
74 struct ui8Printer : public IntPrinter<ui8_t> {
75 ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
78 struct i16Printer : public IntPrinter<i16_t> {
79 i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
82 struct ui16Printer : public IntPrinter<ui16_t> {
83 ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
86 struct i32Printer : public IntPrinter<i32_t> {
87 i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
90 struct ui32Printer : public IntPrinter<ui32_t> {
91 ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
95 struct i64Printer : public IntPrinter<i64_t, 32> {
96 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
99 struct ui64Printer : public IntPrinter<ui64_t, 32> {
100 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
103 struct i64Printer : public IntPrinter<i64_t, 32> {
104 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
107 struct ui64Printer : public IntPrinter<ui64_t, 32> {
108 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
112 // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
113 // the binary buffer was large enough to hold the result. The output parameter
114 // 'char_count' will contain the length of the converted string. If the output
115 // buffer is too small or any of the pointer arguments are NULL, the subroutine
116 // will return -1 and set 'char_count' to the required buffer size. No data will
117 // be written to 'buf' if the subroutine fails.
118 i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
120 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
121 // if the output buffer was large enough to hold the result. If the output buffer
122 // is too small or any of the pointer arguments are NULL, the subroutine will
125 const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
127 const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
129 // same as above for base64 text
130 i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
131 const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
133 // returns the length of a Base64 encoding of a buffer of the given length
134 inline ui32_t base64_encode_length(ui32_t length) {
135 while ( ( length % 3 ) != 0 )
138 return ( length / 3 ) * 4;
141 // print buffer contents to a stream as hexadecimal values in numbered
142 // rows of 16-bytes each.
144 void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
146 // Return the length in bytes of a BER encoded value
147 inline ui32_t BER_length(const byte_t* buf)
149 if ( buf == 0 || (*buf & 0xf0) != 0x80 )
152 return (*buf & 0x0f) + 1;
156 bool read_BER(const byte_t* buf, ui64_t* val);
158 // decode a ber value and compare it to a test value
159 bool read_test_BER(byte_t **buf, ui64_t test_value);
161 // create BER encoding of integer value
162 bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
164 //----------------------------------------------------------------
167 // an abstract base class that objects implement to serialize state
168 // to and from a binary stream.
172 virtual ~IArchive(){}
173 virtual bool HasValue() const = 0;
174 virtual ui32_t ArchiveLength() const = 0;
175 virtual bool Archive(MemIOWriter* Writer) const = 0;
176 virtual bool Unarchive(MemIOReader* Reader) = 0;
181 class ArchivableList : public std::list<T>, public IArchive
185 virtual ~ArchivableList() {}
187 bool HasValue() const { return ! this->empty(); }
189 ui32_t ArchiveLength() const
191 ui32_t arch_size = sizeof(ui32_t);
193 typename ArchivableList<T>::const_iterator i = this->begin();
194 for ( ; i != this->end(); i++ )
195 arch_size += i->ArchiveLength();
200 bool Unarchive(Kumu::MemIOReader* Reader)
202 if ( Reader == 0 ) return false;
203 ui32_t read_size = 0;
204 if ( ! Reader->ReadUi32BE(&read_size) ) return false;
205 for ( ui32_t i = 0; i < read_size; i++ )
208 if ( ! TmpTP.Unarchive(Reader) ) return false;
209 this->push_back(TmpTP);
215 bool Archive(Kumu::MemIOWriter* Writer) const
217 if ( Writer == 0 ) return false;
218 if ( ! Writer->WriteUi32BE(this->size()) ) return false;
219 typename ArchivableList<T>::const_iterator i = this->begin();
220 for ( ; i != this->end(); i++ )
221 if ( ! i->Archive(Writer) ) return false;
228 // the base of all identifier classes, Identifier is not usually used directly
229 // see UUID and SymmetricKey below for more detail.
231 template <ui32_t SIZE>
232 class Identifier : public IArchive
236 byte_t m_Value[SIZE];
239 Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
240 Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
241 Identifier(const Identifier& rhs) {
242 m_HasValue = rhs.m_HasValue;
243 memcpy(m_Value, rhs.m_Value, SIZE);
246 virtual ~Identifier() {}
248 const Identifier& operator=(const Identifier& rhs) {
249 m_HasValue = rhs.m_HasValue;
250 memcpy(m_Value, rhs.m_Value, SIZE);
254 inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
255 inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
256 inline const byte_t* Value() const { return m_Value; }
257 inline ui32_t Size() const { return SIZE; }
259 inline bool operator<(const Identifier& rhs) const {
260 ui32_t test_size = xmin(rhs.Size(), SIZE);
262 for ( ui32_t i = 0; i < test_size; i++ )
264 if ( m_Value[i] != rhs.m_Value[i] )
265 return m_Value[i] < rhs.m_Value[i];
271 inline bool operator==(const Identifier& rhs) const {
272 if ( rhs.Size() != SIZE ) return false;
273 return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
276 inline bool operator!=(const Identifier& rhs) const {
277 if ( rhs.Size() != SIZE ) return true;
278 return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
281 inline bool DecodeHex(const char* str) {
283 m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
287 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
288 return bin2hex(m_Value, SIZE, buf, buf_len);
291 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
292 return EncodeHex(str_buf, buf_len);
295 inline bool DecodeBase64(const char* str) {
297 m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
301 inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
302 return base64encode(m_Value, SIZE, buf, buf_len);
305 inline bool HasValue() const { return m_HasValue; }
307 inline ui32_t ArchiveLength() const { return SIZE; }
309 inline bool Unarchive(Kumu::MemIOReader* Reader) {
310 m_HasValue = Reader->ReadRaw(m_Value, SIZE);
314 inline bool Archive(Kumu::MemIOWriter* Writer) const {
315 return Writer->WriteRaw(m_Value, SIZE);
322 const ui32_t UUID_Length = 16;
323 class UUID : public Identifier<UUID_Length>
327 UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
328 UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
331 inline const char* EncodeString(char* buf, ui32_t buf_len) const {
332 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
335 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
336 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
340 void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
341 void GenRandomValue(UUID&);
343 // a self-wiping key container
345 const ui32_t SymmetricKey_Length = 16;
346 const byte_t NilKey[SymmetricKey_Length] = {
347 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
348 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
351 class SymmetricKey : public Identifier<SymmetricKey_Length>
355 SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
356 SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
357 virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
360 void GenRandomValue(SymmetricKey&);
363 // 2004-05-01T13:20:00-00:00
364 const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds)
366 // UTC time+date representation
367 class Timestamp : public IArchive
378 Timestamp(const Timestamp& rhs);
379 Timestamp(const char* datestr);
380 virtual ~Timestamp();
382 const Timestamp& operator=(const Timestamp& rhs);
383 bool operator<(const Timestamp& rhs) const;
384 bool operator>(const Timestamp& rhs) const;
385 bool operator==(const Timestamp& rhs) const;
386 bool operator!=(const Timestamp& rhs) const;
388 // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00-00:00
389 // returns 0 if the buffer is smaller than DateTimeLen
390 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
392 // decode and set value from string formatted by EncodeString
393 bool DecodeString(const char* datestr);
395 // Add the given number of days or hours to the timestamp value.
396 // Values less than zero will cause the timestamp to decrease
398 void AddHours(i32_t);
400 // Read and write the timestamp value as a byte string having
401 // the following format:
402 // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits |
403 // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
405 virtual bool HasValue() const;
406 virtual ui32_t ArchiveLength() const { return 8L; }
407 virtual bool Archive(MemIOWriter* Writer) const;
408 virtual bool Unarchive(MemIOReader* Reader);
412 class ByteString : public IArchive
414 KM_NO_COPY_CONSTRUCT(ByteString);
417 byte_t* m_Data; // pointer to memory area containing frame data
418 ui32_t m_Capacity; // size of memory area pointed to by m_Data
419 ui32_t m_Length; // length of byte string in memory area pointed to by m_Data
423 ByteString(ui32_t cap);
424 virtual ~ByteString();
426 // Sets or resets the size of the internally allocated buffer.
427 Result_t Capacity(ui32_t cap);
429 Result_t Append(const ByteString&);
430 Result_t Append(const byte_t* buf, ui32_t buf_len);
432 // returns the size of the buffer
433 inline ui32_t Capacity() const { return m_Capacity; }
435 // returns a const pointer to the essence data
436 inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
438 // returns a non-const pointer to the essence data
439 inline byte_t* Data() { assert(m_Data); return m_Data; }
441 // set the length of the buffer's contents
442 inline ui32_t Length(ui32_t l) { return m_Length = l; }
444 // returns the length of the buffer's contents
445 inline ui32_t Length() const { return m_Length; }
447 // copy the given data into the ByteString, set Length value.
448 // Returns error if the ByteString is too small.
449 Result_t Set(const byte_t* buf, ui32_t buf_len);
450 Result_t Set(const ByteString& Buf);
452 inline virtual bool HasValue() const { return m_Length > 0; }
454 inline virtual ui32_t ArchiveLength() const { return m_Length; }
456 inline virtual bool Archive(MemIOWriter* Writer) const {
458 if ( ! Writer->WriteUi32BE(m_Length) ) return false;
459 if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
463 inline virtual bool Unarchive(MemIOReader* Reader) {
466 if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
467 if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
468 if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
477 #endif // _KM_UTIL_H_