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