Merge pull request #20 from cinecert/htj2c
[asdcplib.git] / src / KM_util.h
1 /*
2 Copyright (c) 2005-2015, 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 <KM_tai.h>
38 #include <string.h>
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(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;
228
229           return true;
230         }
231     };
232
233   // archivable version of std::string
234
235   //
236   class ArchivableString : public std::string, public Kumu::IArchive
237     {
238
239     public:
240       ArchivableString() {}
241       ArchivableString(const char* sz) : std::string(sz) {}
242       ArchivableString(const std::string& s) : std::string(s) {}
243       virtual ~ArchivableString() {}
244
245       bool   HasValue() const { return ! this->empty(); }
246       ui32_t ArchiveLength() const { return sizeof(ui32_t) + static_cast<ui32_t>(this->size()); }
247
248       bool   Archive(MemIOWriter* Writer) const {
249         if ( Writer == 0 ) return false;
250         return Writer->WriteString(*this);
251       }
252
253       bool   Unarchive(MemIOReader* Reader) {
254         if ( Reader == 0 ) return false;
255         return Reader->ReadString(*this);
256       }
257     };
258
259   //
260   class ArchivableUi16 : public Kumu::IArchive
261     {
262     public:
263       ui16_t value;
264
265       ArchivableUi16() : value(0) {}
266       ArchivableUi16(const ui16_t& val) : value(val) {}
267       virtual ~ArchivableUi16() {}
268
269       bool   HasValue() const { return true; }
270       ui32_t ArchiveLength() const { return sizeof(ui16_t); }
271
272           operator ui16_t() const { return value; }
273
274       bool   Archive(MemIOWriter* Writer) const {
275         if ( Writer == 0 ) return false;
276         return Writer->WriteUi16BE(value);
277       }
278
279       bool   Unarchive(MemIOReader* Reader) {
280         if ( Reader == 0 ) return false;
281         return Reader->ReadUi16BE(&value);
282       }
283
284       const char* EncodeString(char* str_buf, ui32_t buf_len) const {
285         snprintf(str_buf, buf_len, "%hu", value);
286         return str_buf;
287       }
288     };
289
290   //
291   typedef Kumu::ArchivableList<ArchivableString> StringList;
292
293   //
294   // the base of all identifier classes, Identifier is not usually used directly
295   // see UUID and SymmetricKey below for more detail.
296   //
297   template <ui32_t SIZE>
298     class Identifier : public IArchive
299     {
300     protected:
301       bool   m_HasValue;
302       byte_t m_Value[SIZE];
303
304     public:
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);
310       }
311
312       virtual ~Identifier() {}
313
314       const Identifier& operator=(const Identifier& rhs) {
315         m_HasValue = rhs.m_HasValue;
316         memcpy(m_Value, rhs.m_Value, SIZE);
317         return *this;
318       }
319
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; }
324
325       inline bool operator<(const Identifier& rhs) const {
326         ui32_t test_size = xmin(rhs.Size(), SIZE);
327
328         for ( ui32_t i = 0; i < test_size; i++ )
329           {
330             if ( m_Value[i] != rhs.m_Value[i] )
331               return m_Value[i] < rhs.m_Value[i];
332           }
333         
334         return false;
335       }
336
337       inline bool operator>(const Identifier& rhs) const {
338         ui32_t test_size = xmin(rhs.Size(), SIZE);
339
340         for ( ui32_t i = 0; i < test_size; i++ )
341           {
342             if ( m_Value[i] != rhs.m_Value[i] )
343               return m_Value[i] > rhs.m_Value[i];
344           }
345         
346         return false;
347       }
348
349       inline bool operator==(const Identifier& rhs) const {
350         if ( rhs.Size() != SIZE ) return false;
351         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
352       }
353
354       inline bool operator!=(const Identifier& rhs) const {
355         if ( rhs.Size() != SIZE ) return true;
356         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
357       }
358
359       inline bool DecodeHex(const char* str) {
360         ui32_t char_count;
361         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
362         if ( m_HasValue && char_count != SIZE )
363           m_HasValue = false;
364         return m_HasValue;
365       }
366
367       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
368         return bin2hex(m_Value, SIZE, buf, buf_len);
369       }
370
371       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
372         return EncodeHex(str_buf, buf_len);
373       }
374
375       inline bool DecodeBase64(const char* str) {
376         ui32_t char_count;
377         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
378         if ( m_HasValue && char_count != SIZE )
379           m_HasValue = false;
380         return m_HasValue;
381       }
382
383       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
384         return base64encode(m_Value, SIZE, buf, buf_len);
385       }
386
387       inline bool HasValue() const { return m_HasValue; }
388
389       inline ui32_t ArchiveLength() const { return SIZE; }
390
391       inline bool Unarchive(Kumu::MemIOReader* Reader) {
392         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
393         return m_HasValue;
394       }
395
396       inline bool Archive(Kumu::MemIOWriter* Writer) const {
397         return Writer->WriteRaw(m_Value, SIZE);
398       }
399     };
400
401
402   // UUID
403   //
404   const ui32_t UUID_Length = 16;
405   class UUID : public Identifier<UUID_Length>
406     {
407     public:
408       UUID() {}
409       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
410       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
411       virtual ~UUID() {}
412
413       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
414         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
415       }
416
417       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
418         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
419       }
420     };
421   
422   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
423   void GenRandomValue(UUID&);
424   
425   typedef ArchivableList<UUID> UUIDList;
426
427   // a self-wiping key container
428   //
429   const ui32_t SymmetricKey_Length = 16;
430   const byte_t NilKey[SymmetricKey_Length] = {
431     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
432     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
433   };
434
435   class SymmetricKey : public Identifier<SymmetricKey_Length>
436     {
437     public:
438       SymmetricKey() {}
439       SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
440       SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
441       virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
442     };
443
444   void GenRandomValue(SymmetricKey&);
445
446   //
447   // 2004-05-01T13:20:00+00:00
448   const ui32_t DateTimeLen = 25; //  the number of chars in the xs:dateTime format (sans milliseconds)
449
450   // UTC time+date representation
451   class Timestamp : public IArchive
452     {
453       TAI::tai m_Timestamp; // always UTC
454       i32_t m_TZOffsetMinutes;
455
456    public:
457       Timestamp();
458       Timestamp(const Timestamp& rhs);
459       Timestamp(const char* datestr);
460       Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day);
461       Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day,
462                 const ui8_t&  Hour, const ui8_t&  Minute, const ui8_t&  Second);
463       virtual ~Timestamp();
464
465       const Timestamp& operator=(const Timestamp& rhs);
466       bool operator<(const Timestamp& rhs) const;
467       bool operator>(const Timestamp& rhs) const;
468       bool operator==(const Timestamp& rhs) const;
469       bool operator!=(const Timestamp& rhs) const;
470
471       // always UTC
472       void GetComponents(ui16_t& Year, ui8_t&  Month, ui8_t&  Day,
473                          ui8_t&  Hour, ui8_t&  Minute, ui8_t&  Second) const;      
474       void SetComponents(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day,
475                          const ui8_t&  Hour, const ui8_t&  Minute, const ui8_t&  Second);
476
477       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
478       // returns 0 if the buffer is smaller than DateTimeLen
479       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
480
481       // decode and set value from string formatted by EncodeString
482       bool        DecodeString(const char* datestr);
483
484       // Add the given number of days, hours, minutes, or seconds to the timestamp value.
485       // Values less than zero will cause the timestamp to decrease
486       inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
487       inline  void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
488       inline  void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
489       inline  void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
490
491       // returns false if the requested adjustment is out of range
492       bool SetTZOffsetMinutes(const i32_t& minutes);
493       inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
494
495       // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
496       ui64_t GetCTime() const;
497
498       // Set internal time to the number of seconds since the Unix epoch UTC
499       void SetCTime(const ui64_t& ctime);
500
501       // Read and write the timestamp (always UTC) value as a byte string having
502       // the following format:
503       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
504       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
505       //
506       virtual bool   HasValue() const;
507       virtual ui32_t ArchiveLength() const { return 8L; }
508       virtual bool   Archive(MemIOWriter* Writer) const;
509       virtual bool   Unarchive(MemIOReader* Reader);
510     };
511
512   //
513   class ByteString : public IArchive
514     {
515       KM_NO_COPY_CONSTRUCT(ByteString);
516         
517     protected:
518       byte_t* m_Data;          // pointer to memory area containing frame data
519       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
520       ui32_t  m_Length;        // length of byte string in memory area pointed to by m_Data
521         
522     public:
523       ByteString();
524       ByteString(ui32_t cap);
525       virtual ~ByteString();
526
527       // Sets or resets the size of the internally allocated buffer.
528       Result_t Capacity(ui32_t cap);
529
530       Result_t Append(const ByteString&);
531       Result_t Append(const byte_t* buf, ui32_t buf_len);
532         
533       // returns the size of the buffer
534       inline ui32_t  Capacity() const { return m_Capacity; }
535
536       // returns a const pointer to the essence data
537       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
538         
539       // returns a non-const pointer to the essence data
540       inline byte_t* Data() { assert(m_Data); return m_Data; }
541         
542       // set the length of the buffer's contents
543       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
544         
545       // returns the length of the buffer's contents
546       inline ui32_t  Length() const { return m_Length; }
547
548       // copy the given data into the ByteString, set Length value.
549       // Returns error if the ByteString is too small.
550       Result_t Set(const byte_t* buf, ui32_t buf_len);
551       Result_t Set(const ByteString& Buf);
552
553       inline virtual bool HasValue() const { return m_Length > 0; }
554
555       inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + m_Length; }
556
557       inline virtual bool Archive(MemIOWriter* Writer) const {
558         assert(Writer);
559         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
560         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
561         return true;
562       }
563
564       inline virtual bool Unarchive(MemIOReader* Reader) {
565         assert(Reader);
566         ui32_t tmp_len;
567         if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
568         if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
569         if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
570         m_Length = tmp_len;
571         return true;
572       }
573     };
574
575   inline void hexdump(const ByteString& buf, FILE* stream = 0) {
576     hexdump(buf.RoData(), buf.Length(), stream);
577   }
578
579   // Locates the first occurrence of the null-terminated string s2 in the string s1, where not more
580   // than n characters are searched.  Characters that appear after a `\0' character are not searched.
581   // Reproduced here from BSD for portability.
582   const char *km_strnstr(const char *s1, const char *s2, size_t n);
583
584   // Split the input string into tokens using the given separator. If the separator is not found the
585   // entire string will be returned as a single-item list.  Empty items will be recorded for
586   // adjacent instances of the separator. E.g., "/foo//bar/" will return ["", "foo", "", "bar", ""].
587   std::list<std::string> km_token_split(const std::string& str, const std::string& separator);
588
589   // Join the tokens in the given list using delimiter. If prefix is defined then each token
590   // will be concatenated with the prefix before being added to the composite string.
591   template <class T>
592     std::string
593     km_join(const T& list, const std::string& delimiter, const std::string& prefix = "")
594     {
595       std::string result;
596
597       for ( typename T::const_iterator i = list.begin(); i != list.end(); ++i )
598         {
599           if ( i != list.begin() )
600             {
601               result += delimiter;
602             }
603       
604           result += prefix + *i;
605         }
606
607       return result;
608     }
609
610 } // namespace Kumu
611
612
613 #endif // _KM_UTIL_H_
614
615 //
616 // end KM_util.h
617 //