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