2 Copyright (c) 2005-2012, 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 // The version number declaration and explanation are in ../configure.ac
45 const char* Version();
47 // a class that represents the string form of a value
48 template <class T, int SIZE = 16>
49 class IntPrinter : public std::string
51 KM_NO_COPY_CONSTRUCT(IntPrinter);
59 IntPrinter(const char* format, T value) {
62 snprintf(m_strbuf, SIZE, m_format, value);
65 inline operator const char*() { return m_strbuf; }
66 inline const char* c_str() { return m_strbuf; }
67 inline const char* set_value(T value) {
68 snprintf(m_strbuf, SIZE, m_format, value);
73 struct i8Printer : public IntPrinter<i8_t> {
74 i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
77 struct ui8Printer : public IntPrinter<ui8_t> {
78 ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
81 struct i16Printer : public IntPrinter<i16_t> {
82 i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
85 struct ui16Printer : public IntPrinter<ui16_t> {
86 ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
89 struct i32Printer : public IntPrinter<i32_t> {
90 i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
93 struct ui32Printer : public IntPrinter<ui32_t> {
94 ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
98 struct i64Printer : public IntPrinter<i64_t, 32> {
99 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
102 struct ui64Printer : public IntPrinter<ui64_t, 32> {
103 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
106 struct i64Printer : public IntPrinter<i64_t, 32> {
107 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
110 struct ui64Printer : public IntPrinter<ui64_t, 32> {
111 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
115 // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
116 // the binary buffer was large enough to hold the result. The output parameter
117 // 'char_count' will contain the length of the converted string. If the output
118 // buffer is too small or any of the pointer arguments are NULL, the subroutine
119 // will return -1 and set 'char_count' to the required buffer size. No data will
120 // be written to 'buf' if the subroutine fails.
121 i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
123 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
124 // if the output buffer was large enough to hold the result. If the output buffer
125 // is too small or any of the pointer arguments are NULL, the subroutine will
128 const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
130 const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
132 // same as above for base64 text
133 i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
134 const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
136 // returns the length of a Base64 encoding of a buffer of the given length
137 inline ui32_t base64_encode_length(ui32_t length) {
138 while ( ( length % 3 ) != 0 )
141 return ( length / 3 ) * 4;
144 // print buffer contents to a stream as hexadecimal values in numbered
145 // rows of 16-bytes each.
147 void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
149 // Return the length in bytes of a BER encoded value
150 inline ui32_t BER_length(const byte_t* buf)
152 if ( buf == 0 || (*buf & 0xf0) != 0x80 )
155 return (*buf & 0x0f) + 1;
158 // Return the BER length required to encode value. A return value of zero
159 // indicates a value too large for this library.
160 ui32_t get_BER_length_for_value(ui64_t valuse);
163 bool read_BER(const byte_t* buf, ui64_t* val);
165 // decode a ber value and compare it to a test value
166 bool read_test_BER(byte_t **buf, ui64_t test_value);
168 // create BER encoding of integer value
169 bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
171 //----------------------------------------------------------------
174 // an abstract base class that objects implement to serialize state
175 // to and from a binary stream.
179 virtual ~IArchive(){}
180 virtual bool HasValue() const = 0;
181 virtual ui32_t ArchiveLength() const = 0;
182 virtual bool Archive(MemIOWriter* Writer) const = 0;
183 virtual bool Unarchive(MemIOReader* Reader) = 0;
188 class ArchivableList : public std::list<T>, public IArchive
192 virtual ~ArchivableList() {}
194 bool HasValue() const { return ! this->empty(); }
196 ui32_t ArchiveLength() const
198 ui32_t arch_size = sizeof(ui32_t);
200 typename ArchivableList<T>::const_iterator i = this->begin();
201 for ( ; i != this->end(); i++ )
202 arch_size += i->ArchiveLength();
207 bool Unarchive(Kumu::MemIOReader* Reader)
209 if ( Reader == 0 ) return false;
210 ui32_t read_size = 0;
211 if ( ! Reader->ReadUi32BE(&read_size) ) return false;
212 for ( ui32_t i = 0; i < read_size; i++ )
215 if ( ! TmpTP.Unarchive(Reader) ) return false;
216 this->push_back(TmpTP);
222 bool Archive(Kumu::MemIOWriter* Writer) const
224 if ( Writer == 0 ) return false;
225 if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
226 typename ArchivableList<T>::const_iterator i = this->begin();
227 for ( ; i != this->end(); i++ )
228 if ( ! i->Archive(Writer) ) return false;
234 // archivable version of std::string
237 class ArchivableString : public std::string, public Kumu::IArchive
241 ArchivableString() {}
242 ArchivableString(const char* sz) : std::string(sz) {}
243 ArchivableString(const std::string& s) : std::string(s) {}
244 virtual ~ArchivableString() {}
246 bool HasValue() const { return ! this->empty(); }
247 ui32_t ArchiveLength() const { sizeof(ui32_t) + static_cast<ui32_t>(this->size()); }
249 bool Archive(MemIOWriter* Writer) const {
250 if ( Writer == 0 ) return false;
251 return Writer->WriteString(*this);
254 bool Unarchive(MemIOReader* Reader) {
255 if ( Reader == 0 ) return false;
256 return Reader->ReadString(*this);
261 typedef Kumu::ArchivableList<ArchivableString> StringList;
264 // the base of all identifier classes, Identifier is not usually used directly
265 // see UUID and SymmetricKey below for more detail.
267 template <ui32_t SIZE>
268 class Identifier : public IArchive
272 byte_t m_Value[SIZE];
275 Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
276 Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
277 Identifier(const Identifier& rhs) : IArchive() {
278 m_HasValue = rhs.m_HasValue;
279 memcpy(m_Value, rhs.m_Value, SIZE);
282 virtual ~Identifier() {}
284 const Identifier& operator=(const Identifier& rhs) {
285 m_HasValue = rhs.m_HasValue;
286 memcpy(m_Value, rhs.m_Value, SIZE);
290 inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
291 inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
292 inline const byte_t* Value() const { return m_Value; }
293 inline ui32_t Size() const { return SIZE; }
295 inline bool operator<(const Identifier& rhs) const {
296 ui32_t test_size = xmin(rhs.Size(), SIZE);
298 for ( ui32_t i = 0; i < test_size; i++ )
300 if ( m_Value[i] != rhs.m_Value[i] )
301 return m_Value[i] < rhs.m_Value[i];
307 inline bool operator==(const Identifier& rhs) const {
308 if ( rhs.Size() != SIZE ) return false;
309 return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
312 inline bool operator!=(const Identifier& rhs) const {
313 if ( rhs.Size() != SIZE ) return true;
314 return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
317 inline bool DecodeHex(const char* str) {
319 m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
320 if ( m_HasValue && char_count != SIZE )
325 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
326 return bin2hex(m_Value, SIZE, buf, buf_len);
329 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
330 return EncodeHex(str_buf, buf_len);
333 inline bool DecodeBase64(const char* str) {
335 m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
336 if ( m_HasValue && char_count != SIZE )
341 inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
342 return base64encode(m_Value, SIZE, buf, buf_len);
345 inline bool HasValue() const { return m_HasValue; }
347 inline ui32_t ArchiveLength() const { return SIZE; }
349 inline bool Unarchive(Kumu::MemIOReader* Reader) {
350 m_HasValue = Reader->ReadRaw(m_Value, SIZE);
354 inline bool Archive(Kumu::MemIOWriter* Writer) const {
355 return Writer->WriteRaw(m_Value, SIZE);
362 const ui32_t UUID_Length = 16;
363 class UUID : public Identifier<UUID_Length>
367 UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
368 UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
371 inline const char* EncodeString(char* buf, ui32_t buf_len) const {
372 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
375 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
376 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
380 void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
381 void GenRandomValue(UUID&);
383 typedef ArchivableList<UUID> UUIDList;
385 // a self-wiping key container
387 const ui32_t SymmetricKey_Length = 16;
388 const byte_t NilKey[SymmetricKey_Length] = {
389 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
390 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
393 class SymmetricKey : public Identifier<SymmetricKey_Length>
397 SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
398 SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
399 virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
402 void GenRandomValue(SymmetricKey&);
405 // 2004-05-01T13:20:00+00:00
406 const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds)
408 // UTC time+date representation
409 class Timestamp : public IArchive
411 TAI::tai m_Timestamp; // always UTC
412 i32_t m_TZOffsetMinutes;
416 Timestamp(const Timestamp& rhs);
417 Timestamp(const char* datestr);
418 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day);
419 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
420 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
421 virtual ~Timestamp();
423 const Timestamp& operator=(const Timestamp& rhs);
424 bool operator<(const Timestamp& rhs) const;
425 bool operator>(const Timestamp& rhs) const;
426 bool operator==(const Timestamp& rhs) const;
427 bool operator!=(const Timestamp& rhs) const;
430 void GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
431 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const;
432 void SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
433 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
435 // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
436 // returns 0 if the buffer is smaller than DateTimeLen
437 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
439 // decode and set value from string formatted by EncodeString
440 bool DecodeString(const char* datestr);
442 // Add the given number of days, hours, minutes, or seconds to the timestamp value.
443 // Values less than zero will cause the timestamp to decrease
444 inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
445 inline void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
446 inline void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
447 inline void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
449 // returns false if the requested adjustment is out of range
450 bool SetTZOffsetMinutes(const i32_t& minutes);
451 inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
453 // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
454 ui64_t GetCTime() const;
456 // Set internal time to the number of seconds since the Unix epoch UTC
457 void SetCTime(const ui64_t& ctime);
459 // Read and write the timestamp (always UTC) value as a byte string having
460 // the following format:
461 // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits |
462 // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
464 virtual bool HasValue() const;
465 virtual ui32_t ArchiveLength() const { return 8L; }
466 virtual bool Archive(MemIOWriter* Writer) const;
467 virtual bool Unarchive(MemIOReader* Reader);
471 class ByteString : public IArchive
473 KM_NO_COPY_CONSTRUCT(ByteString);
476 byte_t* m_Data; // pointer to memory area containing frame data
477 ui32_t m_Capacity; // size of memory area pointed to by m_Data
478 ui32_t m_Length; // length of byte string in memory area pointed to by m_Data
482 ByteString(ui32_t cap);
483 virtual ~ByteString();
485 // Sets or resets the size of the internally allocated buffer.
486 Result_t Capacity(ui32_t cap);
488 Result_t Append(const ByteString&);
489 Result_t Append(const byte_t* buf, ui32_t buf_len);
491 // returns the size of the buffer
492 inline ui32_t Capacity() const { return m_Capacity; }
494 // returns a const pointer to the essence data
495 inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
497 // returns a non-const pointer to the essence data
498 inline byte_t* Data() { assert(m_Data); return m_Data; }
500 // set the length of the buffer's contents
501 inline ui32_t Length(ui32_t l) { return m_Length = l; }
503 // returns the length of the buffer's contents
504 inline ui32_t Length() const { return m_Length; }
506 // copy the given data into the ByteString, set Length value.
507 // Returns error if the ByteString is too small.
508 Result_t Set(const byte_t* buf, ui32_t buf_len);
509 Result_t Set(const ByteString& Buf);
511 inline virtual bool HasValue() const { return m_Length > 0; }
513 inline virtual ui32_t ArchiveLength() const { return m_Length; }
515 inline virtual bool Archive(MemIOWriter* Writer) const {
517 if ( ! Writer->WriteUi32BE(m_Length) ) return false;
518 if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
522 inline virtual bool Unarchive(MemIOReader* Reader) {
525 if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
526 if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
527 if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
533 inline void hexdump(const ByteString& buf, FILE* stream = 0) {
534 hexdump(buf.RoData(), buf.Length());
537 // Locates the first occurrence of the null-terminated string s2 in the string s1, where not more
538 // than n characters are searched. Characters that appear after a `\0' character are not searched.
539 // Reproduced here from BSD for portability.
540 const char *km_strnstr(const char *s1, const char *s2, size_t n);
542 // Split the input string into tokens using the given separator. If the separator is not found the
543 // entire string will be returned as a single-item list.
544 std::list<std::string> km_token_split(const std::string& str, const std::string& separator);
549 #endif // _KM_UTIL_H_