big change rollup
[asdcplib.git] / src / KM_util.h
1 /*
2 Copyright (c) 2005-2012, 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 <string>
40 #include <list>
41
42 namespace Kumu
43 {
44   // The version number declaration and explanation are in ../configure.ac
45   const char* Version();
46
47   // a class that represents the string form of a value
48   template <class T, int SIZE = 16>
49     class IntPrinter : public std::string
50   {
51     KM_NO_COPY_CONSTRUCT(IntPrinter);
52     IntPrinter();
53
54     protected:
55     const char* m_format;
56     char m_strbuf[SIZE];
57     
58     public:
59     IntPrinter(const char* format, T value) {
60       assert(format);
61       m_format = format;
62       snprintf(m_strbuf, SIZE, m_format, value);
63     }
64
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);
69       return m_strbuf;
70     }
71   };
72
73   struct i8Printer : public IntPrinter<i8_t> {
74     i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
75   };
76
77   struct ui8Printer : public IntPrinter<ui8_t> {
78     ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
79   };
80
81   struct i16Printer : public IntPrinter<i16_t> {
82     i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
83   };
84
85   struct ui16Printer : public IntPrinter<ui16_t> {
86     ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
87   };
88
89   struct i32Printer : public IntPrinter<i32_t> {
90     i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
91   };
92
93   struct ui32Printer : public IntPrinter<ui32_t> {
94     ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
95   };
96
97 #ifdef KM_WIN32
98   struct i64Printer : public IntPrinter<i64_t, 32> {
99     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
100   };
101
102   struct ui64Printer : public IntPrinter<ui64_t, 32> {
103     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
104   };
105 #else
106   struct i64Printer : public IntPrinter<i64_t, 32> {
107     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
108   };
109
110   struct ui64Printer : public IntPrinter<ui64_t, 32> {
111     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
112   };
113 #endif
114
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);
122
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
126   // return 0.
127   //
128   const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
129
130   const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
131
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);
135
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 )
139       length++;
140
141     return ( length / 3 ) * 4;
142   }
143
144   // print buffer contents to a stream as hexadecimal values in numbered
145   // rows of 16-bytes each.
146   //
147   void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
148
149   // Return the length in bytes of a BER encoded value
150   inline ui32_t BER_length(const byte_t* buf)
151     {
152       if ( buf == 0 || (*buf & 0xf0) != 0x80 )
153         return 0;
154
155       return (*buf & 0x0f) + 1;
156     }
157
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);
161
162   // read a BER value
163   bool read_BER(const byte_t* buf, ui64_t* val);
164
165   // decode a ber value and compare it to a test value
166   bool read_test_BER(byte_t **buf, ui64_t test_value);
167
168   // create BER encoding of integer value
169   bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
170
171   //----------------------------------------------------------------
172   //
173
174   // an abstract base class that objects implement to serialize state
175   // to and from a binary stream.
176   class IArchive
177     {
178     public:
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;
184     };
185
186   //
187   template <class T>
188   class ArchivableList : public std::list<T>, public IArchive
189     {
190     public:
191       ArchivableList() {}
192       virtual ~ArchivableList() {}
193
194       bool HasValue() const { return ! this->empty(); }
195
196       ui32_t ArchiveLength() const
197       {
198         ui32_t arch_size = sizeof(ui32_t);
199
200         typename ArchivableList<T>::const_iterator i = this->begin();
201         for ( ; i != this->end(); i++ )
202           arch_size += i->ArchiveLength();
203
204         return arch_size;
205       }
206
207       bool Unarchive(Kumu::MemIOReader* Reader)
208         {
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++ )
213             {
214               T TmpTP;
215               if ( ! TmpTP.Unarchive(Reader) ) return false;
216               this->push_back(TmpTP);
217             }
218
219           return true;
220         }
221
222       bool Archive(Kumu::MemIOWriter* Writer) const
223         {
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;
229
230           return true;
231         }
232     };
233
234   // archivable version of std::string
235
236   //
237   class ArchivableString : public std::string, public Kumu::IArchive
238     {
239
240     public:
241       ArchivableString() {}
242       ArchivableString(const char* sz) : std::string(sz) {}
243       ArchivableString(const std::string& s) : std::string(s) {}
244       virtual ~ArchivableString() {}
245
246       bool   HasValue() const { return ! this->empty(); }
247       ui32_t ArchiveLength() const { sizeof(ui32_t) + static_cast<ui32_t>(this->size()); }
248
249       bool   Archive(MemIOWriter* Writer) const {
250         if ( Writer == 0 ) return false;
251         return Writer->WriteString(*this);
252       }
253
254       bool   Unarchive(MemIOReader* Reader) {
255         if ( Reader == 0 ) return false;
256         return Reader->ReadString(*this);
257       }
258     };
259
260   //
261   typedef Kumu::ArchivableList<ArchivableString> StringList;
262
263   //
264   // the base of all identifier classes, Identifier is not usually used directly
265   // see UUID and SymmetricKey below for more detail.
266   //
267   template <ui32_t SIZE>
268     class Identifier : public IArchive
269     {
270     protected:
271       bool   m_HasValue;
272       byte_t m_Value[SIZE];
273
274     public:
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);
280       }
281
282       virtual ~Identifier() {}
283
284       const Identifier& operator=(const Identifier& rhs) {
285         m_HasValue = rhs.m_HasValue;
286         memcpy(m_Value, rhs.m_Value, SIZE);
287         return *this;
288       }
289
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; }
294
295       inline bool operator<(const Identifier& rhs) const {
296         ui32_t test_size = xmin(rhs.Size(), SIZE);
297
298         for ( ui32_t i = 0; i < test_size; i++ )
299           {
300             if ( m_Value[i] != rhs.m_Value[i] )
301               return m_Value[i] < rhs.m_Value[i];
302           }
303         
304         return false;
305       }
306
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 );
310       }
311
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 );
315       }
316
317       inline bool DecodeHex(const char* str) {
318         ui32_t char_count;
319         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
320         if ( m_HasValue && char_count != SIZE )
321           m_HasValue = false;
322         return m_HasValue;
323       }
324
325       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
326         return bin2hex(m_Value, SIZE, buf, buf_len);
327       }
328
329       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
330         return EncodeHex(str_buf, buf_len);
331       }
332
333       inline bool DecodeBase64(const char* str) {
334         ui32_t char_count;
335         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
336         if ( m_HasValue && char_count != SIZE )
337           m_HasValue = false;
338         return m_HasValue;
339       }
340
341       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
342         return base64encode(m_Value, SIZE, buf, buf_len);
343       }
344
345       inline bool HasValue() const { return m_HasValue; }
346
347       inline ui32_t ArchiveLength() const { return SIZE; }
348
349       inline bool Unarchive(Kumu::MemIOReader* Reader) {
350         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
351         return m_HasValue;
352       }
353
354       inline bool Archive(Kumu::MemIOWriter* Writer) const {
355         return Writer->WriteRaw(m_Value, SIZE);
356       }
357     };
358
359
360   // UUID
361   //
362   const ui32_t UUID_Length = 16;
363   class UUID : public Identifier<UUID_Length>
364     {
365     public:
366       UUID() {}
367       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
368       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
369       virtual ~UUID() {}
370
371       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
372         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
373       }
374
375       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
376         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
377       }
378     };
379   
380   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
381   void GenRandomValue(UUID&);
382   
383   typedef ArchivableList<UUID> UUIDList;
384
385   // a self-wiping key container
386   //
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
391   };
392
393   class SymmetricKey : public Identifier<SymmetricKey_Length>
394     {
395     public:
396       SymmetricKey() {}
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; }
400     };
401
402   void GenRandomValue(SymmetricKey&);
403
404   //
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)
407
408   // UTC time+date representation
409   class Timestamp : public IArchive
410     {
411       TAI::tai m_Timestamp; // always UTC
412       i32_t m_TZOffsetMinutes;
413
414    public:
415       Timestamp();
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();
422
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;
428
429       // always UTC
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);
434
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;
438
439       // decode and set value from string formatted by EncodeString
440       bool        DecodeString(const char* datestr);
441
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); }
448
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; }
452
453       // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
454       ui64_t GetCTime() const;
455
456       // Set internal time to the number of seconds since the Unix epoch UTC
457       void SetCTime(const ui64_t& ctime);
458
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) |
463       //
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);
468     };
469
470   //
471   class ByteString : public IArchive
472     {
473       KM_NO_COPY_CONSTRUCT(ByteString);
474         
475     protected:
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
479         
480     public:
481       ByteString();
482       ByteString(ui32_t cap);
483       virtual ~ByteString();
484
485       // Sets or resets the size of the internally allocated buffer.
486       Result_t Capacity(ui32_t cap);
487
488       Result_t Append(const ByteString&);
489       Result_t Append(const byte_t* buf, ui32_t buf_len);
490         
491       // returns the size of the buffer
492       inline ui32_t  Capacity() const { return m_Capacity; }
493
494       // returns a const pointer to the essence data
495       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
496         
497       // returns a non-const pointer to the essence data
498       inline byte_t* Data() { assert(m_Data); return m_Data; }
499         
500       // set the length of the buffer's contents
501       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
502         
503       // returns the length of the buffer's contents
504       inline ui32_t  Length() const { return m_Length; }
505
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);
510
511       inline virtual bool HasValue() const { return m_Length > 0; }
512
513       inline virtual ui32_t ArchiveLength() const { return m_Length; }
514
515       inline virtual bool Archive(MemIOWriter* Writer) const {
516         assert(Writer);
517         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
518         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
519         return true;
520       }
521
522       inline virtual bool Unarchive(MemIOReader* Reader) {
523         assert(Reader);
524         ui32_t tmp_len;
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;
528         m_Length = tmp_len;
529         return true;
530       }
531     };
532
533   inline void hexdump(const ByteString& buf, FILE* stream = 0) {
534     hexdump(buf.RoData(), buf.Length());
535   }
536
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);
541
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);
545
546 } // namespace Kumu
547
548
549 #endif // _KM_UTIL_H_
550
551 //
552 // end KM_util.h
553 //