bugfixes for release
[asdcplib.git] / src / KM_util.h
1 /*
2 Copyright (c) 2005-2006, 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 bool Archive(MemIOWriter* Writer) const = 0;
175       virtual bool Unarchive(MemIOReader* Reader) = 0;
176     };
177
178
179   //
180   // the base of all identifier classes, Identifier is not usually used directly
181   // see UUID and SymmetricKey below for more detail.
182   //
183   template <ui32_t SIZE>
184     class Identifier : public IArchive
185     {
186     protected:
187       bool   m_HasValue;
188       byte_t m_Value[SIZE];
189
190     public:
191       Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
192       Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
193       Identifier(const Identifier& rhs) {
194         m_HasValue = rhs.m_HasValue;
195         memcpy(m_Value, rhs.m_Value, SIZE);
196       }
197
198       virtual ~Identifier() {}
199
200       const Identifier& operator=(const Identifier& rhs) {
201         m_HasValue = rhs.m_HasValue;
202         memcpy(m_Value, rhs.m_Value, SIZE);
203         return *this;
204       }
205
206       inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
207       inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
208       inline const byte_t* Value() const { return m_Value; }
209       inline ui32_t Size() const { return SIZE; }
210
211       inline bool operator<(const Identifier& rhs) const {
212         ui32_t test_size = xmin(rhs.Size(), SIZE);
213
214         for ( ui32_t i = 0; i < test_size; i++ )
215           {
216             if ( m_Value[i] != rhs.m_Value[i] )
217               return m_Value[i] < rhs.m_Value[i];
218           }
219         
220         return false;
221       }
222
223       inline bool operator==(const Identifier& rhs) const {
224         if ( rhs.Size() != SIZE ) return false;
225         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
226       }
227
228       inline bool operator!=(const Identifier& rhs) const {
229         if ( rhs.Size() != SIZE ) return true;
230         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
231       }
232
233       inline bool DecodeHex(const char* str) {
234         ui32_t char_count;
235         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
236         return m_HasValue;
237       }
238
239       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
240         return bin2hex(m_Value, SIZE, buf, buf_len);
241       }
242
243       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
244         return EncodeHex(str_buf, buf_len);
245       }
246
247       inline bool DecodeBase64(const char* str) {
248         ui32_t char_count;
249         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
250         return m_HasValue;
251       }
252
253       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
254         return base64encode(m_Value, SIZE, buf, buf_len);
255       }
256
257       inline bool HasValue() const { return m_HasValue; }
258
259       inline bool Unarchive(Kumu::MemIOReader* Reader) {
260         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
261         return m_HasValue;
262       }
263
264       inline bool Archive(Kumu::MemIOWriter* Writer) const {
265         return Writer->WriteRaw(m_Value, SIZE);
266       }
267     };
268
269   //
270   template <class T>
271   class IdentifierList : public std::list<T>, public IArchive
272     {
273     public:
274       IdentifierList() {}
275       virtual ~IdentifierList() {}
276
277       bool HasValue() const { return ! this->empty(); }
278
279       bool Unarchive(Kumu::MemIOReader* Reader)
280         {
281           if ( Reader == 0 )return false;
282           ui32_t read_size = 0;
283           if ( ! Reader->ReadUi32BE(&read_size) ) return false;
284           for ( ui32_t i = 0; i < read_size; i++ )
285             {
286               T TmpTP;
287               if ( ! TmpTP.Unarchive(Reader) ) return false;
288               this->push_back(TmpTP);
289             }
290
291           return true;
292         }
293
294       bool Archive(Kumu::MemIOWriter* Writer) const
295         {
296           if ( Writer == 0 )return false;
297           if ( ! Writer->WriteUi32BE(this->size()) ) return false;
298           typename IdentifierList<T>::const_iterator i = this->begin();
299           for ( ; i != this->end(); i++ )
300             if ( ! (*i).Archive(Writer) ) return false;
301
302           return true;
303         }
304     };
305
306   // UUID
307   //
308   const ui32_t UUID_Length = 16;
309   class UUID : public Identifier<UUID_Length>
310     {
311     public:
312       UUID() {}
313       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
314       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
315       virtual ~UUID() {}
316
317       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
318         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
319       }
320
321       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
322         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
323       }
324     };
325   
326   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
327   void GenRandomValue(UUID&);
328   
329   // a self-wiping key container
330   //
331   const ui32_t SymmetricKey_Length = 16;
332   const byte_t NilKey[SymmetricKey_Length] = {
333     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
334     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
335   };
336
337   class SymmetricKey : public Identifier<SymmetricKey_Length>
338     {
339     public:
340       SymmetricKey() {}
341       SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
342       SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
343       virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
344     };
345
346   void GenRandomValue(SymmetricKey&);
347
348   //
349   // 2004-05-01T13:20:00-00:00
350   const ui32_t DateTimeLen = 25; //  the number of chars in the xs:dateTime format (sans milliseconds)
351
352   // UTC time+date representation
353   class Timestamp : public IArchive
354     {
355     public:
356       ui16_t Year;
357       ui8_t  Month;
358       ui8_t  Day;
359       ui8_t  Hour;
360       ui8_t  Minute;
361       ui8_t  Second;
362
363       Timestamp();
364       Timestamp(const Timestamp& rhs);
365       Timestamp(const char* datestr);
366       virtual ~Timestamp();
367
368       const Timestamp& operator=(const Timestamp& rhs);
369       bool operator<(const Timestamp& rhs) const;
370       bool operator>(const Timestamp& rhs) const;
371       bool operator==(const Timestamp& rhs) const;
372       bool operator!=(const Timestamp& rhs) const;
373
374       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00-00:00
375       // returns 0 if the buffer is smaller than DateTimeLen
376       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
377
378       // decode and set value from string formatted by EncodeString
379       bool        DecodeString(const char* datestr);
380
381       // Add the given number of days or hours to the timestamp value.
382       // Values less than zero will cause the timestamp to decrease
383       void AddDays(i32_t);
384       void AddHours(i32_t);
385
386       // Read and write the timestamp value as a byte string having
387       // the following format:
388       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
389       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
390       //
391       virtual bool HasValue() const;
392       virtual bool Archive(MemIOWriter* Writer) const;
393       virtual bool Unarchive(MemIOReader* Reader);
394     };
395
396   //
397   class ByteString : public IArchive
398     {
399       KM_NO_COPY_CONSTRUCT(ByteString);
400         
401     protected:
402       byte_t* m_Data;          // pointer to memory area containing frame data
403       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
404       ui32_t  m_Length;        // length of byte string in memory area pointed to by m_Data
405         
406     public:
407       ByteString();
408       ByteString(ui32_t cap);
409       virtual ~ByteString();
410
411       // Sets the size of the internally allocated buffer.
412       // Resets content Size to zero.
413       Result_t Capacity(ui32_t cap);
414
415       Result_t Append(const ByteString&);
416       Result_t Append(const byte_t* buf, ui32_t buf_len);
417         
418       // returns the size of the buffer
419       inline ui32_t  Capacity() const { return m_Capacity; }
420
421       // returns a const pointer to the essence data
422       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
423         
424       // returns a non-const pointer to the essence data
425       inline byte_t* Data() { assert(m_Data); return m_Data; }
426         
427       // set the length of the buffer's contents
428       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
429         
430       // returns the length of the buffer's contents
431       inline ui32_t  Length() const { return m_Length; }
432
433       // copy the given data into the ByteString, set Length value.
434       // Returns error if the ByteString is too small.
435       Result_t Set(const byte_t* buf, ui32_t buf_len);
436       Result_t Set(const ByteString& Buf);
437
438       inline virtual bool HasValue() const { return m_Length > 0; }
439
440       inline virtual bool Archive(MemIOWriter* Writer) const {
441         assert(Writer);
442         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
443         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
444         return true;
445       }
446
447       inline virtual bool Unarchive(MemIOReader* Reader) {
448         assert(Reader);
449         ui32_t tmp_len;
450         if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
451         if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
452         if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
453         m_Length = tmp_len;
454         return true;
455       }
456     };
457
458 } // namespace Kumu
459
460
461 #endif // _KM_UTIL_H_
462
463 //
464 // end KM_util.h
465 //