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.
28 \version $Id: KM_util.h,v 1.32 2012/02/21 02:09:30 jhurst Exp $
29 \brief Utility functions
44 extern bool libdcp_test;
46 // The version number declaration and explanation are in ../configure.ac
47 const char* Version();
49 // a class that represents the string form of a value
50 template <class T, int SIZE = 16>
51 class IntPrinter : public std::string
53 KM_NO_COPY_CONSTRUCT(IntPrinter);
61 IntPrinter(const char* format, T value) {
64 snprintf(m_strbuf, SIZE, m_format, value);
67 inline operator const char*() { return m_strbuf; }
68 inline const char* c_str() { return m_strbuf; }
69 inline const char* set_value(T value) {
70 snprintf(m_strbuf, SIZE, m_format, value);
75 struct i8Printer : public IntPrinter<i8_t> {
76 i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
79 struct ui8Printer : public IntPrinter<ui8_t> {
80 ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
83 struct i16Printer : public IntPrinter<i16_t> {
84 i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
87 struct ui16Printer : public IntPrinter<ui16_t> {
88 ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
91 struct i32Printer : public IntPrinter<i32_t> {
92 i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
95 struct ui32Printer : public IntPrinter<ui32_t> {
96 ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
100 struct i64Printer : public IntPrinter<i64_t, 32> {
101 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
104 struct ui64Printer : public IntPrinter<ui64_t, 32> {
105 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
108 struct i64Printer : public IntPrinter<i64_t, 32> {
109 i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
112 struct ui64Printer : public IntPrinter<ui64_t, 32> {
113 ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
117 // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
118 // the binary buffer was large enough to hold the result. The output parameter
119 // 'char_count' will contain the length of the converted string. If the output
120 // buffer is too small or any of the pointer arguments are NULL, the subroutine
121 // will return -1 and set 'char_count' to the required buffer size. No data will
122 // be written to 'buf' if the subroutine fails.
123 i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
125 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
126 // if the output buffer was large enough to hold the result. If the output buffer
127 // is too small or any of the pointer arguments are NULL, the subroutine will
130 const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
132 const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
134 // same as above for base64 text
135 i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
136 const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
138 // returns the length of a Base64 encoding of a buffer of the given length
139 inline ui32_t base64_encode_length(ui32_t length) {
140 while ( ( length % 3 ) != 0 )
143 return ( length / 3 ) * 4;
146 // print buffer contents to a stream as hexadecimal values in numbered
147 // rows of 16-bytes each.
149 void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
151 // Return the length in bytes of a BER encoded value
152 inline ui32_t BER_length(const byte_t* buf)
154 if ( buf == 0 || (*buf & 0xf0) != 0x80 )
157 return (*buf & 0x0f) + 1;
160 // Return the BER length required to encode value. A return value of zero
161 // indicates a value too large for this library.
162 ui32_t get_BER_length_for_value(ui64_t valuse);
165 bool read_BER(const byte_t* buf, ui64_t* val);
167 // decode a ber value and compare it to a test value
168 bool read_test_BER(byte_t **buf, ui64_t test_value);
170 // create BER encoding of integer value
171 bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
173 //----------------------------------------------------------------
176 // an abstract base class that objects implement to serialize state
177 // to and from a binary stream.
181 virtual ~IArchive(){}
182 virtual bool HasValue() const = 0;
183 virtual ui32_t ArchiveLength() const = 0;
184 virtual bool Archive(MemIOWriter* Writer) const = 0;
185 virtual bool Unarchive(MemIOReader* Reader) = 0;
190 class ArchivableList : public std::list<T>, public IArchive
194 virtual ~ArchivableList() {}
196 bool HasValue() const { return ! this->empty(); }
198 ui32_t ArchiveLength() const
200 ui32_t arch_size = sizeof(ui32_t);
202 typename ArchivableList<T>::const_iterator i = this->begin();
203 for ( ; i != this->end(); i++ )
204 arch_size += i->ArchiveLength();
209 bool Unarchive(Kumu::MemIOReader* Reader)
211 if ( Reader == 0 ) return false;
212 ui32_t read_size = 0;
213 if ( ! Reader->ReadUi32BE(&read_size) ) return false;
214 for ( ui32_t i = 0; i < read_size; i++ )
217 if ( ! TmpTP.Unarchive(Reader) ) return false;
218 this->push_back(TmpTP);
224 bool Archive(Kumu::MemIOWriter* Writer) const
226 if ( Writer == 0 ) return false;
227 if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
228 typename ArchivableList<T>::const_iterator i = this->begin();
229 for ( ; i != this->end(); i++ )
230 if ( ! i->Archive(Writer) ) return false;
236 // archivable version of std::string
239 class ArchivableString : public std::string, public Kumu::IArchive
243 ArchivableString() {}
244 ArchivableString(const char* sz) : std::string(sz) {}
245 ArchivableString(const std::string& s) : std::string(s) {}
246 virtual ~ArchivableString() {}
248 bool HasValue() const { return ! this->empty(); }
249 ui32_t ArchiveLength() const { return static_cast<ui32_t>((sizeof(ui32_t) + this->size())|0xffffffff); }
251 bool Archive(MemIOWriter* Writer) const {
252 if ( Writer == 0 ) return false;
253 return Writer->WriteString(*this);
256 bool Unarchive(MemIOReader* Reader) {
257 if ( Reader == 0 ) return false;
258 return Reader->ReadString(*this);
263 typedef Kumu::ArchivableList<ArchivableString> StringList;
266 // the base of all identifier classes, Identifier is not usually used directly
267 // see UUID and SymmetricKey below for more detail.
269 template <ui32_t SIZE>
270 class Identifier : public IArchive
274 byte_t m_Value[SIZE];
277 Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
278 Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
279 Identifier(const Identifier& rhs) : IArchive() {
280 m_HasValue = rhs.m_HasValue;
281 memcpy(m_Value, rhs.m_Value, SIZE);
284 virtual ~Identifier() {}
286 const Identifier& operator=(const Identifier& rhs) {
287 m_HasValue = rhs.m_HasValue;
288 memcpy(m_Value, rhs.m_Value, SIZE);
292 inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
293 inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
294 inline const byte_t* Value() const { return m_Value; }
295 inline ui32_t Size() const { return SIZE; }
297 inline bool operator<(const Identifier& rhs) const {
298 ui32_t test_size = xmin(rhs.Size(), SIZE);
300 for ( ui32_t i = 0; i < test_size; i++ )
302 if ( m_Value[i] != rhs.m_Value[i] )
303 return m_Value[i] < rhs.m_Value[i];
309 inline bool operator==(const Identifier& rhs) const {
310 if ( rhs.Size() != SIZE ) return false;
311 return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
314 inline bool operator!=(const Identifier& rhs) const {
315 if ( rhs.Size() != SIZE ) return true;
316 return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
319 inline bool DecodeHex(const char* str) {
321 m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
322 if ( m_HasValue && char_count != SIZE )
327 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
328 return bin2hex(m_Value, SIZE, buf, buf_len);
331 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
332 return EncodeHex(str_buf, buf_len);
335 inline bool DecodeBase64(const char* str) {
337 m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
338 if ( m_HasValue && char_count != SIZE )
343 inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
344 return base64encode(m_Value, SIZE, buf, buf_len);
347 inline bool HasValue() const { return m_HasValue; }
349 inline ui32_t ArchiveLength() const { return SIZE; }
351 inline bool Unarchive(Kumu::MemIOReader* Reader) {
352 m_HasValue = Reader->ReadRaw(m_Value, SIZE);
356 inline bool Archive(Kumu::MemIOWriter* Writer) const {
357 return Writer->WriteRaw(m_Value, SIZE);
364 const ui32_t UUID_Length = 16;
365 class UUID : public Identifier<UUID_Length>
369 UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
370 UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
373 inline const char* EncodeString(char* buf, ui32_t buf_len) const {
374 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
377 inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
378 return bin2UUIDhex(m_Value, Size(), buf, buf_len);
382 void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
383 void GenRandomValue(UUID&);
388 typedef ArchivableList<UUID> UUIDList;
390 // a self-wiping key container
392 const ui32_t SymmetricKey_Length = 16;
393 const byte_t NilKey[SymmetricKey_Length] = {
394 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
395 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
398 class SymmetricKey : public Identifier<SymmetricKey_Length>
402 SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
403 SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
404 virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
407 void GenRandomValue(SymmetricKey&);
410 // 2004-05-01T13:20:00+00:00
411 const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds)
413 // UTC time+date representation
414 class Timestamp : public IArchive
416 TAI::tai m_Timestamp; // always UTC
417 i32_t m_TZOffsetMinutes;
421 Timestamp(const Timestamp& rhs);
422 Timestamp(const char* datestr);
423 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day);
424 Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
425 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
426 virtual ~Timestamp();
428 const Timestamp& operator=(const Timestamp& rhs);
429 bool operator<(const Timestamp& rhs) const;
430 bool operator>(const Timestamp& rhs) const;
431 bool operator==(const Timestamp& rhs) const;
432 bool operator!=(const Timestamp& rhs) const;
435 void GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
436 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const;
437 void SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
438 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second);
440 // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
441 // returns 0 if the buffer is smaller than DateTimeLen
442 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
444 // decode and set value from string formatted by EncodeString
445 bool DecodeString(const char* datestr);
447 // Add the given number of days, hours, minutes, or seconds to the timestamp value.
448 // Values less than zero will cause the timestamp to decrease
449 inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
450 inline void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
451 inline void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
452 inline void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
454 // returns false if the requested adjustment is out of range
455 bool SetTZOffsetMinutes(const i32_t& minutes);
456 inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
458 // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
459 ui64_t GetCTime() const;
461 // Read and write the timestamp (always UTC) value as a byte string having
462 // the following format:
463 // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits |
464 // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
466 virtual bool HasValue() const;
467 virtual ui32_t ArchiveLength() const { return 8L; }
468 virtual bool Archive(MemIOWriter* Writer) const;
469 virtual bool Unarchive(MemIOReader* Reader);
473 class ByteString : public IArchive
475 KM_NO_COPY_CONSTRUCT(ByteString);
478 byte_t* m_Data; // pointer to memory area containing frame data
479 ui32_t m_Capacity; // size of memory area pointed to by m_Data
480 ui32_t m_Length; // length of byte string in memory area pointed to by m_Data
484 ByteString(ui32_t cap);
485 virtual ~ByteString();
487 // Sets or resets the size of the internally allocated buffer.
488 Result_t Capacity(ui32_t cap);
490 Result_t Append(const ByteString&);
491 Result_t Append(const byte_t* buf, ui32_t buf_len);
493 // returns the size of the buffer
494 inline ui32_t Capacity() const { return m_Capacity; }
496 // returns a const pointer to the essence data
497 inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
499 // returns a non-const pointer to the essence data
500 inline byte_t* Data() { assert(m_Data); return m_Data; }
502 // set the length of the buffer's contents
503 inline ui32_t Length(ui32_t l) { return m_Length = l; }
505 // returns the length of the buffer's contents
506 inline ui32_t Length() const { return m_Length; }
508 // copy the given data into the ByteString, set Length value.
509 // Returns error if the ByteString is too small.
510 Result_t Set(const byte_t* buf, ui32_t buf_len);
511 Result_t Set(const ByteString& Buf);
513 inline virtual bool HasValue() const { return m_Length > 0; }
515 inline virtual ui32_t ArchiveLength() const { return m_Length; }
517 inline virtual bool Archive(MemIOWriter* Writer) const {
519 if ( ! Writer->WriteUi32BE(m_Length) ) return false;
520 if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
524 inline virtual bool Unarchive(MemIOReader* Reader) {
527 if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
528 if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
529 if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
535 inline void hexdump(const ByteString& buf, FILE*) {
536 hexdump(buf.RoData(), buf.Length());
543 #endif // _KM_UTIL_H_