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