kumu merge
[asdcplib.git] / src / KM_util.cpp
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.cpp
28     \version $Id$
29     \brief   Utility functions
30   */
31
32 #include <KM_util.h>
33 #include <KM_prng.h>
34 #include <KM_memio.h>
35 #include <KM_fileio.h>
36 #include <KM_log.h>
37 #include <ctype.h>
38 #include <list>
39 #include <map>
40 #include <string>
41
42 //------------------------------------------------------------------------------------------
43
44 // Result_t Internals
45
46 struct map_entry_t
47 {
48   long            rcode;
49   Kumu::Result_t* result;
50 };
51
52 const ui32_t MapMax = 512;
53 const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t));
54 static bool s_MapInit = false;
55 static struct map_entry_t s_ResultMap[MapSize];
56
57 //
58 const Kumu::Result_t&
59 Kumu::Result_t::Find(long v)
60 {
61   for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
62     {
63       if ( s_ResultMap[i].rcode == v )
64         return *s_ResultMap[i].result;
65     }
66
67   DefaultLogSink().Error("Unknown result code: %ld\n", v);
68   return RESULT_FAIL;
69 }
70
71 //
72 Kumu::Result_t::Result_t(long v, const char* l) : value(v), label(l)
73 {
74   assert(l);
75
76   if ( ! s_MapInit )
77     {
78       s_MapInit = true;
79       s_ResultMap[0].rcode = v;
80       s_ResultMap[0].result = this;
81       s_ResultMap[1].rcode = 0;
82       s_ResultMap[1].result = 0;
83       return;
84     }
85
86   ui32_t i = 0;
87   while ( s_ResultMap[i].result != 0 && i < MapMax )
88     {
89       i++;
90       if ( s_ResultMap[i].rcode == v )
91         return;
92     }
93
94   assert(i+2 < MapMax);
95
96   s_ResultMap[i].rcode = v;
97   s_ResultMap[i].result = this;
98   s_ResultMap[i+1].rcode = 0;
99   s_ResultMap[i+1].result = 0;
100   return;
101 }
102
103 Kumu::Result_t::~Result_t() {}
104
105
106 //------------------------------------------------------------------------------------------
107
108
109 const char  fill = '=';
110 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
111
112 const byte_t decode_map[] =
113 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
114   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
117   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118   0xff, 0xff, 0xff, 62,   0xff, 0xff, 0xff, 63,
119   52,   53,   54,   55,   56,   57,   58,   59,
120   60,   61,   0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
121   0xff, 0,    1,    2,    3,    4,    5,    6,
122   7,    8,    9,    10,   11,   12,   13,   14,
123   15,   16,   17,   18,   19,   20,   21,   22,
124   23,   24,   25,   0xff, 0xff, 0xff, 0xff, 0xff,
125   0xff, 26,   27,   28,   29,   30,   31,   32,
126   33,   34,   35,   36,   37,   38,   39,   40,
127   41,   42,   43,   44,   45,   46,   47,   48,
128   49,   50,   51,   0xff, 0xff, 0xff, 0xff, 0xff,
129   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
135   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
145 };
146
147
148 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
149 // if the binary buffer was large enough to hold the result. If the output buffer
150 // is too small or any of the pointer arguments are NULL, the subroutine will
151 // return 0.
152 //
153 const char*
154 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
155 {
156   ui32_t out_char = 0;
157   ui32_t i, block_len, diff;
158
159   if ( buf == 0 || strbuf == 0 )
160     return 0;
161
162   if ( strbuf_len < base64_encode_length(buf_len) + 1 )
163     return 0;
164
165   block_len = buf_len;
166
167   while ( block_len % 3 )
168     block_len--;
169
170   for ( i = 0; i < block_len; i += 3 )
171     {
172       strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
173       strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
174       strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
175       strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
176       buf += 3;
177     }
178
179   if ( i < buf_len )
180     {
181       diff = buf_len - i;
182       assert(diff > 0);
183       assert(diff < 3);
184       
185       strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
186
187       if ( diff == 1 )
188         {
189           strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
190           strbuf[out_char++] = fill;
191         }
192       else if ( diff == 2 )
193         {
194           strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
195           strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
196         }
197
198       strbuf[out_char++] = fill;
199     }
200
201   strbuf[out_char] = 0;
202   return strbuf;;
203 }
204
205
206
207
208 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
209 // the binary buffer was large enough to hold the result. The output parameter
210 // 'char_count' will contain the length of the converted string. If the output
211 // buffer is too small or any of the pointer arguments are NULL, the subroutine
212 // will return -1 and set 'char_count' to the required buffer size. No data will
213 // be written to 'buf' if the subroutine fails.
214 //
215 i32_t
216 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
217 {
218   register byte_t c = 0, d = 0;
219   register ui32_t phase = 0, i = 0;
220
221   if ( str == 0 || buf == 0 || char_count == 0 )
222     return -1;
223
224   while ( *str != 0 && i < buf_len )
225     {
226       c = decode_map[(int)*str++];
227       if ( c == 0xff ) continue;
228       if ( c == 0xfe ) break;
229
230       switch ( phase++ )
231         {
232         case 0:
233           buf[i++] =  c << 2;
234           break;
235
236         case 1:
237           buf[i - 1] |= c >> 4;
238           d = c;
239           break;
240
241         case 2:
242           buf[i++] =  ( d << 4 ) | ( c >> 2 );
243           d = c;
244           break;
245
246         case 3:
247           buf[i++] =  ( d << 6 ) | c;
248           phase = 0;
249           break;
250         }
251     }
252
253   *char_count = i;
254   return 0;
255 }
256
257 //------------------------------------------------------------------------------------------
258
259 // convert utf-8 hext string to bin
260 i32_t
261 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
262 {
263   KM_TEST_NULL(str);
264   KM_TEST_NULL(buf);
265   KM_TEST_NULL(conv_size);
266
267   *conv_size = 0;
268
269   if ( str[0] == 0 ) // nothing to convert
270     return 0;
271
272   for ( int j = 0; str[j]; j++ )
273     {
274       if ( isxdigit(str[j]) )
275         (*conv_size)++;
276     }
277
278   if ( *conv_size & 0x01 ) (*conv_size)++;
279   *conv_size /= 2;
280
281   if ( *conv_size > buf_len )// maximum possible data size
282     return -1;
283
284   *conv_size = 0;
285
286   int phase = 0; // track high/low nybble
287
288   // for each character, fill in the high nybble then the low
289   for ( int i = 0; str[i]; i++ )
290     {
291       if ( ! isxdigit(str[i]) )
292         continue;
293
294       byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
295
296       if ( phase == 0 )
297         {
298           buf[*conv_size] = val << 4;
299           phase++;
300         }
301       else
302         {
303           buf[*conv_size] |= val;
304           phase = 0;
305           (*conv_size)++;
306         }
307     }
308
309   return 0;
310 }
311
312
313 // convert a memory region to a NULL-terminated hexadecimal string
314 //
315 const char*
316 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
317 {
318   if ( bin_buf == 0
319        || str_buf == 0
320        || ((bin_len * 2) + 1) > str_len )
321     return 0;
322
323   char* p = str_buf;
324
325   for ( ui32_t i = 0; i < bin_len; i++ )
326     {
327       *p = (bin_buf[i] >> 4) & 0x0f;
328       *p += *p < 10 ? 0x30 : 0x61 - 10;
329       p++;
330
331       *p = bin_buf[i] & 0x0f;
332       *p += *p < 10 ? 0x30 : 0x61 - 10;
333       p++;
334     }
335
336   *p = '\0';
337   return str_buf;
338 }
339
340
341 // spew a range of bin data as hex
342 void
343 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
344 {
345   if ( buf == 0 )
346     return;
347
348   if ( stream == 0 )
349     stream = stderr;
350
351   static ui32_t row_len = 16;
352   const byte_t* p = buf;
353   const byte_t* end_p = p + dump_len;
354
355   for ( ui32_t line = 0; p < end_p; line++ )
356     {
357       fprintf(stream, "  %06x: ", line);
358       ui32_t i;
359       const byte_t* pp;
360
361       for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
362         fprintf(stream, "%02x ", *pp);
363
364       while ( i++ < row_len )
365         fputs("   ", stream);
366
367       for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
368         fputc((isprint(*pp) ? *pp : '.'), stream);
369
370       fputc('\n', stream);
371       p += row_len;
372     }
373 }
374
375 //
376 const char*
377 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
378 {
379   ui32_t i, j, k;
380
381   if ( str_len < 34 || bin_len != UUID_Length )
382     return 0;
383
384   if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
385     return 0;
386
387   // shift the node id
388   for ( k = 19, i = 12; i > 0; i-- )
389     str_buf[k+i+4] = str_buf[k+i];
390
391   // shift the time (mid+hi+clk)
392   for ( k = 15, j = 3; k > 6; k -= 4, j-- )
393     {
394       for ( i = 4; i > 0; i-- )
395         str_buf[k+i+j] = str_buf[k+i];
396     }
397
398   // add in the hyphens and trainling null
399   for ( i = 8; i < 24; i += 5 )
400     str_buf[i] = '-';
401   
402   str_buf[36] = 0;
403   return str_buf;
404 }
405
406 //
407 void
408 Kumu::GenRandomValue(UUID& ID)
409 {
410   byte_t tmp_buf[UUID_Length];
411   GenRandomUUID(tmp_buf);
412   ID.Set(tmp_buf);
413 }
414
415 //
416 void
417 Kumu::GenRandomUUID(byte_t* buf)
418 {
419   FortunaRNG RNG;
420   RNG.FillRandom(buf, UUID_Length);
421   buf[6] &= 0x0f; // clear bits 4-7
422   buf[6] |= 0x40; // set UUID version
423   buf[8] &= 0x3f; // clear bits 6&7
424   buf[8] |= 0x80; // set bit 7
425 }
426
427 //
428 void
429 Kumu::GenRandomValue(SymmetricKey& ID)
430 {
431   byte_t tmp_buf[SymmetricKey_Length];
432   FortunaRNG RNG;
433   RNG.FillRandom(tmp_buf, SymmetricKey_Length);
434   ID.Set(tmp_buf);
435 }
436
437
438 //------------------------------------------------------------------------------------------
439 // read a ber value from the buffer and compare with test value.
440 // Advances buffer to first character after BER value.
441
442 // read a ber value from the buffer and compare with test value.
443 // Advances buffer to first character after BER value.
444 //
445 bool
446 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
447 {
448   if ( buf == 0 )
449     return false;
450
451   if ( ( **buf & 0x80 ) == 0 )
452     return false;
453
454   ui64_t val = 0;
455   ui8_t ber_size = ( **buf & 0x0f ) + 1;
456
457   if ( ber_size > 9 )
458     return false;
459
460   for ( ui8_t i = 1; i < ber_size; i++ )
461     {
462       if ( (*buf)[i] > 0 )
463         val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
464     }
465
466   *buf += ber_size;
467   return ( val == test_value );
468 }
469
470
471 //
472 bool
473 Kumu::read_BER(const byte_t* buf, ui64_t* val)
474 {
475   ui8_t ber_size, i;
476   
477   if ( buf == 0 || val == 0 )
478     return false;
479
480   if ( ( *buf & 0x80 ) == 0 )
481     return false;
482
483   *val = 0;
484   ber_size = ( *buf & 0x0f ) + 1;
485
486   if ( ber_size > 9 )
487     return false;
488
489   for ( i = 1; i < ber_size; i++ )
490     {
491       if ( buf[i] > 0 )
492         *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
493     }
494
495   return true;
496 }
497
498
499 static const ui64_t ber_masks[9] =
500   { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00), 
501     ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
502     ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
503     ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
504     0
505   };
506
507
508 //
509 bool
510 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
511 {
512   if ( buf == 0 )
513     return false;
514
515   if ( ber_len == 0 )
516     { // calculate default length
517       if ( val < 0x01000000L )
518         ber_len = 4;
519       else if ( val < ui64_C(0x0100000000000000) )
520         ber_len = 8;
521       else
522         ber_len = 9;
523     }
524   else
525     { // sanity check BER length
526       if ( ber_len > 9 )
527         {
528           DefaultLogSink().Error("BER size %lu exceeds maximum size of 9\n", ber_len);
529           return false;
530         }
531       
532       if ( val & ber_masks[ber_len - 1] )
533         {
534           ui64Printer tmp_i(val);
535           DefaultLogSink().Error("BER size %lu too small for value %s\n", tmp_i.c_str());
536           return false;
537         }
538     }
539
540   buf[0] = 0x80 + ( ber_len - 1 );
541
542   for ( ui32_t i = ber_len - 1; i > 0; i-- )
543     {
544       buf[i] = (ui8_t)(val & 0xff);
545       val >>= 8;
546     }
547
548   return true;
549 }
550
551
552 //------------------------------------------------------------------------------------------
553 #ifdef KM_WIN32
554
555 #define TIMESTAMP_TO_SYSTIME(ts, t) \
556   (t)->wYear    = (ts).Year;   /* year */ \
557   (t)->wMonth   = (ts).Month;  /* month of year (1 - 12) */ \
558   (t)->wDay     = (ts).Day;    /* day of month (1 - 31) */ \
559   (t)->wHour    = (ts).Hour;   /* hours (0 - 23) */ \
560   (t)->wMinute  = (ts).Minute; /* minutes (0 - 59) */ \
561   (t)->wSecond  = (ts).Second; /* seconds (0 - 60) */ \
562   (t)->wDayOfWeek = 0; \
563   (t)->wMilliseconds = 0
564
565 #define SYSTIME_TO_TIMESTAMP(t, ts) \
566   (ts).Year   = (t)->wYear;    /* year */ \
567   (ts).Month  = (t)->wMonth;   /* month of year (1 - 12) */ \
568   (ts).Day    = (t)->wDay;     /* day of month (1 - 31) */ \
569   (ts).Hour   = (t)->wHour;    /* hours (0 - 23) */ \
570   (ts).Minute = (t)->wMinute;  /* minutes (0 - 59) */ \
571   (ts).Second = (t)->wSecond;  /* seconds (0 - 60) */
572
573 //
574 Kumu::Timestamp::Timestamp() :
575   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
576 {
577   SYSTEMTIME sys_time;
578   GetSystemTime(&sys_time);
579   SYSTIME_TO_TIMESTAMP(&sys_time, *this);
580 }
581
582 //
583 bool
584 Kumu::Timestamp::operator<(const Timestamp& rhs) const
585 {
586   SYSTEMTIME lhst, rhst;
587   FILETIME lft, rft;
588
589   TIMESTAMP_TO_SYSTIME(*this, &lhst);
590   TIMESTAMP_TO_SYSTIME(rhs, &rhst);
591   SystemTimeToFileTime(&lhst, &lft);
592   SystemTimeToFileTime(&rhst, &rft);
593   return ( CompareFileTime(&lft, &rft) == -1 );
594 }
595
596 inline ui64_t
597 seconds_to_ns100(ui32_t seconds)
598 {
599   return ((ui64_t)seconds * 10000000);
600 }
601
602 //
603 void
604 Kumu::Timestamp::AddDays(i32_t days)
605 {
606   SYSTEMTIME current_st;
607   FILETIME current_ft;
608   ULARGE_INTEGER current_ul;
609
610   if ( days != 0 )
611     {
612       TIMESTAMP_TO_SYSTIME(*this, &current_st);
613       SystemTimeToFileTime(&current_st, &current_ft);
614       memcpy(&current_ul, &current_ft, sizeof(current_ul));
615       current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
616       memcpy(&current_ft, &current_ul, sizeof(current_ft));
617       FileTimeToSystemTime(&current_ft, &current_st);
618       SYSTIME_TO_TIMESTAMP(&current_st, *this);
619     }
620 }
621
622 //
623 void
624 Kumu::Timestamp::AddHours(i32_t hours)
625 {
626   SYSTEMTIME current_st;
627   FILETIME current_ft;
628   ULARGE_INTEGER current_ul;
629
630   if ( hours != 0 )
631     {
632       TIMESTAMP_TO_SYSTIME(*this, &current_st);
633       SystemTimeToFileTime(&current_st, &current_ft);
634       memcpy(&current_ul, &current_ft, sizeof(current_ul));
635       current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
636       memcpy(&current_ft, &current_ul, sizeof(current_ft));
637       FileTimeToSystemTime(&current_ft, &current_st);
638       SYSTIME_TO_TIMESTAMP(&current_st, *this);
639     }
640 }
641
642 #else // KM_WIN32
643
644 #include <time.h>
645
646 #define TIMESTAMP_TO_TM(ts, t) \
647   (t)->tm_year = (ts).Year - 1900;   /* year - 1900 */ \
648   (t)->tm_mon  = (ts).Month - 1;     /* month of year (0 - 11) */ \
649   (t)->tm_mday = (ts).Day;           /* day of month (1 - 31) */ \
650   (t)->tm_hour = (ts).Hour;          /* hours (0 - 23) */ \
651   (t)->tm_min  = (ts).Minute;        /* minutes (0 - 59) */ \
652   (t)->tm_sec  = (ts).Second;        /* seconds (0 - 60) */
653
654 #define TM_TO_TIMESTAMP(t, ts) \
655   (ts).Year   = (t)->tm_year + 1900;    /* year - 1900 */ \
656   (ts).Month  = (t)->tm_mon + 1;     /* month of year (0 - 11) */ \
657   (ts).Day    = (t)->tm_mday;    /* day of month (1 - 31) */ \
658   (ts).Hour   = (t)->tm_hour;    /* hours (0 - 23) */ \
659   (ts).Minute = (t)->tm_min;     /* minutes (0 - 59) */ \
660   (ts).Second = (t)->tm_sec;     /* seconds (0 - 60) */
661
662 //
663 Kumu::Timestamp::Timestamp() :
664   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
665 {
666   time_t t_now = time(0);
667   struct tm*  now = gmtime(&t_now);
668   TM_TO_TIMESTAMP(now, *this);
669 }
670
671 //
672 bool
673 Kumu::Timestamp::operator<(const Timestamp& rhs) const
674 {
675   struct tm lhtm, rhtm;
676   TIMESTAMP_TO_TM(*this, &lhtm);
677   TIMESTAMP_TO_TM(rhs, &rhtm);
678   return ( timegm(&lhtm) < timegm(&rhtm) );
679 }
680
681 //
682 void
683 Kumu::Timestamp::AddDays(i32_t days)
684 {
685   struct tm current;
686
687   if ( days != 0 )
688     {
689       TIMESTAMP_TO_TM(*this, &current);
690       time_t adj_time = timegm(&current);
691       adj_time += 86400 * days;
692       struct tm*  now = gmtime(&adj_time);
693       TM_TO_TIMESTAMP(now, *this);
694     }
695 }
696
697 //
698 void
699 Kumu::Timestamp::AddHours(i32_t hours)
700 {
701   struct tm current;
702
703   if ( hours != 0 )
704     {
705       TIMESTAMP_TO_TM(*this, &current);
706       time_t adj_time = timegm(&current);
707       adj_time += 3600 * hours;
708       struct tm*  now = gmtime(&adj_time);
709       TM_TO_TIMESTAMP(now, *this);
710     }
711 }
712
713 #endif // KM_WIN32
714
715
716 Kumu::Timestamp::Timestamp(const Timestamp& rhs)
717 {
718   Year   = rhs.Year;
719   Month  = rhs.Month;
720   Day    = rhs.Day;
721   Hour   = rhs.Hour;
722   Minute = rhs.Minute;
723   Second = rhs.Second;
724 }
725
726 Kumu::Timestamp::~Timestamp()
727 {
728 }
729
730 //
731 const Kumu::Timestamp&
732 Kumu::Timestamp::operator=(const Timestamp& rhs)
733 {
734   Year   = rhs.Year;
735   Month  = rhs.Month;
736   Day    = rhs.Day;
737   Hour   = rhs.Hour;
738   Minute = rhs.Minute;
739   Second = rhs.Second;
740   return *this;
741 }
742
743 //
744 bool
745 Kumu::Timestamp::operator==(const Timestamp& rhs) const
746 {
747   if ( Year == rhs.Year
748        && Month  == rhs.Month
749        && Day    == rhs.Day
750        && Hour   == rhs.Hour
751        && Minute == rhs.Minute
752        && Second == rhs.Second )
753     return true;
754
755   return false;
756 }
757
758 //
759 bool
760 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
761 {
762   if ( Year != rhs.Year
763        || Month  != rhs.Month
764        || Day    != rhs.Day
765        || Hour   != rhs.Hour
766        || Minute != rhs.Minute
767        || Second != rhs.Second )
768     return true;
769
770   return false;
771 }
772
773 // 
774 const char*
775 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
776 {
777   if ( buf_len < ( DateTimeLen + 1 ) )
778     return 0;
779
780   // 2004-05-01T13:20:00-00:00
781   snprintf(str_buf, buf_len,
782            "%04hu-%02hu-%02huT%02hu:%02hu:%02hu-00:00",
783            Year, Month, Day, Hour, Minute, Second);
784   
785   return str_buf;
786 }
787
788 //
789 bool
790 Kumu::Timestamp::DecodeString(const char* datestr)
791 {
792   if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
793        || datestr[4] != '-'
794        || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
795        || datestr[7] != '-'
796        || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) )
797        || datestr[10] != 'T'
798        || ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
799        || datestr[13] != ':'
800        || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) )
801        || datestr[16] != ':'
802        || ! ( isdigit(datestr[17]) && isdigit(datestr[18]) )
803        || ! ( datestr[19] == '-' || datestr[19] == '+' )
804        || ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
805        || datestr[22] != ':'
806        || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
807     return false;
808
809   // TODO -- test this!
810   Year = atoi(datestr);
811   Month = atoi(datestr + 5);
812   Day = atoi(datestr + 8);
813   Hour = atoi(datestr + 11);
814   Minute = atoi(datestr + 14);
815   Second = atoi(datestr + 17);
816
817   ui32_t TZ_hh = atoi(datestr + 20);
818   ui32_t TZ_mm = atoi(datestr + 23);
819
820   if ( TZ_mm != 0 )
821     DefaultLogSink().Error("Ignoring sub-hours timezone offset: %lu\n", TZ_mm);
822  
823   if ( TZ_hh > 12 )
824     DefaultLogSink().Error("Ignoring large timezone offset: %s\n", (datestr+19));
825   else 
826     AddHours(TZ_hh);
827
828   return true;
829 }
830
831 //
832 bool
833 Kumu::Timestamp::HasValue() const
834 {
835   if ( Year || Month || Day || Hour || Minute || Second )
836     return true;
837
838   return false;
839 }
840
841 //
842 bool
843 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
844 {
845   assert(Reader);
846   if ( ! Reader->ReadUi16BE(&Year) ) return false;      
847   if ( ! Reader->ReadRaw(&Month, 6) ) return false;
848   return true;
849 }
850
851 //
852 bool
853 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
854 {
855   assert(Writer);
856   if ( ! Writer->WriteUi16BE(Year) ) return false;      
857   if ( ! Writer->WriteRaw(&Month, 6) ) return false;
858   return true;
859 }
860
861 #if 0
862 //
863 bool
864 Kumu::UnarchiveString(MemIOReader* Reader, std::string&)
865 {
866   assert(Reader);
867   ui32_t str_length;
868   if ( ! Reader->ReadUi32BE(&str_length) ) return false;
869   assign((const char*)Reader->CurrentData(), str_length);
870   if ( ! Reader->SkipOffset(str_length) ) return false;
871   return true;
872 }
873
874 //
875 bool
876 Kumu::String::Archive(MemIOWriter* Writer) const
877 {
878   assert(Writer);
879   if ( ! Writer->WriteUi32BE(length()) ) return false;
880   if ( ! Writer->WriteRaw((const byte_t*)c_str(), length()) ) return false;
881
882   return true;
883 }
884 #endif
885
886 //------------------------------------------------------------------------------------------
887
888 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
889   : m_p(0), m_capacity(0), m_size(0)
890 {
891   m_p = Buf->Data();
892   m_capacity = Buf->Capacity();
893   assert(m_p); assert(m_capacity);
894 }
895
896 bool
897 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
898 {
899   if ( ( m_size + ber_len ) > m_capacity )
900     return false;
901
902   if ( ! write_BER(m_p + m_size, i, ber_len) )
903     return false;
904
905   m_size += ber_len;
906   return true;
907 }
908
909
910 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
911   : m_p(0), m_capacity(0), m_size(0)
912 {
913   m_p = Buf->RoData();
914   m_capacity = Buf->Capacity();
915   assert(m_p); assert(m_capacity);
916 }
917
918 bool
919 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
920 {
921   if ( i == 0 || ber_len == 0 ) return false;
922
923   if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
924     return false;
925
926   if ( ( m_size + *ber_len ) > m_capacity )
927     return false;
928
929   if ( ! read_BER(m_p + m_size, i) )
930     return false;
931
932   m_size += *ber_len;
933   return true;
934 }
935
936 //------------------------------------------------------------------------------------------
937
938 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
939
940 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
941 {
942   Capacity(cap);
943 }
944
945 Kumu::ByteString::~ByteString()
946 {
947   if ( m_Data != 0 )
948     free(m_Data);
949 }
950
951
952 // copy the given data into the ByteString, set Length value.
953 // Returns error if the ByteString is too small.
954 Kumu::Result_t
955 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
956 {
957   if ( m_Capacity < buf_len )
958     return RESULT_ALLOC;
959
960   memcpy(m_Data, buf, buf_len);
961   m_Length = buf_len;
962   return RESULT_OK;
963 }
964
965
966 // Sets the size of the internally allocate buffer.
967 // Resets content length to zero.
968 Kumu::Result_t
969 Kumu::ByteString::Capacity(ui32_t cap_size)
970 {
971   if ( m_Capacity < cap_size )
972     {
973       if ( m_Data != 0 )
974         free(m_Data);
975                 
976       m_Data = (byte_t*)malloc(cap_size);
977                 
978       if ( m_Data == 0 )
979         return RESULT_ALLOC;
980                 
981       m_Capacity = cap_size;
982       m_Length = 0;
983     }
984         
985   return RESULT_OK;
986 }
987
988 //
989 Kumu::Result_t
990 Kumu::ByteString::Append(const ByteString& Buf)
991 {
992   Result_t result = RESULT_OK;
993   ui32_t diff = m_Capacity - m_Length;
994
995   if ( diff < Buf.Length() )
996     result = Capacity(m_Capacity + Buf.Length());
997
998   if ( KM_SUCCESS(result) )
999     {
1000       memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1001       m_Length += Buf.Length();
1002     }
1003
1004   return result;
1005 }
1006
1007 //
1008 Kumu::Result_t
1009 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1010 {
1011   Result_t result = RESULT_OK;
1012   ui32_t diff = m_Capacity - m_Length;
1013
1014   if ( diff < buf_len )
1015     result = Capacity(m_Capacity + buf_len);
1016
1017   if ( KM_SUCCESS(result) )
1018     {
1019       memcpy(m_Data + m_Length, buf, buf_len);
1020       m_Length += buf_len;
1021     }
1022
1023   return result;
1024 }
1025
1026
1027 //
1028 // end KM_util.cpp
1029 //