2 Copyright (c) 2005-2009, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
29 \brief Utility functions
35 #include <KM_fileio.h>
43 #define CONFIG_RANDOM_UUID
48 return PACKAGE_VERSION;
52 //------------------------------------------------------------------------------------------
59 Kumu::Result_t* result;
62 const ui32_t MapMax = 1024;
63 const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t));
64 static bool s_MapInit = false;
65 static struct map_entry_t s_ResultMap[MapSize];
69 Kumu::Result_t::Find(int v)
74 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
76 if ( s_ResultMap[i].rcode == v )
77 return *s_ResultMap[i].result;
80 return RESULT_UNKNOWN;
85 Kumu::Result_t::Delete(int v)
87 if ( v >= RESULT_NOTAFILE.Value() )
89 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
93 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
95 if ( s_ResultMap[i].rcode == v )
97 s_ResultMap[i].rcode = 0;
98 s_ResultMap[i++].result = 0;
100 for ( ; s_ResultMap[i].result != 0 && i < MapMax; i++ )
101 s_ResultMap[i-1] = s_ResultMap[i];
112 Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l)
115 assert(value < (int)MapMax);
123 s_ResultMap[0].rcode = v;
124 s_ResultMap[0].result = this;
125 s_ResultMap[1].rcode = 0;
126 s_ResultMap[1].result = 0;
131 while ( s_ResultMap[i].result != 0 && i < MapMax )
133 if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
139 assert(i+2 < MapMax);
141 s_ResultMap[i].rcode = v;
142 s_ResultMap[i].result = this;
143 s_ResultMap[i+1].rcode = 0;
144 s_ResultMap[i+1].result = 0;
148 Kumu::Result_t::~Result_t() {}
151 //------------------------------------------------------------------------------------------
154 static int s_DTraceSequence = 0;
156 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
157 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
159 m_Sequence = s_DTraceSequence++;
160 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
163 Kumu::DTrace_t::~DTrace_t()
166 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
168 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
171 //------------------------------------------------------------------------------------------
174 const char fill = '=';
175 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
177 const byte_t decode_map[] =
178 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
179 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
180 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
182 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
183 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
184 52, 53, 54, 55, 56, 57, 58, 59,
185 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
186 0xff, 0, 1, 2, 3, 4, 5, 6,
187 7, 8, 9, 10, 11, 12, 13, 14,
188 15, 16, 17, 18, 19, 20, 21, 22,
189 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
190 0xff, 26, 27, 28, 29, 30, 31, 32,
191 33, 34, 35, 36, 37, 38, 39, 40,
192 41, 42, 43, 44, 45, 46, 47, 48,
193 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
198 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
213 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
214 // if the binary buffer was large enough to hold the result. If the output buffer
215 // is too small or any of the pointer arguments are NULL, the subroutine will
219 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
222 ui32_t i, block_len, diff;
224 if ( buf == 0 || strbuf == 0 )
227 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
232 while ( block_len % 3 )
235 for ( i = 0; i < block_len; i += 3 )
237 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
238 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
239 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
240 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
250 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
254 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
255 strbuf[out_char++] = fill;
257 else if ( diff == 2 )
259 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
260 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
263 strbuf[out_char++] = fill;
266 strbuf[out_char] = 0;
273 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
274 // the binary buffer was large enough to hold the result. The output parameter
275 // 'char_count' will contain the length of the converted string. If the output
276 // buffer is too small or any of the pointer arguments are NULL, the subroutine
277 // will return -1 and set 'char_count' to the required buffer size. No data will
278 // be written to 'buf' if the subroutine fails.
281 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
283 register byte_t c = 0, d = 0;
284 register ui32_t phase = 0, i = 0;
286 if ( str == 0 || buf == 0 || char_count == 0 )
289 while ( *str != 0 && i < buf_len )
291 c = decode_map[(int)*str++];
292 if ( c == 0xff ) continue;
293 if ( c == 0xfe ) break;
302 buf[i - 1] |= c >> 4;
307 buf[i++] = ( d << 4 ) | ( c >> 2 );
312 buf[i++] = ( d << 6 ) | c;
322 //------------------------------------------------------------------------------------------
324 // convert utf-8 hext string to bin
326 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
330 KM_TEST_NULL_L(conv_size);
334 if ( str[0] == 0 ) // nothing to convert
337 for ( int j = 0; str[j]; j++ )
339 if ( isxdigit(str[j]) )
343 if ( *conv_size & 0x01 ) (*conv_size)++;
346 if ( *conv_size > buf_len )// maximum possible data size
351 int phase = 0; // track high/low nybble
353 // for each character, fill in the high nybble then the low
354 for ( int i = 0; str[i]; i++ )
356 if ( ! isxdigit(str[i]) )
359 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
363 buf[*conv_size] = val << 4;
368 buf[*conv_size] |= val;
377 #ifdef CONFIG_RANDOM_UUID
379 // convert a memory region to a NULL-terminated hexadecimal string
382 bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
386 || ((bin_len * 2) + 1) > str_len )
390 Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
391 Kumu::FortunaRNG RNG;
392 RNG.FillRandom(rand_buf, bin_len);
394 for ( ui32_t i = 0; i < bin_len; i++ )
396 *p = (bin_buf[i] >> 4) & 0x0f;
397 *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
400 *p = bin_buf[i] & 0x0f;
401 *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
410 // convert a memory region to a NULL-terminated hexadecimal string
413 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
417 || ((bin_len * 2) + 1) > str_len )
420 #ifdef CONFIG_RANDOM_UUID
421 const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
422 if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
423 return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
428 for ( ui32_t i = 0; i < bin_len; i++ )
430 *p = (bin_buf[i] >> 4) & 0x0f;
431 *p += *p < 10 ? 0x30 : 0x61 - 10;
434 *p = bin_buf[i] & 0x0f;
435 *p += *p < 10 ? 0x30 : 0x61 - 10;
444 // spew a range of bin data as hex
446 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
454 static ui32_t row_len = 16;
455 const byte_t* p = buf;
456 const byte_t* end_p = p + dump_len;
458 for ( ui32_t line = 0; p < end_p; line++ )
460 fprintf(stream, " %06x: ", line);
464 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
465 fprintf(stream, "%02x ", *pp);
467 while ( i++ < row_len )
470 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
471 fputc((isprint(*pp) ? *pp : '.'), stream);
480 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
484 if ( str_len < 34 || bin_len != UUID_Length )
487 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
491 for ( k = 19, i = 12; i > 0; i-- )
492 str_buf[k+i+4] = str_buf[k+i];
494 // shift the time (mid+hi+clk)
495 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
497 for ( i = 4; i > 0; i-- )
498 str_buf[k+i+j] = str_buf[k+i];
501 // add in the hyphens and trainling null
502 for ( i = 8; i < 24; i += 5 )
511 Kumu::GenRandomValue(UUID& ID)
513 byte_t tmp_buf[UUID_Length];
514 GenRandomUUID(tmp_buf);
520 Kumu::GenRandomUUID(byte_t* buf)
523 RNG.FillRandom(buf, UUID_Length);
524 buf[6] &= 0x0f; // clear bits 4-7
525 buf[6] |= 0x40; // set UUID version
526 buf[8] &= 0x3f; // clear bits 6&7
527 buf[8] |= 0x80; // set bit 7
532 Kumu::GenRandomValue(SymmetricKey& Key)
534 byte_t tmp_buf[SymmetricKey_Length];
536 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
541 //------------------------------------------------------------------------------------------
542 // read a ber value from the buffer and compare with test value.
543 // Advances buffer to first character after BER value.
545 // read a ber value from the buffer and compare with test value.
546 // Advances buffer to first character after BER value.
549 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
554 if ( ( **buf & 0x80 ) == 0 )
558 ui8_t ber_size = ( **buf & 0x0f ) + 1;
563 for ( ui8_t i = 1; i < ber_size; i++ )
566 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
570 return ( val == test_value );
576 Kumu::read_BER(const byte_t* buf, ui64_t* val)
580 if ( buf == 0 || val == 0 )
583 if ( ( *buf & 0x80 ) == 0 )
587 ber_size = ( *buf & 0x0f ) + 1;
592 for ( i = 1; i < ber_size; i++ )
595 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
602 static const ui64_t ber_masks[9] =
603 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
604 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
605 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
606 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
613 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
619 { // calculate default length
620 if ( val < 0x01000000L )
622 else if ( val < ui64_C(0x0100000000000000) )
628 { // sanity check BER length
631 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
635 if ( val & ber_masks[ber_len - 1] )
637 ui64Printer tmp_i(val);
638 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
643 buf[0] = 0x80 + ( ber_len - 1 );
645 for ( ui32_t i = ber_len - 1; i > 0; i-- )
647 buf[i] = (ui8_t)(val & 0xff);
655 //------------------------------------------------------------------------------------------
658 #define TIMESTAMP_TO_SYSTIME(ts, t) \
659 (t)->wYear = (ts).Year; /* year */ \
660 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
661 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
662 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
663 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
664 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
665 (t)->wDayOfWeek = 0; \
666 (t)->wMilliseconds = 0
668 #define SYSTIME_TO_TIMESTAMP(t, ts) \
669 (ts).Year = (t)->wYear; /* year */ \
670 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
671 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
672 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
673 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
674 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
677 Kumu::Timestamp::Timestamp() :
678 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
681 GetSystemTime(&sys_time);
682 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
687 Kumu::Timestamp::operator<(const Timestamp& rhs) const
689 SYSTEMTIME lhst, rhst;
692 TIMESTAMP_TO_SYSTIME(*this, &lhst);
693 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
694 SystemTimeToFileTime(&lhst, &lft);
695 SystemTimeToFileTime(&rhst, &rft);
696 return ( CompareFileTime(&lft, &rft) == -1 );
701 Kumu::Timestamp::operator>(const Timestamp& rhs) const
703 SYSTEMTIME lhst, rhst;
706 TIMESTAMP_TO_SYSTIME(*this, &lhst);
707 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
708 SystemTimeToFileTime(&lhst, &lft);
709 SystemTimeToFileTime(&rhst, &rft);
710 return ( CompareFileTime(&lft, &rft) == 1 );
714 seconds_to_ns100(ui32_t seconds)
716 return ((ui64_t)seconds * 10000000);
721 Kumu::Timestamp::AddDays(i32_t days)
723 SYSTEMTIME current_st;
725 ULARGE_INTEGER current_ul;
729 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
730 SystemTimeToFileTime(¤t_st, ¤t_ft);
731 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
732 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
733 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
734 FileTimeToSystemTime(¤t_ft, ¤t_st);
735 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
741 Kumu::Timestamp::AddHours(i32_t hours)
743 SYSTEMTIME current_st;
745 ULARGE_INTEGER current_ul;
749 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
750 SystemTimeToFileTime(¤t_st, ¤t_ft);
751 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
752 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
753 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
754 FileTimeToSystemTime(¤t_ft, ¤t_st);
755 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
763 #define TIMESTAMP_TO_CALTIME(ts, ct) \
764 (ct)->date.year = (ts).Year; /* year */ \
765 (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \
766 (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \
767 (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \
768 (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \
769 (ct)->second = (ts).Second; /* seconds (0 - 60) */ \
772 #define CALTIME_TO_TIMESTAMP(ct, ts) \
773 assert((ct)->offset == 0); \
774 (ts).Year = (ct)->date.year; /* year */ \
775 (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \
776 (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \
777 (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \
778 (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \
779 (ts).Second = (ct)->second; /* seconds (0 - 60) */
783 Kumu::Timestamp::Timestamp() :
784 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
787 Kumu::TAI::caltime ct;
790 CALTIME_TO_TIMESTAMP(&ct, *this)
795 Kumu::Timestamp::operator<(const Timestamp& rhs) const
797 Kumu::TAI::caltime lh_ct, rh_ct;
798 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
799 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
801 Kumu::TAI::tai lh_tai, rh_tai;
805 return ( lh_tai.x < rh_tai.x );
810 Kumu::Timestamp::operator>(const Timestamp& rhs) const
812 Kumu::TAI::caltime lh_ct, rh_ct;
813 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
814 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
816 Kumu::TAI::tai lh_tai, rh_tai;
820 return ( lh_tai.x > rh_tai.x );
825 Kumu::Timestamp::AddDays(i32_t days)
827 Kumu::TAI::caltime ct;
832 TIMESTAMP_TO_CALTIME(*this, &ct)
836 CALTIME_TO_TIMESTAMP(&ct, *this)
842 Kumu::Timestamp::AddHours(i32_t hours)
844 Kumu::TAI::caltime ct;
849 TIMESTAMP_TO_CALTIME(*this, &ct)
853 CALTIME_TO_TIMESTAMP(&ct, *this)
860 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
870 Kumu::Timestamp::~Timestamp()
875 const Kumu::Timestamp&
876 Kumu::Timestamp::operator=(const Timestamp& rhs)
889 Kumu::Timestamp::operator==(const Timestamp& rhs) const
891 if ( Year == rhs.Year
892 && Month == rhs.Month
895 && Minute == rhs.Minute
896 && Second == rhs.Second )
904 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
906 if ( Year != rhs.Year
907 || Month != rhs.Month
910 || Minute != rhs.Minute
911 || Second != rhs.Second )
919 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
921 if ( buf_len < ( DateTimeLen + 1 ) )
924 // 2004-05-01T13:20:00-00:00
925 snprintf(str_buf, buf_len,
926 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu+00:00",
927 Year, Month, Day, Hour, Minute, Second);
934 Kumu::Timestamp::DecodeString(const char* datestr)
938 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
940 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
942 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
945 ui32_t char_count = 10;
946 TmpStamp.Year = atoi(datestr);
947 TmpStamp.Month = atoi(datestr + 5);
948 TmpStamp.Day = atoi(datestr + 8);
949 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
951 if ( datestr[10] == 'T' )
953 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
954 || datestr[13] != ':'
955 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
959 TmpStamp.Hour = atoi(datestr + 11);
960 TmpStamp.Minute = atoi(datestr + 14);
962 if ( datestr[16] == ':' )
964 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
968 TmpStamp.Second = atoi(datestr + 17);
971 if ( datestr[19] == '.' )
973 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
976 // we don't carry the ms value
980 if ( datestr[19] == '-' || datestr[19] == '+' )
982 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
983 || datestr[22] != ':'
984 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
988 ui32_t TZ_hh = atoi(datestr + 20);
989 ui32_t TZ_mm = atoi(datestr + 23);
992 Kumu::DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
998 AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
1002 if ( datestr[char_count] != 0 )
1004 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
1005 datestr, char_count);
1012 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
1013 if ( SystemTimeToFileTime(&st, &ft) == 0 )
1015 SYSTIME_TO_TIMESTAMP(&st, *this);
1018 Kumu::TAI::caltime ct;
1019 TIMESTAMP_TO_CALTIME(TmpStamp, &ct);
1020 t = ct; // back and forth to tai to normalize offset
1022 CALTIME_TO_TIMESTAMP(&ct, *this)
1030 Kumu::Timestamp::HasValue() const
1032 if ( Year || Month || Day || Hour || Minute || Second )
1040 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
1043 if ( ! Reader->ReadUi16BE(&Year) ) return false;
1044 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
1050 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1053 if ( ! Writer->WriteUi16BE(Year) ) return false;
1054 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1058 //------------------------------------------------------------------------------------------
1060 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1061 : m_p(0), m_capacity(0), m_size(0)
1064 m_capacity = Buf->Capacity();
1065 assert(m_p); assert(m_capacity);
1069 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1071 if ( ( m_size + ber_len ) > m_capacity )
1074 if ( ! write_BER(m_p + m_size, i, ber_len) )
1082 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1083 : m_p(0), m_capacity(0), m_size(0)
1085 m_p = Buf->RoData();
1086 m_capacity = Buf->Length();
1087 assert(m_p); assert(m_capacity);
1091 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1093 if ( i == 0 || ber_len == 0 ) return false;
1095 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1098 if ( ( m_size + *ber_len ) > m_capacity )
1101 if ( ! read_BER(m_p + m_size, i) )
1108 //------------------------------------------------------------------------------------------
1110 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1112 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1117 Kumu::ByteString::~ByteString()
1124 // copy the given data into the ByteString, set Length value.
1125 // Returns error if the ByteString is too small.
1127 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1129 if ( m_Capacity < buf_len )
1130 return RESULT_ALLOC;
1132 memcpy(m_Data, buf, buf_len);
1138 // copy the given data into the ByteString, set Length value.
1139 // Returns error if the ByteString is too small.
1141 Kumu::ByteString::Set(const ByteString& Buf)
1143 if ( m_Capacity < Buf.m_Capacity )
1144 return RESULT_ALLOC;
1146 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1147 m_Length = Buf.m_Length;
1152 // Sets the size of the internally allocate buffer.
1154 Kumu::ByteString::Capacity(ui32_t cap_size)
1156 if ( m_Capacity >= cap_size )
1159 byte_t* tmp_data = 0;
1168 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1169 return RESULT_ALLOC;
1171 if ( tmp_data != 0 )
1173 assert(m_Length > 0);
1174 memcpy(m_Data, tmp_data, m_Length);
1178 m_Capacity = cap_size;
1184 Kumu::ByteString::Append(const ByteString& Buf)
1186 Result_t result = RESULT_OK;
1187 ui32_t diff = m_Capacity - m_Length;
1189 if ( diff < Buf.Length() )
1190 result = Capacity(m_Capacity + Buf.Length());
1192 if ( KM_SUCCESS(result) )
1194 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1195 m_Length += Buf.Length();
1203 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1205 Result_t result = RESULT_OK;
1206 ui32_t diff = m_Capacity - m_Length;
1208 if ( diff < buf_len )
1209 result = Capacity(m_Capacity + buf_len);
1211 if ( KM_SUCCESS(result) )
1213 memcpy(m_Data + m_Length, buf, buf_len);
1214 m_Length += buf_len;