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>
46 return PACKAGE_VERSION;
50 //------------------------------------------------------------------------------------------
57 Kumu::Result_t* result;
60 const ui32_t MapMax = 1024;
61 const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t));
62 static bool s_MapInit = false;
63 static struct map_entry_t s_ResultMap[MapSize];
67 Kumu::Result_t::Find(int v)
72 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
74 if ( s_ResultMap[i].rcode == v )
75 return *s_ResultMap[i].result;
78 return RESULT_UNKNOWN;
83 Kumu::Result_t::Delete(int v)
85 if ( v >= RESULT_NOTAFILE.Value() )
87 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
91 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
93 if ( s_ResultMap[i].rcode == v )
95 s_ResultMap[i].rcode = 0;
96 s_ResultMap[i++].result = 0;
98 for ( ; s_ResultMap[i].result != 0 && i < MapMax; i++ )
99 s_ResultMap[i-1] = s_ResultMap[i];
110 Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l)
113 assert(value < (int)MapMax);
121 s_ResultMap[0].rcode = v;
122 s_ResultMap[0].result = this;
123 s_ResultMap[1].rcode = 0;
124 s_ResultMap[1].result = 0;
129 while ( s_ResultMap[i].result != 0 && i < MapMax )
131 if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
137 assert(i+2 < MapMax);
139 s_ResultMap[i].rcode = v;
140 s_ResultMap[i].result = this;
141 s_ResultMap[i+1].rcode = 0;
142 s_ResultMap[i+1].result = 0;
146 Kumu::Result_t::~Result_t() {}
149 //------------------------------------------------------------------------------------------
152 static int s_DTraceSequence = 0;
154 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
155 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
157 m_Sequence = s_DTraceSequence++;
158 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
161 Kumu::DTrace_t::~DTrace_t()
164 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
166 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
169 //------------------------------------------------------------------------------------------
172 const char fill = '=';
173 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
175 const byte_t decode_map[] =
176 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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, 62, 0xff, 0xff, 0xff, 63,
182 52, 53, 54, 55, 56, 57, 58, 59,
183 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
184 0xff, 0, 1, 2, 3, 4, 5, 6,
185 7, 8, 9, 10, 11, 12, 13, 14,
186 15, 16, 17, 18, 19, 20, 21, 22,
187 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
188 0xff, 26, 27, 28, 29, 30, 31, 32,
189 33, 34, 35, 36, 37, 38, 39, 40,
190 41, 42, 43, 44, 45, 46, 47, 48,
191 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
192 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
193 0xff, 0xff, 0xff, 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
211 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
212 // if the binary buffer was large enough to hold the result. If the output buffer
213 // is too small or any of the pointer arguments are NULL, the subroutine will
217 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
220 ui32_t i, block_len, diff;
222 if ( buf == 0 || strbuf == 0 )
225 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
230 while ( block_len % 3 )
233 for ( i = 0; i < block_len; i += 3 )
235 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
236 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
237 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
238 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
248 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
252 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
253 strbuf[out_char++] = fill;
255 else if ( diff == 2 )
257 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
258 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
261 strbuf[out_char++] = fill;
264 strbuf[out_char] = 0;
271 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
272 // the binary buffer was large enough to hold the result. The output parameter
273 // 'char_count' will contain the length of the converted string. If the output
274 // buffer is too small or any of the pointer arguments are NULL, the subroutine
275 // will return -1 and set 'char_count' to the required buffer size. No data will
276 // be written to 'buf' if the subroutine fails.
279 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
281 register byte_t c = 0, d = 0;
282 register ui32_t phase = 0, i = 0;
284 if ( str == 0 || buf == 0 || char_count == 0 )
287 while ( *str != 0 && i < buf_len )
289 c = decode_map[(int)*str++];
290 if ( c == 0xff ) continue;
291 if ( c == 0xfe ) break;
300 buf[i - 1] |= c >> 4;
305 buf[i++] = ( d << 4 ) | ( c >> 2 );
310 buf[i++] = ( d << 6 ) | c;
320 //------------------------------------------------------------------------------------------
322 // convert utf-8 hext string to bin
324 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
328 KM_TEST_NULL_L(conv_size);
332 if ( str[0] == 0 ) // nothing to convert
335 for ( int j = 0; str[j]; j++ )
337 if ( isxdigit(str[j]) )
341 if ( *conv_size & 0x01 ) (*conv_size)++;
344 if ( *conv_size > buf_len )// maximum possible data size
349 int phase = 0; // track high/low nybble
351 // for each character, fill in the high nybble then the low
352 for ( int i = 0; str[i]; i++ )
354 if ( ! isxdigit(str[i]) )
357 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
361 buf[*conv_size] = val << 4;
366 buf[*conv_size] |= val;
375 #ifdef CONFIG_RANDOM_UUID
377 // convert a memory region to a NULL-terminated hexadecimal string
380 bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
384 || ((bin_len * 2) + 1) > str_len )
388 Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
389 Kumu::FortunaRNG RNG;
390 RNG.FillRandom(rand_buf, bin_len);
392 for ( ui32_t i = 0; i < bin_len; i++ )
394 *p = (bin_buf[i] >> 4) & 0x0f;
395 *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
398 *p = bin_buf[i] & 0x0f;
399 *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
408 // convert a memory region to a NULL-terminated hexadecimal string
411 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
415 || ((bin_len * 2) + 1) > str_len )
418 #ifdef CONFIG_RANDOM_UUID
419 const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
420 if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
421 return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
426 for ( ui32_t i = 0; i < bin_len; i++ )
428 *p = (bin_buf[i] >> 4) & 0x0f;
429 *p += *p < 10 ? 0x30 : 0x61 - 10;
432 *p = bin_buf[i] & 0x0f;
433 *p += *p < 10 ? 0x30 : 0x61 - 10;
442 // spew a range of bin data as hex
444 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
452 static ui32_t row_len = 16;
453 const byte_t* p = buf;
454 const byte_t* end_p = p + dump_len;
456 for ( ui32_t line = 0; p < end_p; line++ )
458 fprintf(stream, " %06x: ", line);
462 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
463 fprintf(stream, "%02x ", *pp);
465 while ( i++ < row_len )
468 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
469 fputc((isprint(*pp) ? *pp : '.'), stream);
478 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
482 if ( str_len < 34 || bin_len != UUID_Length )
485 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
489 for ( k = 19, i = 12; i > 0; i-- )
490 str_buf[k+i+4] = str_buf[k+i];
492 // shift the time (mid+hi+clk)
493 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
495 for ( i = 4; i > 0; i-- )
496 str_buf[k+i+j] = str_buf[k+i];
499 // add in the hyphens and trainling null
500 for ( i = 8; i < 24; i += 5 )
509 Kumu::GenRandomValue(UUID& ID)
511 byte_t tmp_buf[UUID_Length];
512 GenRandomUUID(tmp_buf);
518 Kumu::GenRandomUUID(byte_t* buf)
521 RNG.FillRandom(buf, UUID_Length);
522 buf[6] &= 0x0f; // clear bits 4-7
523 buf[6] |= 0x40; // set UUID version
524 buf[8] &= 0x3f; // clear bits 6&7
525 buf[8] |= 0x80; // set bit 7
530 Kumu::GenRandomValue(SymmetricKey& Key)
532 byte_t tmp_buf[SymmetricKey_Length];
534 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
539 //------------------------------------------------------------------------------------------
540 // read a ber value from the buffer and compare with test value.
541 // Advances buffer to first character after BER value.
543 // read a ber value from the buffer and compare with test value.
544 // Advances buffer to first character after BER value.
547 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
552 if ( ( **buf & 0x80 ) == 0 )
556 ui8_t ber_size = ( **buf & 0x0f ) + 1;
561 for ( ui8_t i = 1; i < ber_size; i++ )
564 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
568 return ( val == test_value );
574 Kumu::read_BER(const byte_t* buf, ui64_t* val)
578 if ( buf == 0 || val == 0 )
581 if ( ( *buf & 0x80 ) == 0 )
585 ber_size = ( *buf & 0x0f ) + 1;
590 for ( i = 1; i < ber_size; i++ )
593 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
600 static const ui64_t ber_masks[9] =
601 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
602 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
603 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
604 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
611 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
617 { // calculate default length
618 if ( val < 0x01000000L )
620 else if ( val < ui64_C(0x0100000000000000) )
626 { // sanity check BER length
629 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
633 if ( val & ber_masks[ber_len - 1] )
635 ui64Printer tmp_i(val);
636 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
641 buf[0] = 0x80 + ( ber_len - 1 );
643 for ( ui32_t i = ber_len - 1; i > 0; i-- )
645 buf[i] = (ui8_t)(val & 0xff);
653 //------------------------------------------------------------------------------------------
656 #define TIMESTAMP_TO_SYSTIME(ts, t) \
657 (t)->wYear = (ts).Year; /* year */ \
658 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
659 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
660 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
661 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
662 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
663 (t)->wDayOfWeek = 0; \
664 (t)->wMilliseconds = 0
666 #define SYSTIME_TO_TIMESTAMP(t, ts) \
667 (ts).Year = (t)->wYear; /* year */ \
668 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
669 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
670 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
671 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
672 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
675 Kumu::Timestamp::Timestamp() :
676 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
679 GetSystemTime(&sys_time);
680 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
685 Kumu::Timestamp::operator<(const Timestamp& rhs) const
687 SYSTEMTIME lhst, rhst;
690 TIMESTAMP_TO_SYSTIME(*this, &lhst);
691 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
692 SystemTimeToFileTime(&lhst, &lft);
693 SystemTimeToFileTime(&rhst, &rft);
694 return ( CompareFileTime(&lft, &rft) == -1 );
699 Kumu::Timestamp::operator>(const Timestamp& rhs) const
701 SYSTEMTIME lhst, rhst;
704 TIMESTAMP_TO_SYSTIME(*this, &lhst);
705 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
706 SystemTimeToFileTime(&lhst, &lft);
707 SystemTimeToFileTime(&rhst, &rft);
708 return ( CompareFileTime(&lft, &rft) == 1 );
712 seconds_to_ns100(ui32_t seconds)
714 return ((ui64_t)seconds * 10000000);
719 Kumu::Timestamp::AddDays(i32_t days)
721 SYSTEMTIME current_st;
723 ULARGE_INTEGER current_ul;
727 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
728 SystemTimeToFileTime(¤t_st, ¤t_ft);
729 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
730 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
731 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
732 FileTimeToSystemTime(¤t_ft, ¤t_st);
733 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
739 Kumu::Timestamp::AddHours(i32_t hours)
741 SYSTEMTIME current_st;
743 ULARGE_INTEGER current_ul;
747 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
748 SystemTimeToFileTime(¤t_st, ¤t_ft);
749 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
750 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
751 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
752 FileTimeToSystemTime(¤t_ft, ¤t_st);
753 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
761 #define TIMESTAMP_TO_CALTIME(ts, ct) \
762 (ct)->date.year = (ts).Year; /* year */ \
763 (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \
764 (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \
765 (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \
766 (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \
767 (ct)->second = (ts).Second; /* seconds (0 - 60) */ \
770 #define CALTIME_TO_TIMESTAMP(ct, ts) \
771 assert((ct)->offset == 0); \
772 (ts).Year = (ct)->date.year; /* year */ \
773 (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \
774 (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \
775 (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \
776 (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \
777 (ts).Second = (ct)->second; /* seconds (0 - 60) */
781 Kumu::Timestamp::Timestamp() :
782 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
785 Kumu::TAI::caltime ct;
788 CALTIME_TO_TIMESTAMP(&ct, *this)
793 Kumu::Timestamp::operator<(const Timestamp& rhs) const
795 Kumu::TAI::caltime lh_ct, rh_ct;
796 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
797 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
799 Kumu::TAI::tai lh_tai, rh_tai;
803 return ( lh_tai.x < rh_tai.x );
808 Kumu::Timestamp::operator>(const Timestamp& rhs) const
810 Kumu::TAI::caltime lh_ct, rh_ct;
811 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
812 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
814 Kumu::TAI::tai lh_tai, rh_tai;
818 return ( lh_tai.x > rh_tai.x );
823 Kumu::Timestamp::AddDays(i32_t days)
825 Kumu::TAI::caltime ct;
830 TIMESTAMP_TO_CALTIME(*this, &ct)
834 CALTIME_TO_TIMESTAMP(&ct, *this)
840 Kumu::Timestamp::AddHours(i32_t hours)
842 Kumu::TAI::caltime ct;
847 TIMESTAMP_TO_CALTIME(*this, &ct)
851 CALTIME_TO_TIMESTAMP(&ct, *this)
858 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
868 Kumu::Timestamp::~Timestamp()
873 const Kumu::Timestamp&
874 Kumu::Timestamp::operator=(const Timestamp& rhs)
887 Kumu::Timestamp::operator==(const Timestamp& rhs) const
889 if ( Year == rhs.Year
890 && Month == rhs.Month
893 && Minute == rhs.Minute
894 && Second == rhs.Second )
902 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
904 if ( Year != rhs.Year
905 || Month != rhs.Month
908 || Minute != rhs.Minute
909 || Second != rhs.Second )
917 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
919 if ( buf_len < ( DateTimeLen + 1 ) )
922 // 2004-05-01T13:20:00-00:00
923 snprintf(str_buf, buf_len,
924 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu+00:00",
925 Year, Month, Day, Hour, Minute, Second);
932 Kumu::Timestamp::DecodeString(const char* datestr)
936 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
938 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
940 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
943 ui32_t char_count = 10;
944 TmpStamp.Year = atoi(datestr);
945 TmpStamp.Month = atoi(datestr + 5);
946 TmpStamp.Day = atoi(datestr + 8);
947 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
949 if ( datestr[10] == 'T' )
951 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
952 || datestr[13] != ':'
953 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
957 TmpStamp.Hour = atoi(datestr + 11);
958 TmpStamp.Minute = atoi(datestr + 14);
960 if ( datestr[16] == ':' )
962 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
966 TmpStamp.Second = atoi(datestr + 17);
969 if ( datestr[19] == '.' )
971 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
974 // we don't carry the ms value
978 if ( datestr[19] == '-' || datestr[19] == '+' )
980 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
981 || datestr[22] != ':'
982 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
986 ui32_t TZ_hh = atoi(datestr + 20);
987 ui32_t TZ_mm = atoi(datestr + 23);
990 Kumu::DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
996 AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
1000 if ( datestr[char_count] != 0 )
1002 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
1003 datestr, char_count);
1010 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
1011 if ( SystemTimeToFileTime(&st, &ft) == 0 )
1013 SYSTIME_TO_TIMESTAMP(&st, *this);
1016 Kumu::TAI::caltime ct;
1017 TIMESTAMP_TO_CALTIME(TmpStamp, &ct);
1018 t = ct; // back and forth to tai to normalize offset
1020 CALTIME_TO_TIMESTAMP(&ct, *this)
1028 Kumu::Timestamp::HasValue() const
1030 if ( Year || Month || Day || Hour || Minute || Second )
1038 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
1041 if ( ! Reader->ReadUi16BE(&Year) ) return false;
1042 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
1048 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1051 if ( ! Writer->WriteUi16BE(Year) ) return false;
1052 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1056 //------------------------------------------------------------------------------------------
1058 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1059 : m_p(0), m_capacity(0), m_size(0)
1062 m_capacity = Buf->Capacity();
1063 assert(m_p); assert(m_capacity);
1067 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1069 if ( ( m_size + ber_len ) > m_capacity )
1072 if ( ! write_BER(m_p + m_size, i, ber_len) )
1080 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1081 : m_p(0), m_capacity(0), m_size(0)
1083 m_p = Buf->RoData();
1084 m_capacity = Buf->Length();
1085 assert(m_p); assert(m_capacity);
1089 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1091 if ( i == 0 || ber_len == 0 ) return false;
1093 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1096 if ( ( m_size + *ber_len ) > m_capacity )
1099 if ( ! read_BER(m_p + m_size, i) )
1106 //------------------------------------------------------------------------------------------
1108 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1110 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1115 Kumu::ByteString::~ByteString()
1122 // copy the given data into the ByteString, set Length value.
1123 // Returns error if the ByteString is too small.
1125 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1127 if ( m_Capacity < buf_len )
1128 return RESULT_ALLOC;
1130 memcpy(m_Data, buf, buf_len);
1136 // copy the given data into the ByteString, set Length value.
1137 // Returns error if the ByteString is too small.
1139 Kumu::ByteString::Set(const ByteString& Buf)
1141 if ( m_Capacity < Buf.m_Capacity )
1142 return RESULT_ALLOC;
1144 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1145 m_Length = Buf.m_Length;
1150 // Sets the size of the internally allocate buffer.
1152 Kumu::ByteString::Capacity(ui32_t cap_size)
1154 if ( m_Capacity >= cap_size )
1157 byte_t* tmp_data = 0;
1166 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1167 return RESULT_ALLOC;
1169 if ( tmp_data != 0 )
1171 assert(m_Length > 0);
1172 memcpy(m_Data, tmp_data, m_Length);
1176 m_Capacity = cap_size;
1182 Kumu::ByteString::Append(const ByteString& Buf)
1184 Result_t result = RESULT_OK;
1185 ui32_t diff = m_Capacity - m_Length;
1187 if ( diff < Buf.Length() )
1188 result = Capacity(m_Capacity + Buf.Length());
1190 if ( KM_SUCCESS(result) )
1192 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1193 m_Length += Buf.Length();
1201 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1203 Result_t result = RESULT_OK;
1204 ui32_t diff = m_Capacity - m_Length;
1206 if ( diff < buf_len )
1207 result = Capacity(m_Capacity + buf_len);
1209 if ( KM_SUCCESS(result) )
1211 memcpy(m_Data + m_Length, buf, buf_len);
1212 m_Length += buf_len;