big KLV support
[asdcplib.git] / src / KM_util.h
1 /*
2 Copyright (c) 2005-2009, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
27   /*! \file    KM_util.h
28     \version $Id$
29     \brief   Utility functions
30   */
31
32 #ifndef _KM_UTIL_H_
33 #define _KM_UTIL_H_
34
35 #include <KM_memio.h>
36 #include <KM_error.h>
37 #include <string.h>
38 #include <string>
39 #include <list>
40
41 namespace Kumu
42 {
43   // The version number declaration and explanation are in ../configure.ac
44   const char* Version();
45
46   // a class that represents the string form of a value
47   template <class T, int SIZE = 16>
48     class IntPrinter : public std::string
49   {
50     KM_NO_COPY_CONSTRUCT(IntPrinter);
51     IntPrinter();
52
53     protected:
54     const char* m_format;
55     char m_strbuf[SIZE];
56     
57     public:
58     IntPrinter(const char* format, T value) {
59       assert(format);
60       m_format = format;
61       snprintf(m_strbuf, SIZE, m_format, value);
62     }
63
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);
68       return m_strbuf;
69     }
70   };
71
72   struct i8Printer : public IntPrinter<i8_t> {
73     i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
74   };
75
76   struct ui8Printer : public IntPrinter<ui8_t> {
77     ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
78   };
79
80   struct i16Printer : public IntPrinter<i16_t> {
81     i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
82   };
83
84   struct ui16Printer : public IntPrinter<ui16_t> {
85     ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
86   };
87
88   struct i32Printer : public IntPrinter<i32_t> {
89     i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
90   };
91
92   struct ui32Printer : public IntPrinter<ui32_t> {
93     ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
94   };
95
96 #ifdef KM_WIN32
97   struct i64Printer : public IntPrinter<i64_t, 32> {
98     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
99   };
100
101   struct ui64Printer : public IntPrinter<ui64_t, 32> {
102     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
103   };
104 #else
105   struct i64Printer : public IntPrinter<i64_t, 32> {
106     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
107   };
108
109   struct ui64Printer : public IntPrinter<ui64_t, 32> {
110     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
111   };
112 #endif
113
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);
121
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
125   // return 0.
126   //
127   const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
128
129   const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
130
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);
134
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 )
138       length++;
139
140     return ( length / 3 ) * 4;
141   }
142
143   // print buffer contents to a stream as hexadecimal values in numbered
144   // rows of 16-bytes each.
145   //
146   void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
147
148   // Return the length in bytes of a BER encoded value
149   inline ui32_t BER_length(const byte_t* buf)
150     {
151       if ( buf == 0 || (*buf & 0xf0) != 0x80 )
152         return 0;
153
154       return (*buf & 0x0f) + 1;
155     }
156
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);
160
161   // read a BER value
162   bool read_BER(const byte_t* buf, ui64_t* val);
163
164   // decode a ber value and compare it to a test value
165   bool read_test_BER(byte_t **buf, ui64_t test_value);
166
167   // create BER encoding of integer value
168   bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
169
170   //----------------------------------------------------------------
171   //
172
173   // an abstract base class that objects implement to serialize state
174   // to and from a binary stream.
175   class IArchive
176     {
177     public:
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;
183     };
184
185   //
186   template <class T>
187   class ArchivableList : public std::list<T>, public IArchive
188     {
189     public:
190       ArchivableList() {}
191       virtual ~ArchivableList() {}
192
193       bool HasValue() const { return ! this->empty(); }
194
195       ui32_t ArchiveLength() const
196       {
197         ui32_t arch_size = sizeof(ui32_t);
198
199         typename ArchivableList<T>::const_iterator i = this->begin();
200         for ( ; i != this->end(); i++ )
201           arch_size += i->ArchiveLength();
202
203         return arch_size;
204       }
205
206       bool Unarchive(Kumu::MemIOReader* Reader)
207         {
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++ )
212             {
213               T TmpTP;
214               if ( ! TmpTP.Unarchive(Reader) ) return false;
215               this->push_back(TmpTP);
216             }
217
218           return true;
219         }
220
221       bool Archive(Kumu::MemIOWriter* Writer) const
222         {
223           if ( Writer == 0 ) return false;
224           if ( ! Writer->WriteUi32BE(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;
228
229           return true;
230         }
231     };
232
233   //
234   // the base of all identifier classes, Identifier is not usually used directly
235   // see UUID and SymmetricKey below for more detail.
236   //
237   template <ui32_t SIZE>
238     class Identifier : public IArchive
239     {
240     protected:
241       bool   m_HasValue;
242       byte_t m_Value[SIZE];
243
244     public:
245       Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
246       Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
247       Identifier(const Identifier& rhs) : IArchive() {
248         m_HasValue = rhs.m_HasValue;
249         memcpy(m_Value, rhs.m_Value, SIZE);
250       }
251
252       virtual ~Identifier() {}
253
254       const Identifier& operator=(const Identifier& rhs) {
255         m_HasValue = rhs.m_HasValue;
256         memcpy(m_Value, rhs.m_Value, SIZE);
257         return *this;
258       }
259
260       inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
261       inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
262       inline const byte_t* Value() const { return m_Value; }
263       inline ui32_t Size() const { return SIZE; }
264
265       inline bool operator<(const Identifier& rhs) const {
266         ui32_t test_size = xmin(rhs.Size(), SIZE);
267
268         for ( ui32_t i = 0; i < test_size; i++ )
269           {
270             if ( m_Value[i] != rhs.m_Value[i] )
271               return m_Value[i] < rhs.m_Value[i];
272           }
273         
274         return false;
275       }
276
277       inline bool operator==(const Identifier& rhs) const {
278         if ( rhs.Size() != SIZE ) return false;
279         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
280       }
281
282       inline bool operator!=(const Identifier& rhs) const {
283         if ( rhs.Size() != SIZE ) return true;
284         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
285       }
286
287       inline bool DecodeHex(const char* str) {
288         ui32_t char_count;
289         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
290         if ( m_HasValue && char_count != SIZE )
291           m_HasValue = false;
292         return m_HasValue;
293       }
294
295       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
296         return bin2hex(m_Value, SIZE, buf, buf_len);
297       }
298
299       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
300         return EncodeHex(str_buf, buf_len);
301       }
302
303       inline bool DecodeBase64(const char* str) {
304         ui32_t char_count;
305         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
306         if ( m_HasValue && char_count != SIZE )
307           m_HasValue = false;
308         return m_HasValue;
309       }
310
311       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
312         return base64encode(m_Value, SIZE, buf, buf_len);
313       }
314
315       inline bool HasValue() const { return m_HasValue; }
316
317       inline ui32_t ArchiveLength() const { return SIZE; }
318
319       inline bool Unarchive(Kumu::MemIOReader* Reader) {
320         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
321         return m_HasValue;
322       }
323
324       inline bool Archive(Kumu::MemIOWriter* Writer) const {
325         return Writer->WriteRaw(m_Value, SIZE);
326       }
327     };
328
329
330   // UUID
331   //
332   const ui32_t UUID_Length = 16;
333   class UUID : public Identifier<UUID_Length>
334     {
335     public:
336       UUID() {}
337       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
338       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
339       virtual ~UUID() {}
340
341       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
342         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
343       }
344
345       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
346         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
347       }
348     };
349   
350   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
351   void GenRandomValue(UUID&);
352   
353   typedef ArchivableList<UUID> UUIDList;
354
355   // a self-wiping key container
356   //
357   const ui32_t SymmetricKey_Length = 16;
358   const byte_t NilKey[SymmetricKey_Length] = {
359     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
360     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
361   };
362
363   class SymmetricKey : public Identifier<SymmetricKey_Length>
364     {
365     public:
366       SymmetricKey() {}
367       SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
368       SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
369       virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
370     };
371
372   void GenRandomValue(SymmetricKey&);
373
374   //
375   // 2004-05-01T13:20:00+00:00
376   const ui32_t DateTimeLen = 25; //  the number of chars in the xs:dateTime format (sans milliseconds)
377
378   // UTC time+date representation
379   class Timestamp : public IArchive
380     {
381     public:
382       ui16_t Year;
383       ui8_t  Month;
384       ui8_t  Day;
385       ui8_t  Hour;
386       ui8_t  Minute;
387       ui8_t  Second;
388
389       Timestamp();
390       Timestamp(const Timestamp& rhs);
391       Timestamp(const char* datestr);
392       virtual ~Timestamp();
393
394       const Timestamp& operator=(const Timestamp& rhs);
395       bool operator<(const Timestamp& rhs) const;
396       bool operator>(const Timestamp& rhs) const;
397       bool operator==(const Timestamp& rhs) const;
398       bool operator!=(const Timestamp& rhs) const;
399
400       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
401       // returns 0 if the buffer is smaller than DateTimeLen
402       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
403       const char* EncodeStringWithOffset(char* str_buf, ui32_t buf_len,
404                                          i32_t offset_minutes = 0) const;
405
406       // decode and set value from string formatted by EncodeString
407       bool        DecodeString(const char* datestr);
408
409       // Add the given number of days, hours, minutes, or seconds to the timestamp value.
410       // Values less than zero will cause the timestamp to decrease
411       void AddDays(i32_t);
412       void AddHours(i32_t);
413       void AddMinutes(i32_t);
414       void AddSeconds(i32_t);
415
416       // Read and write the timestamp value as a byte string having
417       // the following format:
418       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
419       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
420       //
421       virtual bool   HasValue() const;
422       virtual ui32_t ArchiveLength() const { return 8L; }
423       virtual bool   Archive(MemIOWriter* Writer) const;
424       virtual bool   Unarchive(MemIOReader* Reader);
425
426       // Get the number of seconds since the Unix epoch (1970-01-01T00:00:00+00:00)
427       long GetSecondsSinceEpoch(void) const;
428     };
429
430   //
431   class ByteString : public IArchive
432     {
433       KM_NO_COPY_CONSTRUCT(ByteString);
434         
435     protected:
436       byte_t* m_Data;          // pointer to memory area containing frame data
437       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
438       ui32_t  m_Length;        // length of byte string in memory area pointed to by m_Data
439         
440     public:
441       ByteString();
442       ByteString(ui32_t cap);
443       virtual ~ByteString();
444
445       // Sets or resets the size of the internally allocated buffer.
446       Result_t Capacity(ui32_t cap);
447
448       Result_t Append(const ByteString&);
449       Result_t Append(const byte_t* buf, ui32_t buf_len);
450         
451       // returns the size of the buffer
452       inline ui32_t  Capacity() const { return m_Capacity; }
453
454       // returns a const pointer to the essence data
455       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
456         
457       // returns a non-const pointer to the essence data
458       inline byte_t* Data() { assert(m_Data); return m_Data; }
459         
460       // set the length of the buffer's contents
461       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
462         
463       // returns the length of the buffer's contents
464       inline ui32_t  Length() const { return m_Length; }
465
466       // copy the given data into the ByteString, set Length value.
467       // Returns error if the ByteString is too small.
468       Result_t Set(const byte_t* buf, ui32_t buf_len);
469       Result_t Set(const ByteString& Buf);
470
471       inline virtual bool HasValue() const { return m_Length > 0; }
472
473       inline virtual ui32_t ArchiveLength() const { return m_Length; }
474
475       inline virtual bool Archive(MemIOWriter* Writer) const {
476         assert(Writer);
477         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
478         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
479         return true;
480       }
481
482       inline virtual bool Unarchive(MemIOReader* Reader) {
483         assert(Reader);
484         ui32_t tmp_len;
485         if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
486         if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
487         if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
488         m_Length = tmp_len;
489         return true;
490       }
491     };
492
493 } // namespace Kumu
494
495
496 #endif // _KM_UTIL_H_
497
498 //
499 // end KM_util.h
500 //