2 Copyright (c) 2005-2006, 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 DefaultLogSink().Error("Unknown result code: %ld\n", v);
84 Kumu::Result_t::Delete(int v)
86 if ( v >= RESULT_NOTAFILE.Value() )
88 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
92 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
94 if ( s_ResultMap[i].rcode == v )
96 s_ResultMap[i].rcode = 0;
97 s_ResultMap[i++].result = 0;
99 for ( ; s_ResultMap[i].result != 0 && i < MapMax; i++ )
100 s_ResultMap[i-1] = s_ResultMap[i];
111 Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l)
114 assert(value < (int)MapMax);
122 s_ResultMap[0].rcode = v;
123 s_ResultMap[0].result = this;
124 s_ResultMap[1].rcode = 0;
125 s_ResultMap[1].result = 0;
130 while ( s_ResultMap[i].result != 0 && i < MapMax )
132 if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
138 assert(i+2 < MapMax);
140 s_ResultMap[i].rcode = v;
141 s_ResultMap[i].result = this;
142 s_ResultMap[i+1].rcode = 0;
143 s_ResultMap[i+1].result = 0;
147 Kumu::Result_t::~Result_t() {}
150 //------------------------------------------------------------------------------------------
153 static int s_DTraceSequence = 0;
155 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
156 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
158 m_Sequence = s_DTraceSequence++;
159 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
162 Kumu::DTrace_t::~DTrace_t()
165 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
167 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
170 //------------------------------------------------------------------------------------------
173 const char fill = '=';
174 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
176 const byte_t decode_map[] =
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, 0xff, 0xff, 0xff, 0xff, 0xff,
182 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
183 52, 53, 54, 55, 56, 57, 58, 59,
184 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
185 0xff, 0, 1, 2, 3, 4, 5, 6,
186 7, 8, 9, 10, 11, 12, 13, 14,
187 15, 16, 17, 18, 19, 20, 21, 22,
188 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
189 0xff, 26, 27, 28, 29, 30, 31, 32,
190 33, 34, 35, 36, 37, 38, 39, 40,
191 41, 42, 43, 44, 45, 46, 47, 48,
192 49, 50, 51, 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,
208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
212 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
213 // if the binary buffer was large enough to hold the result. If the output buffer
214 // is too small or any of the pointer arguments are NULL, the subroutine will
218 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
221 ui32_t i, block_len, diff;
223 if ( buf == 0 || strbuf == 0 )
226 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
231 while ( block_len % 3 )
234 for ( i = 0; i < block_len; i += 3 )
236 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
237 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
238 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
239 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
249 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
253 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
254 strbuf[out_char++] = fill;
256 else if ( diff == 2 )
258 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
259 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
262 strbuf[out_char++] = fill;
265 strbuf[out_char] = 0;
272 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
273 // the binary buffer was large enough to hold the result. The output parameter
274 // 'char_count' will contain the length of the converted string. If the output
275 // buffer is too small or any of the pointer arguments are NULL, the subroutine
276 // will return -1 and set 'char_count' to the required buffer size. No data will
277 // be written to 'buf' if the subroutine fails.
280 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
282 register byte_t c = 0, d = 0;
283 register ui32_t phase = 0, i = 0;
285 if ( str == 0 || buf == 0 || char_count == 0 )
288 while ( *str != 0 && i < buf_len )
290 c = decode_map[(int)*str++];
291 if ( c == 0xff ) continue;
292 if ( c == 0xfe ) break;
301 buf[i - 1] |= c >> 4;
306 buf[i++] = ( d << 4 ) | ( c >> 2 );
311 buf[i++] = ( d << 6 ) | c;
321 //------------------------------------------------------------------------------------------
323 // convert utf-8 hext string to bin
325 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
329 KM_TEST_NULL_L(conv_size);
333 if ( str[0] == 0 ) // nothing to convert
336 for ( int j = 0; str[j]; j++ )
338 if ( isxdigit(str[j]) )
342 if ( *conv_size & 0x01 ) (*conv_size)++;
345 if ( *conv_size > buf_len )// maximum possible data size
350 int phase = 0; // track high/low nybble
352 // for each character, fill in the high nybble then the low
353 for ( int i = 0; str[i]; i++ )
355 if ( ! isxdigit(str[i]) )
358 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
362 buf[*conv_size] = val << 4;
367 buf[*conv_size] |= val;
377 // convert a memory region to a NULL-terminated hexadecimal string
380 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
384 || ((bin_len * 2) + 1) > str_len )
389 for ( ui32_t i = 0; i < bin_len; i++ )
391 *p = (bin_buf[i] >> 4) & 0x0f;
392 *p += *p < 10 ? 0x30 : 0x61 - 10;
395 *p = bin_buf[i] & 0x0f;
396 *p += *p < 10 ? 0x30 : 0x61 - 10;
405 // spew a range of bin data as hex
407 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
415 static ui32_t row_len = 16;
416 const byte_t* p = buf;
417 const byte_t* end_p = p + dump_len;
419 for ( ui32_t line = 0; p < end_p; line++ )
421 fprintf(stream, " %06x: ", line);
425 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
426 fprintf(stream, "%02x ", *pp);
428 while ( i++ < row_len )
431 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
432 fputc((isprint(*pp) ? *pp : '.'), stream);
441 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
445 if ( str_len < 34 || bin_len != UUID_Length )
448 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
452 for ( k = 19, i = 12; i > 0; i-- )
453 str_buf[k+i+4] = str_buf[k+i];
455 // shift the time (mid+hi+clk)
456 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
458 for ( i = 4; i > 0; i-- )
459 str_buf[k+i+j] = str_buf[k+i];
462 // add in the hyphens and trainling null
463 for ( i = 8; i < 24; i += 5 )
472 Kumu::GenRandomValue(UUID& ID)
474 byte_t tmp_buf[UUID_Length];
475 GenRandomUUID(tmp_buf);
481 Kumu::GenRandomUUID(byte_t* buf)
484 RNG.FillRandom(buf, UUID_Length);
485 buf[6] &= 0x0f; // clear bits 4-7
486 buf[6] |= 0x40; // set UUID version
487 buf[8] &= 0x3f; // clear bits 6&7
488 buf[8] |= 0x80; // set bit 7
493 Kumu::GenRandomValue(SymmetricKey& Key)
495 byte_t tmp_buf[SymmetricKey_Length];
497 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
502 //------------------------------------------------------------------------------------------
503 // read a ber value from the buffer and compare with test value.
504 // Advances buffer to first character after BER value.
506 // read a ber value from the buffer and compare with test value.
507 // Advances buffer to first character after BER value.
510 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
515 if ( ( **buf & 0x80 ) == 0 )
519 ui8_t ber_size = ( **buf & 0x0f ) + 1;
524 for ( ui8_t i = 1; i < ber_size; i++ )
527 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
531 return ( val == test_value );
537 Kumu::read_BER(const byte_t* buf, ui64_t* val)
541 if ( buf == 0 || val == 0 )
544 if ( ( *buf & 0x80 ) == 0 )
548 ber_size = ( *buf & 0x0f ) + 1;
553 for ( i = 1; i < ber_size; i++ )
556 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
563 static const ui64_t ber_masks[9] =
564 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
565 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
566 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
567 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
574 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
580 { // calculate default length
581 if ( val < 0x01000000L )
583 else if ( val < ui64_C(0x0100000000000000) )
589 { // sanity check BER length
592 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
596 if ( val & ber_masks[ber_len - 1] )
598 ui64Printer tmp_i(val);
599 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
604 buf[0] = 0x80 + ( ber_len - 1 );
606 for ( ui32_t i = ber_len - 1; i > 0; i-- )
608 buf[i] = (ui8_t)(val & 0xff);
616 //------------------------------------------------------------------------------------------
619 #define TIMESTAMP_TO_SYSTIME(ts, t) \
620 (t)->wYear = (ts).Year; /* year */ \
621 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
622 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
623 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
624 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
625 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
626 (t)->wDayOfWeek = 0; \
627 (t)->wMilliseconds = 0
629 #define SYSTIME_TO_TIMESTAMP(t, ts) \
630 (ts).Year = (t)->wYear; /* year */ \
631 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
632 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
633 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
634 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
635 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
638 Kumu::Timestamp::Timestamp() :
639 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
642 GetSystemTime(&sys_time);
643 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
648 Kumu::Timestamp::operator<(const Timestamp& rhs) const
650 SYSTEMTIME lhst, rhst;
653 TIMESTAMP_TO_SYSTIME(*this, &lhst);
654 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
655 SystemTimeToFileTime(&lhst, &lft);
656 SystemTimeToFileTime(&rhst, &rft);
657 return ( CompareFileTime(&lft, &rft) == -1 );
662 Kumu::Timestamp::operator>(const Timestamp& rhs) const
664 SYSTEMTIME lhst, rhst;
667 TIMESTAMP_TO_SYSTIME(*this, &lhst);
668 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
669 SystemTimeToFileTime(&lhst, &lft);
670 SystemTimeToFileTime(&rhst, &rft);
671 return ( CompareFileTime(&lft, &rft) == 1 );
675 seconds_to_ns100(ui32_t seconds)
677 return ((ui64_t)seconds * 10000000);
682 Kumu::Timestamp::AddDays(i32_t days)
684 SYSTEMTIME current_st;
686 ULARGE_INTEGER current_ul;
690 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
691 SystemTimeToFileTime(¤t_st, ¤t_ft);
692 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
693 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
694 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
695 FileTimeToSystemTime(¤t_ft, ¤t_st);
696 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
702 Kumu::Timestamp::AddHours(i32_t hours)
704 SYSTEMTIME current_st;
706 ULARGE_INTEGER current_ul;
710 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
711 SystemTimeToFileTime(¤t_st, ¤t_ft);
712 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
713 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
714 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
715 FileTimeToSystemTime(¤t_ft, ¤t_st);
716 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
724 #define TIMESTAMP_TO_CALTIME(ts, ct) \
725 (ct)->date.year = (ts).Year; /* year */ \
726 (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \
727 (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \
728 (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \
729 (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \
730 (ct)->second = (ts).Second; /* seconds (0 - 60) */ \
733 #define CALTIME_TO_TIMESTAMP(ct, ts) \
734 assert((ct)->offset == 0); \
735 (ts).Year = (ct)->date.year; /* year */ \
736 (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \
737 (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \
738 (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \
739 (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \
740 (ts).Second = (ct)->second; /* seconds (0 - 60) */
744 Kumu::Timestamp::Timestamp() :
745 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
748 Kumu::TAI::caltime ct;
751 CALTIME_TO_TIMESTAMP(&ct, *this)
756 Kumu::Timestamp::operator<(const Timestamp& rhs) const
758 Kumu::TAI::caltime lh_ct, rh_ct;
759 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
760 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
762 Kumu::TAI::tai lh_tai, rh_tai;
766 return ( lh_tai.x < rh_tai.x );
771 Kumu::Timestamp::operator>(const Timestamp& rhs) const
773 Kumu::TAI::caltime lh_ct, rh_ct;
774 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
775 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
777 Kumu::TAI::tai lh_tai, rh_tai;
781 return ( lh_tai.x > rh_tai.x );
786 Kumu::Timestamp::AddDays(i32_t days)
788 Kumu::TAI::caltime ct;
793 TIMESTAMP_TO_CALTIME(*this, &ct)
797 CALTIME_TO_TIMESTAMP(&ct, *this)
803 Kumu::Timestamp::AddHours(i32_t hours)
805 Kumu::TAI::caltime ct;
810 TIMESTAMP_TO_CALTIME(*this, &ct)
814 CALTIME_TO_TIMESTAMP(&ct, *this)
821 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
831 Kumu::Timestamp::~Timestamp()
836 const Kumu::Timestamp&
837 Kumu::Timestamp::operator=(const Timestamp& rhs)
850 Kumu::Timestamp::operator==(const Timestamp& rhs) const
852 if ( Year == rhs.Year
853 && Month == rhs.Month
856 && Minute == rhs.Minute
857 && Second == rhs.Second )
865 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
867 if ( Year != rhs.Year
868 || Month != rhs.Month
871 || Minute != rhs.Minute
872 || Second != rhs.Second )
880 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
882 if ( buf_len < ( DateTimeLen + 1 ) )
885 // 2004-05-01T13:20:00-00:00
886 snprintf(str_buf, buf_len,
887 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu+00:00",
888 Year, Month, Day, Hour, Minute, Second);
895 Kumu::Timestamp::DecodeString(const char* datestr)
899 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
901 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
903 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
906 ui32_t char_count = 10;
907 TmpStamp.Year = atoi(datestr);
908 TmpStamp.Month = atoi(datestr + 5);
909 TmpStamp.Day = atoi(datestr + 8);
910 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
912 if ( datestr[10] == 'T' )
914 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
915 || datestr[13] != ':'
916 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
920 TmpStamp.Hour = atoi(datestr + 11);
921 TmpStamp.Minute = atoi(datestr + 14);
923 if ( datestr[16] == ':' )
925 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
929 TmpStamp.Second = atoi(datestr + 17);
932 if ( datestr[19] == '.' )
934 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
937 // we don't carry the ms value
941 if ( datestr[19] == '-' || datestr[19] == '+' )
943 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
944 || datestr[22] != ':'
945 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
949 ui32_t TZ_hh = atoi(datestr + 20);
950 ui32_t TZ_mm = atoi(datestr + 23);
953 Kumu::DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
959 AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
963 if ( datestr[char_count] != 0 )
965 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
966 datestr, char_count);
973 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
974 if ( SystemTimeToFileTime(&st, &ft) == 0 )
976 SYSTIME_TO_TIMESTAMP(&st, *this);
979 Kumu::TAI::caltime ct;
980 TIMESTAMP_TO_CALTIME(TmpStamp, &ct);
981 t = ct; // back and forth to tai to normalize offset
983 CALTIME_TO_TIMESTAMP(&ct, *this)
991 Kumu::Timestamp::HasValue() const
993 if ( Year || Month || Day || Hour || Minute || Second )
1001 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
1004 if ( ! Reader->ReadUi16BE(&Year) ) return false;
1005 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
1011 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1014 if ( ! Writer->WriteUi16BE(Year) ) return false;
1015 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1019 //------------------------------------------------------------------------------------------
1021 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1022 : m_p(0), m_capacity(0), m_size(0)
1025 m_capacity = Buf->Capacity();
1026 assert(m_p); assert(m_capacity);
1030 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1032 if ( ( m_size + ber_len ) > m_capacity )
1035 if ( ! write_BER(m_p + m_size, i, ber_len) )
1043 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1044 : m_p(0), m_capacity(0), m_size(0)
1046 m_p = Buf->RoData();
1047 m_capacity = Buf->Length();
1048 assert(m_p); assert(m_capacity);
1052 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1054 if ( i == 0 || ber_len == 0 ) return false;
1056 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1059 if ( ( m_size + *ber_len ) > m_capacity )
1062 if ( ! read_BER(m_p + m_size, i) )
1069 //------------------------------------------------------------------------------------------
1071 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1073 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1078 Kumu::ByteString::~ByteString()
1085 // copy the given data into the ByteString, set Length value.
1086 // Returns error if the ByteString is too small.
1088 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1090 if ( m_Capacity < buf_len )
1091 return RESULT_ALLOC;
1093 memcpy(m_Data, buf, buf_len);
1099 // copy the given data into the ByteString, set Length value.
1100 // Returns error if the ByteString is too small.
1102 Kumu::ByteString::Set(const ByteString& Buf)
1104 if ( m_Capacity < Buf.m_Capacity )
1105 return RESULT_ALLOC;
1107 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1108 m_Length = Buf.m_Length;
1113 // Sets the size of the internally allocate buffer.
1115 Kumu::ByteString::Capacity(ui32_t cap_size)
1117 if ( m_Capacity >= cap_size )
1120 byte_t* tmp_data = 0;
1129 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1130 return RESULT_ALLOC;
1132 if ( tmp_data != 0 )
1134 assert(m_Length > 0);
1135 memcpy(m_Data, tmp_data, m_Length);
1139 m_Capacity = cap_size;
1145 Kumu::ByteString::Append(const ByteString& Buf)
1147 Result_t result = RESULT_OK;
1148 ui32_t diff = m_Capacity - m_Length;
1150 if ( diff < Buf.Length() )
1151 result = Capacity(m_Capacity + Buf.Length());
1153 if ( KM_SUCCESS(result) )
1155 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1156 m_Length += Buf.Length();
1164 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1166 Result_t result = RESULT_OK;
1167 ui32_t diff = m_Capacity - m_Length;
1169 if ( diff < buf_len )
1170 result = Capacity(m_Capacity + buf_len);
1172 if ( KM_SUCCESS(result) )
1174 memcpy(m_Data + m_Length, buf, buf_len);
1175 m_Length += buf_len;