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>
42 //------------------------------------------------------------------------------------------
49 Kumu::Result_t* result;
52 const ui32_t MapMax = 512;
53 const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t));
54 static bool s_MapInit = false;
55 static struct map_entry_t s_ResultMap[MapSize];
59 Kumu::Result_t::Find(long v)
64 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
66 if ( s_ResultMap[i].rcode == v )
67 return *s_ResultMap[i].result;
70 DefaultLogSink().Error("Unknown result code: %ld\n", v);
75 Kumu::Result_t::Result_t(long v, const char* l) : value(v), label(l)
85 s_ResultMap[0].rcode = v;
86 s_ResultMap[0].result = this;
87 s_ResultMap[1].rcode = 0;
88 s_ResultMap[1].result = 0;
93 while ( s_ResultMap[i].result != 0 && i < MapMax )
95 if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
101 assert(i+2 < MapMax);
103 s_ResultMap[i].rcode = v;
104 s_ResultMap[i].result = this;
105 s_ResultMap[i+1].rcode = 0;
106 s_ResultMap[i+1].result = 0;
110 Kumu::Result_t::~Result_t() {}
113 //------------------------------------------------------------------------------------------
116 static int s_DTraceSequence = 0;
118 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
119 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
121 m_Sequence = s_DTraceSequence++;
122 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
125 Kumu::DTrace_t::~DTrace_t()
128 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
130 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
133 //------------------------------------------------------------------------------------------
136 const char fill = '=';
137 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139 const byte_t decode_map[] =
140 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
146 52, 53, 54, 55, 56, 57, 58, 59,
147 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
148 0xff, 0, 1, 2, 3, 4, 5, 6,
149 7, 8, 9, 10, 11, 12, 13, 14,
150 15, 16, 17, 18, 19, 20, 21, 22,
151 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
152 0xff, 26, 27, 28, 29, 30, 31, 32,
153 33, 34, 35, 36, 37, 38, 39, 40,
154 41, 42, 43, 44, 45, 46, 47, 48,
155 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
163 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
164 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
165 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
166 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
167 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
168 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
170 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
171 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
175 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
176 // if the binary buffer was large enough to hold the result. If the output buffer
177 // is too small or any of the pointer arguments are NULL, the subroutine will
181 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
184 ui32_t i, block_len, diff;
186 if ( buf == 0 || strbuf == 0 )
189 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
194 while ( block_len % 3 )
197 for ( i = 0; i < block_len; i += 3 )
199 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
200 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
201 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
202 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
212 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
216 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
217 strbuf[out_char++] = fill;
219 else if ( diff == 2 )
221 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
222 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
225 strbuf[out_char++] = fill;
228 strbuf[out_char] = 0;
235 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
236 // the binary buffer was large enough to hold the result. The output parameter
237 // 'char_count' will contain the length of the converted string. If the output
238 // buffer is too small or any of the pointer arguments are NULL, the subroutine
239 // will return -1 and set 'char_count' to the required buffer size. No data will
240 // be written to 'buf' if the subroutine fails.
243 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
245 register byte_t c = 0, d = 0;
246 register ui32_t phase = 0, i = 0;
248 if ( str == 0 || buf == 0 || char_count == 0 )
251 while ( *str != 0 && i < buf_len )
253 c = decode_map[(int)*str++];
254 if ( c == 0xff ) continue;
255 if ( c == 0xfe ) break;
264 buf[i - 1] |= c >> 4;
269 buf[i++] = ( d << 4 ) | ( c >> 2 );
274 buf[i++] = ( d << 6 ) | c;
284 //------------------------------------------------------------------------------------------
286 // convert utf-8 hext string to bin
288 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
292 KM_TEST_NULL_L(conv_size);
296 if ( str[0] == 0 ) // nothing to convert
299 for ( int j = 0; str[j]; j++ )
301 if ( isxdigit(str[j]) )
305 if ( *conv_size & 0x01 ) (*conv_size)++;
308 if ( *conv_size > buf_len )// maximum possible data size
313 int phase = 0; // track high/low nybble
315 // for each character, fill in the high nybble then the low
316 for ( int i = 0; str[i]; i++ )
318 if ( ! isxdigit(str[i]) )
321 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
325 buf[*conv_size] = val << 4;
330 buf[*conv_size] |= val;
340 // convert a memory region to a NULL-terminated hexadecimal string
343 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
347 || ((bin_len * 2) + 1) > str_len )
352 for ( ui32_t i = 0; i < bin_len; i++ )
354 *p = (bin_buf[i] >> 4) & 0x0f;
355 *p += *p < 10 ? 0x30 : 0x61 - 10;
358 *p = bin_buf[i] & 0x0f;
359 *p += *p < 10 ? 0x30 : 0x61 - 10;
368 // spew a range of bin data as hex
370 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
378 static ui32_t row_len = 16;
379 const byte_t* p = buf;
380 const byte_t* end_p = p + dump_len;
382 for ( ui32_t line = 0; p < end_p; line++ )
384 fprintf(stream, " %06x: ", line);
388 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
389 fprintf(stream, "%02x ", *pp);
391 while ( i++ < row_len )
394 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
395 fputc((isprint(*pp) ? *pp : '.'), stream);
404 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
408 if ( str_len < 34 || bin_len != UUID_Length )
411 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
415 for ( k = 19, i = 12; i > 0; i-- )
416 str_buf[k+i+4] = str_buf[k+i];
418 // shift the time (mid+hi+clk)
419 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
421 for ( i = 4; i > 0; i-- )
422 str_buf[k+i+j] = str_buf[k+i];
425 // add in the hyphens and trainling null
426 for ( i = 8; i < 24; i += 5 )
435 Kumu::GenRandomValue(UUID& ID)
437 byte_t tmp_buf[UUID_Length];
438 GenRandomUUID(tmp_buf);
444 Kumu::GenRandomUUID(byte_t* buf)
447 RNG.FillRandom(buf, UUID_Length);
448 buf[6] &= 0x0f; // clear bits 4-7
449 buf[6] |= 0x40; // set UUID version
450 buf[8] &= 0x3f; // clear bits 6&7
451 buf[8] |= 0x80; // set bit 7
456 Kumu::GenRandomValue(SymmetricKey& Key)
458 byte_t tmp_buf[SymmetricKey_Length];
460 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
465 //------------------------------------------------------------------------------------------
466 // read a ber value from the buffer and compare with test value.
467 // Advances buffer to first character after BER value.
469 // read a ber value from the buffer and compare with test value.
470 // Advances buffer to first character after BER value.
473 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
478 if ( ( **buf & 0x80 ) == 0 )
482 ui8_t ber_size = ( **buf & 0x0f ) + 1;
487 for ( ui8_t i = 1; i < ber_size; i++ )
490 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
494 return ( val == test_value );
500 Kumu::read_BER(const byte_t* buf, ui64_t* val)
504 if ( buf == 0 || val == 0 )
507 if ( ( *buf & 0x80 ) == 0 )
511 ber_size = ( *buf & 0x0f ) + 1;
516 for ( i = 1; i < ber_size; i++ )
519 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
526 static const ui64_t ber_masks[9] =
527 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
528 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
529 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
530 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
537 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
543 { // calculate default length
544 if ( val < 0x01000000L )
546 else if ( val < ui64_C(0x0100000000000000) )
552 { // sanity check BER length
555 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
559 if ( val & ber_masks[ber_len - 1] )
561 ui64Printer tmp_i(val);
562 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
567 buf[0] = 0x80 + ( ber_len - 1 );
569 for ( ui32_t i = ber_len - 1; i > 0; i-- )
571 buf[i] = (ui8_t)(val & 0xff);
579 //------------------------------------------------------------------------------------------
582 #define TIMESTAMP_TO_SYSTIME(ts, t) \
583 (t)->wYear = (ts).Year; /* year */ \
584 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
585 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
586 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
587 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
588 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
589 (t)->wDayOfWeek = 0; \
590 (t)->wMilliseconds = 0
592 #define SYSTIME_TO_TIMESTAMP(t, ts) \
593 (ts).Year = (t)->wYear; /* year */ \
594 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
595 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
596 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
597 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
598 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
601 Kumu::Timestamp::Timestamp() :
602 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
605 GetSystemTime(&sys_time);
606 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
611 Kumu::Timestamp::operator<(const Timestamp& rhs) const
613 SYSTEMTIME lhst, rhst;
616 TIMESTAMP_TO_SYSTIME(*this, &lhst);
617 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
618 SystemTimeToFileTime(&lhst, &lft);
619 SystemTimeToFileTime(&rhst, &rft);
620 return ( CompareFileTime(&lft, &rft) == -1 );
625 Kumu::Timestamp::operator>(const Timestamp& rhs) const
627 SYSTEMTIME lhst, rhst;
630 TIMESTAMP_TO_SYSTIME(*this, &lhst);
631 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
632 SystemTimeToFileTime(&lhst, &lft);
633 SystemTimeToFileTime(&rhst, &rft);
634 return ( CompareFileTime(&lft, &rft) == 1 );
638 seconds_to_ns100(ui32_t seconds)
640 return ((ui64_t)seconds * 10000000);
645 Kumu::Timestamp::AddDays(i32_t days)
647 SYSTEMTIME current_st;
649 ULARGE_INTEGER current_ul;
653 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
654 SystemTimeToFileTime(¤t_st, ¤t_ft);
655 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
656 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
657 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
658 FileTimeToSystemTime(¤t_ft, ¤t_st);
659 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
665 Kumu::Timestamp::AddHours(i32_t hours)
667 SYSTEMTIME current_st;
669 ULARGE_INTEGER current_ul;
673 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
674 SystemTimeToFileTime(¤t_st, ¤t_ft);
675 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
676 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
677 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
678 FileTimeToSystemTime(¤t_ft, ¤t_st);
679 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
687 #define TIMESTAMP_TO_TM(ts, t) \
688 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
689 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
690 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
691 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
692 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
693 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
695 #define TM_TO_TIMESTAMP(t, ts) \
696 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
697 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
698 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
699 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
700 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
701 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
704 Kumu::Timestamp::Timestamp() :
705 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
707 time_t t_now = time(0);
708 struct tm* now = gmtime(&t_now);
709 TM_TO_TIMESTAMP(now, *this);
714 Kumu::Timestamp::operator<(const Timestamp& rhs) const
716 struct tm lhtm, rhtm;
717 TIMESTAMP_TO_TM(*this, &lhtm);
718 TIMESTAMP_TO_TM(rhs, &rhtm);
719 return ( timegm(&lhtm) < timegm(&rhtm) );
724 Kumu::Timestamp::operator>(const Timestamp& rhs) const
726 struct tm lhtm, rhtm;
727 TIMESTAMP_TO_TM(*this, &lhtm);
728 TIMESTAMP_TO_TM(rhs, &rhtm);
729 return ( timegm(&lhtm) > timegm(&rhtm) );
734 Kumu::Timestamp::AddDays(i32_t days)
740 TIMESTAMP_TO_TM(*this, ¤t);
741 time_t adj_time = timegm(¤t);
742 adj_time += 86400 * days;
743 struct tm* now = gmtime(&adj_time);
744 TM_TO_TIMESTAMP(now, *this);
750 Kumu::Timestamp::AddHours(i32_t hours)
756 TIMESTAMP_TO_TM(*this, ¤t);
757 time_t adj_time = timegm(¤t);
758 adj_time += 3600 * hours;
759 struct tm* now = gmtime(&adj_time);
760 TM_TO_TIMESTAMP(now, *this);
767 Kumu::Timestamp::Timestamp(const Timestamp& rhs)
777 Kumu::Timestamp::~Timestamp()
782 const Kumu::Timestamp&
783 Kumu::Timestamp::operator=(const Timestamp& rhs)
796 Kumu::Timestamp::operator==(const Timestamp& rhs) const
798 if ( Year == rhs.Year
799 && Month == rhs.Month
802 && Minute == rhs.Minute
803 && Second == rhs.Second )
811 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
813 if ( Year != rhs.Year
814 || Month != rhs.Month
817 || Minute != rhs.Minute
818 || Second != rhs.Second )
826 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
828 if ( buf_len < ( DateTimeLen + 1 ) )
831 // 2004-05-01T13:20:00-00:00
832 snprintf(str_buf, buf_len,
833 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu-00:00",
834 Year, Month, Day, Hour, Minute, Second);
841 Kumu::Timestamp::DecodeString(const char* datestr)
845 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
847 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
849 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
852 ui32_t char_count = 10;
853 TmpStamp.Year = atoi(datestr);
854 TmpStamp.Month = atoi(datestr + 5);
855 TmpStamp.Day = atoi(datestr + 8);
856 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
858 if ( datestr[10] == 'T' )
860 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
861 || datestr[13] != ':'
862 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
866 TmpStamp.Hour = atoi(datestr + 11);
867 TmpStamp.Minute = atoi(datestr + 14);
869 if ( datestr[16] == ':' )
871 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
875 TmpStamp.Second = atoi(datestr + 17);
878 if ( datestr[19] == '-' || datestr[19] == '+' )
880 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
881 || datestr[22] != ':'
882 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
886 ui32_t TZ_hh = atoi(datestr + 20);
887 ui32_t TZ_mm = atoi(datestr + 23);
890 DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
896 AddHours( (datestr[19] == '-' ? (-TZ_hh) : TZ_hh));
900 if ( datestr[char_count] != 0 )
902 DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
903 datestr, char_count);
910 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
911 if ( SystemTimeToFileTime(&st, &ft) == 0 )
913 SYSTIME_TO_TIMESTAMP(&st, *this);
916 TIMESTAMP_TO_TM(TmpStamp, &stm);
917 if ( timegm(&stm) == 0 )
919 TM_TO_TIMESTAMP(&stm, *this);
927 Kumu::Timestamp::HasValue() const
929 if ( Year || Month || Day || Hour || Minute || Second )
937 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
940 if ( ! Reader->ReadUi16BE(&Year) ) return false;
941 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
947 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
950 if ( ! Writer->WriteUi16BE(Year) ) return false;
951 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
955 //------------------------------------------------------------------------------------------
957 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
958 : m_p(0), m_capacity(0), m_size(0)
961 m_capacity = Buf->Capacity();
962 assert(m_p); assert(m_capacity);
966 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
968 if ( ( m_size + ber_len ) > m_capacity )
971 if ( ! write_BER(m_p + m_size, i, ber_len) )
979 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
980 : m_p(0), m_capacity(0), m_size(0)
983 m_capacity = Buf->Length();
984 assert(m_p); assert(m_capacity);
988 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
990 if ( i == 0 || ber_len == 0 ) return false;
992 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
995 if ( ( m_size + *ber_len ) > m_capacity )
998 if ( ! read_BER(m_p + m_size, i) )
1005 //------------------------------------------------------------------------------------------
1007 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1009 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1014 Kumu::ByteString::~ByteString()
1021 // copy the given data into the ByteString, set Length value.
1022 // Returns error if the ByteString is too small.
1024 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1026 if ( m_Capacity < buf_len )
1027 return RESULT_ALLOC;
1029 memcpy(m_Data, buf, buf_len);
1035 // copy the given data into the ByteString, set Length value.
1036 // Returns error if the ByteString is too small.
1038 Kumu::ByteString::Set(const ByteString& Buf)
1040 if ( m_Capacity < Buf.m_Capacity )
1041 return RESULT_ALLOC;
1043 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1044 m_Length = Buf.m_Length;
1049 // Sets the size of the internally allocate buffer.
1050 // Resets content length to zero.
1052 Kumu::ByteString::Capacity(ui32_t cap_size)
1054 if ( m_Capacity < cap_size )
1059 m_Data = (byte_t*)malloc(cap_size);
1062 return RESULT_ALLOC;
1064 m_Capacity = cap_size;
1073 Kumu::ByteString::Append(const ByteString& Buf)
1075 Result_t result = RESULT_OK;
1076 ui32_t diff = m_Capacity - m_Length;
1078 if ( diff < Buf.Length() )
1079 result = Capacity(m_Capacity + Buf.Length());
1081 if ( KM_SUCCESS(result) )
1083 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1084 m_Length += Buf.Length();
1092 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1094 Result_t result = RESULT_OK;
1095 ui32_t diff = m_Capacity - m_Length;
1097 if ( diff < buf_len )
1098 result = Capacity(m_Capacity + buf_len);
1100 if ( KM_SUCCESS(result) )
1102 memcpy(m_Data + m_Length, buf, buf_len);
1103 m_Length += buf_len;