2 Copyright (c) 2005-2015, 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
43 // The version number declaration and explanation are in ../configure.ac
44 const char* Version();
46 // a class that represents the string form of a value
47 template <class T, int SIZE = 16>
48 class IntPrinter : public std::string
50 KM_NO_COPY_CONSTRUCT(IntPrinter);
58 IntPrinter(const char* format, T value) {
61 snprintf(m_strbuf, SIZE, m_format, value);
64 inline operator const char*() { return m_strbuf; }
65 inline const char* c_str() { return m_strbuf; }
66 inline const char* set_value(T value) {
67 snprintf(m_strbuf, SIZE, m_format, value);
72 struct i8Printer : public IntPrinter<i8_t> {
73 i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
76 struct ui8Printer : public IntPrinter<ui8_t> {
77 ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
80 struct i16Printer : public IntPrinter<i16_t> {
81 i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
84 struct ui16Printer : public IntPrinter<ui16_t> {
85 ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
88 struct i32Printer : public IntPrinter<i32_t> {
89 i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
92 struct ui32Printer : public IntPrinter<ui32_t> {
93 ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
97 struct i64Printer : public IntPrinter<i64_t, 32> {
98 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
101 struct ui64Printer : public IntPrinter<ui64_t, 32> {
102 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
105 struct i64Printer : public IntPrinter<i64_t, 32> {
106 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
109 struct ui64Printer : public IntPrinter<ui64_t, 32> {
110 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
114 // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
115 // the binary buffer was large enough to hold the result. The output parameter
116 // 'char_count' will contain the length of the converted string. If the output
117 // buffer is too small or any of the pointer arguments are NULL, the subroutine
118 // will return -1 and set 'char_count' to the required buffer size. No data will
119 // be written to 'buf' if the subroutine fails.
120 i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
122 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
123 // if the output buffer was large enough to hold the result. If the output buffer
124 // is too small or any of the pointer arguments are NULL, the subroutine will
127 const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
129 const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
131 // same as above for base64 text
132 i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
133 const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
135 // returns the length of a Base64 encoding of a buffer of the given length
136 inline ui32_t base64_encode_length(ui32_t length) {
137 while ( ( length % 3 ) != 0 )
140 return ( length / 3 ) * 4;
143 // print buffer contents to a stream as hexadecimal values in numbered
144 // rows of 16-bytes each.
146 void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
148 // Return the length in bytes of a BER encoded value
149 inline ui32_t BER_length(const byte_t* buf)
151 if ( buf == 0 || (*buf & 0xf0) != 0x80 )
154 return (*buf & 0x0f) + 1;
157 // Return the BER length required to encode value. A return value of zero
158 // indicates a value too large for this library.
159 ui32_t get_BER_length_for_value(ui64_t valuse);
162 bool read_BER(const byte_t* buf, ui64_t* val);
164 // decode a ber value and compare it to a test value
165 bool read_test_BER(byte_t **buf, ui64_t test_value);
167 // create BER encoding of integer value
168 bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
170 //----------------------------------------------------------------
173 // an abstract base class that objects implement to serialize state
174 // to and from a binary stream.
178 virtual ~IArchive(){}
179 virtual bool HasValue() const = 0;
180 virtual ui32_t ArchiveLength() const = 0;
181 virtual bool Archive(MemIOWriter* Writer) const = 0;
182 virtual bool Unarchive(MemIOReader* Reader) = 0;
187 class ArchivableList : public std::list<T>, public IArchive
191 virtual ~ArchivableList() {}
193 bool HasValue() const { return ! this->empty(); }
195 ui32_t ArchiveLength() const
197 ui32_t arch_size = sizeof(ui32_t);
199 typename ArchivableList<T>::const_iterator i = this->begin();
200 for ( ; i != this->end(); i++ )
201 arch_size += i->ArchiveLength();
206 bool Unarchive(Kumu::MemIOReader* Reader)
208 if ( Reader == 0 ) return false;
209 ui32_t read_size = 0;
210 if ( ! Reader->ReadUi32BE(&read_size) ) return false;
211 for ( ui32_t i = 0; i < read_size; i++ )
214 if ( ! TmpTP.Unarchive(Reader) ) return false;
215 this->push_back(TmpTP);
221 bool Archive(Kumu::MemIOWriter* Writer) const
223 if ( Writer == 0 ) return false;
224 if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
225 typename ArchivableList<T>::const_iterator i = this->begin();
226 for ( ; i != this->end(); i++ )
227 if ( ! i->Archive(Writer) ) return false;
233 // archivable version of std::string
236 class ArchivableString : public std::string, public Kumu::IArchive
240 ArchivableString() {}
241 ArchivableString(const char* sz) : std::string(sz) {}
242 ArchivableString(const std::string& s) : std::string(s) {}
243 virtual ~ArchivableString() {}
245 bool HasValue() const { return ! this->empty(); }
246 ui32_t ArchiveLength() const { return sizeof(ui32_t) + static_cast<ui32_t>(this->size()); }
248 bool Archive(MemIOWriter* Writer) const {
249 if ( Writer == 0 ) return false;
250 return Writer->WriteString(*this);
253 bool Unarchive(MemIOReader* Reader) {
254 if ( Reader == 0 ) return false;
255 return Reader->ReadString(*this);
260 class ArchivableUi16 : public Kumu::IArchive
265 ArchivableUi16() : value(0) {}
266 ArchivableUi16(const ui16_t& val) : value(val) {}
267 virtual ~ArchivableUi16() {}
269 bool HasValue() const { return true; }
270 ui32_t ArchiveLength() const { return sizeof(ui16_t); }
272 operator ui16_t() const { return value; }
274 bool Archive(MemIOWriter* Writer) const {
275 if ( Writer == 0 ) return false;
276 return Writer->WriteUi16BE(value);
279 bool Unarchive(MemIOReader* Reader) {
280 if ( Reader == 0 ) return false;
281 return Reader->ReadUi16BE(&value);
284 const char* EncodeString(char* str_buf, ui32_t buf_len) const {
285 snprintf(str_buf, buf_len, "%hu", value);
291 typedef Kumu::ArchivableList<ArchivableString> StringList;
294 // the base of all identifier classes, Identifier is not usually used directly
295 // see UUID and SymmetricKey below for more detail.
297 template <ui32_t SIZE>
298 class Identifier : public IArchive
302 byte_t m_Value[SIZE];
305 Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
306 Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
307 Identifier(const Identifier& rhs) : IArchive() {
308 m_HasValue = rhs.m_HasValue;
309 memcpy(m_Value, rhs.m_Value, SIZE);
312 virtual ~Identifier() {}
314 const Identifier& operator=(const Identifier& rhs) {
315 m_HasValue = rhs.m_HasValue;
316 memcpy(m_Value, rhs.m_Value, SIZE);
320 inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
321 inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
322 inline const byte_t* Value() const { return m_Value; }
323 inline ui32_t Size() const { return SIZE; }
325 inline bool operator<(const Identifier& rhs) const {
326 ui32_t test_size = xmin(rhs.Size(), SIZE);
328 for ( ui32_t i = 0; i < test_size; i++ )
330 if ( m_Value[i] != rhs.m_Value[i] )
331 return m_Value[i] < rhs.m_Value[i];
337 inline bool operator==(const Identifier& rhs) const {
338 if ( rhs.Size() != SIZE ) return false;
339 return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
342 inline bool operator!=(const Identifier& rhs) const {
343 if ( rhs.Size() != SIZE ) return true;
344 return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
347 inline bool DecodeHex(const char* str) {
349 m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
350 if ( m_HasValue && char_count != SIZE )
355 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
356 return bin2hex(m_Value, SIZE, buf, buf_len);
359 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
360 return EncodeHex(str_buf, buf_len);
363 inline bool DecodeBase64(const char* str) {
365 m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
366 if ( m_HasValue && char_count != SIZE )
371 inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
372 return base64encode(m_Value, SIZE, buf, buf_len);
375 inline bool HasValue() const { return m_HasValue; }
377 inline ui32_t ArchiveLength() const { return SIZE; }
379 inline bool Unarchive(Kumu::MemIOReader* Reader) {
380 m_HasValue = Reader->ReadRaw(m_Value, SIZE);
384 inline bool Archive(Kumu::MemIOWriter* Writer) const {
385 return Writer->WriteRaw(m_Value, SIZE);
392 const ui32_t UUID_Length = 16;
393 class UUID : public Identifier<UUID_Length>
397 UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
398 UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
401 inline const char* EncodeString(char* buf, ui32_t buf_len) const {
402 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
405 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
406 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
410 void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
411 void GenRandomValue(UUID&);
413 typedef ArchivableList<UUID> UUIDList;
415 // a self-wiping key container
417 const ui32_t SymmetricKey_Length = 16;
418 const byte_t NilKey[SymmetricKey_Length] = {
419 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
420 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
423 class SymmetricKey : public Identifier<SymmetricKey_Length>
427 SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
428 SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
429 virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
432 void GenRandomValue(SymmetricKey&);
435 // 2004-05-01T13:20:00+00:00
436 const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds)
438 // UTC time+date representation
439 class Timestamp : public IArchive
441 TAI::tai m_Timestamp; // always UTC
442 i32_t m_TZOffsetMinutes;
446 Timestamp(const Timestamp& rhs);
447 Timestamp(const char* datestr);
448 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day);
449 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
450 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
451 virtual ~Timestamp();
453 const Timestamp& operator=(const Timestamp& rhs);
454 bool operator<(const Timestamp& rhs) const;
455 bool operator>(const Timestamp& rhs) const;
456 bool operator==(const Timestamp& rhs) const;
457 bool operator!=(const Timestamp& rhs) const;
460 void GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
461 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const;
462 void SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
463 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
465 // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
466 // returns 0 if the buffer is smaller than DateTimeLen
467 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
469 // decode and set value from string formatted by EncodeString
470 bool DecodeString(const char* datestr);
472 // Add the given number of days, hours, minutes, or seconds to the timestamp value.
473 // Values less than zero will cause the timestamp to decrease
474 inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
475 inline void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
476 inline void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
477 inline void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
479 // returns false if the requested adjustment is out of range
480 bool SetTZOffsetMinutes(const i32_t& minutes);
481 inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
483 // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
484 ui64_t GetCTime() const;
486 // Set internal time to the number of seconds since the Unix epoch UTC
487 void SetCTime(const ui64_t& ctime);
489 // Read and write the timestamp (always UTC) value as a byte string having
490 // the following format:
491 // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits |
492 // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
494 virtual bool HasValue() const;
495 virtual ui32_t ArchiveLength() const { return 8L; }
496 virtual bool Archive(MemIOWriter* Writer) const;
497 virtual bool Unarchive(MemIOReader* Reader);
501 class ByteString : public IArchive
503 KM_NO_COPY_CONSTRUCT(ByteString);
506 byte_t* m_Data; // pointer to memory area containing frame data
507 ui32_t m_Capacity; // size of memory area pointed to by m_Data
508 ui32_t m_Length; // length of byte string in memory area pointed to by m_Data
512 ByteString(ui32_t cap);
513 virtual ~ByteString();
515 // Sets or resets the size of the internally allocated buffer.
516 Result_t Capacity(ui32_t cap);
518 Result_t Append(const ByteString&);
519 Result_t Append(const byte_t* buf, ui32_t buf_len);
521 // returns the size of the buffer
522 inline ui32_t Capacity() const { return m_Capacity; }
524 // returns a const pointer to the essence data
525 inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
527 // returns a non-const pointer to the essence data
528 inline byte_t* Data() { assert(m_Data); return m_Data; }
530 // set the length of the buffer's contents
531 inline ui32_t Length(ui32_t l) { return m_Length = l; }
533 // returns the length of the buffer's contents
534 inline ui32_t Length() const { return m_Length; }
536 // copy the given data into the ByteString, set Length value.
537 // Returns error if the ByteString is too small.
538 Result_t Set(const byte_t* buf, ui32_t buf_len);
539 Result_t Set(const ByteString& Buf);
541 inline virtual bool HasValue() const { return m_Length > 0; }
543 inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + m_Length; }
545 inline virtual bool Archive(MemIOWriter* Writer) const {
547 if ( ! Writer->WriteUi32BE(m_Length) ) return false;
548 if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
552 inline virtual bool Unarchive(MemIOReader* Reader) {
555 if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
556 if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
557 if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
563 inline void hexdump(const ByteString& buf, FILE* stream = 0) {
564 hexdump(buf.RoData(), buf.Length(), stream);
567 // Locates the first occurrence of the null-terminated string s2 in the string s1, where not more
568 // than n characters are searched. Characters that appear after a `\0' character are not searched.
569 // Reproduced here from BSD for portability.
570 const char *km_strnstr(const char *s1, const char *s2, size_t n);
572 // Split the input string into tokens using the given separator. If the separator is not found the
573 // entire string will be returned as a single-item list. Empty items will be recorded for
574 // adjacent instances of the separator. E.g., "/foo//bar/" will return ["", "foo", "", "bar", ""].
575 std::list<std::string> km_token_split(const std::string& str, const std::string& separator);
577 // Join the tokens in the given list using delimiter. If prefix is defined then each token
578 // will be concatenated with the prefix before being added to the composite string.
581 km_join(const T& list, const std::string& delimiter, const std::string& prefix = "")
585 for ( typename T::const_iterator i = list.begin(); i != list.end(); ++i )
587 if ( i != list.begin() )
592 result += prefix + *i;
601 #endif // _KM_UTIL_H_