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 = 1024;
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(int 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);
76 Kumu::Result_t::Delete(int v)
78 if ( v >= RESULT_NOTAFILE.Value() )
80 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
84 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
86 if ( s_ResultMap[i].rcode == v )
88 s_ResultMap[i].rcode = 0;
89 s_ResultMap[i++].result = 0;
91 for ( ; s_ResultMap[i].result != 0 && i < MapMax; i++ )
92 s_ResultMap[i-1] = s_ResultMap[i];
103 Kumu::Result_t::Result_t(int v, const char* l) : value(v), label(l)
106 assert(value < (int)MapMax);
114 s_ResultMap[0].rcode = v;
115 s_ResultMap[0].result = this;
116 s_ResultMap[1].rcode = 0;
117 s_ResultMap[1].result = 0;
122 while ( s_ResultMap[i].result != 0 && i < MapMax )
124 if ( s_ResultMap[i].rcode == v && s_ResultMap[i].result != 0 )
130 assert(i+2 < MapMax);
132 s_ResultMap[i].rcode = v;
133 s_ResultMap[i].result = this;
134 s_ResultMap[i+1].rcode = 0;
135 s_ResultMap[i+1].result = 0;
139 Kumu::Result_t::~Result_t() {}
142 //------------------------------------------------------------------------------------------
145 static int s_DTraceSequence = 0;
147 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
148 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
150 m_Sequence = s_DTraceSequence++;
151 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
154 Kumu::DTrace_t::~DTrace_t()
157 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
159 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
162 //------------------------------------------------------------------------------------------
165 const char fill = '=';
166 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
168 const byte_t decode_map[] =
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,
172 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
173 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
175 52, 53, 54, 55, 56, 57, 58, 59,
176 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
177 0xff, 0, 1, 2, 3, 4, 5, 6,
178 7, 8, 9, 10, 11, 12, 13, 14,
179 15, 16, 17, 18, 19, 20, 21, 22,
180 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
181 0xff, 26, 27, 28, 29, 30, 31, 32,
182 33, 34, 35, 36, 37, 38, 39, 40,
183 41, 42, 43, 44, 45, 46, 47, 48,
184 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
185 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
186 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
187 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
188 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
189 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
190 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
191 0xff, 0xff, 0xff, 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
204 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
205 // if the binary buffer was large enough to hold the result. If the output buffer
206 // is too small or any of the pointer arguments are NULL, the subroutine will
210 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
213 ui32_t i, block_len, diff;
215 if ( buf == 0 || strbuf == 0 )
218 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
223 while ( block_len % 3 )
226 for ( i = 0; i < block_len; i += 3 )
228 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
229 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
230 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
231 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
241 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
245 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
246 strbuf[out_char++] = fill;
248 else if ( diff == 2 )
250 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
251 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
254 strbuf[out_char++] = fill;
257 strbuf[out_char] = 0;
264 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
265 // the binary buffer was large enough to hold the result. The output parameter
266 // 'char_count' will contain the length of the converted string. If the output
267 // buffer is too small or any of the pointer arguments are NULL, the subroutine
268 // will return -1 and set 'char_count' to the required buffer size. No data will
269 // be written to 'buf' if the subroutine fails.
272 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
274 register byte_t c = 0, d = 0;
275 register ui32_t phase = 0, i = 0;
277 if ( str == 0 || buf == 0 || char_count == 0 )
280 while ( *str != 0 && i < buf_len )
282 c = decode_map[(int)*str++];
283 if ( c == 0xff ) continue;
284 if ( c == 0xfe ) break;
293 buf[i - 1] |= c >> 4;
298 buf[i++] = ( d << 4 ) | ( c >> 2 );
303 buf[i++] = ( d << 6 ) | c;
313 //------------------------------------------------------------------------------------------
315 // convert utf-8 hext string to bin
317 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
321 KM_TEST_NULL_L(conv_size);
325 if ( str[0] == 0 ) // nothing to convert
328 for ( int j = 0; str[j]; j++ )
330 if ( isxdigit(str[j]) )
334 if ( *conv_size & 0x01 ) (*conv_size)++;
337 if ( *conv_size > buf_len )// maximum possible data size
342 int phase = 0; // track high/low nybble
344 // for each character, fill in the high nybble then the low
345 for ( int i = 0; str[i]; i++ )
347 if ( ! isxdigit(str[i]) )
350 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
354 buf[*conv_size] = val << 4;
359 buf[*conv_size] |= val;
369 // convert a memory region to a NULL-terminated hexadecimal string
372 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
376 || ((bin_len * 2) + 1) > str_len )
381 for ( ui32_t i = 0; i < bin_len; i++ )
383 *p = (bin_buf[i] >> 4) & 0x0f;
384 *p += *p < 10 ? 0x30 : 0x61 - 10;
387 *p = bin_buf[i] & 0x0f;
388 *p += *p < 10 ? 0x30 : 0x61 - 10;
397 // spew a range of bin data as hex
399 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
407 static ui32_t row_len = 16;
408 const byte_t* p = buf;
409 const byte_t* end_p = p + dump_len;
411 for ( ui32_t line = 0; p < end_p; line++ )
413 fprintf(stream, " %06x: ", line);
417 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
418 fprintf(stream, "%02x ", *pp);
420 while ( i++ < row_len )
423 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
424 fputc((isprint(*pp) ? *pp : '.'), stream);
433 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
437 if ( str_len < 34 || bin_len != UUID_Length )
440 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
444 for ( k = 19, i = 12; i > 0; i-- )
445 str_buf[k+i+4] = str_buf[k+i];
447 // shift the time (mid+hi+clk)
448 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
450 for ( i = 4; i > 0; i-- )
451 str_buf[k+i+j] = str_buf[k+i];
454 // add in the hyphens and trainling null
455 for ( i = 8; i < 24; i += 5 )
464 Kumu::GenRandomValue(UUID& ID)
466 byte_t tmp_buf[UUID_Length];
467 GenRandomUUID(tmp_buf);
473 Kumu::GenRandomUUID(byte_t* buf)
476 RNG.FillRandom(buf, UUID_Length);
477 buf[6] &= 0x0f; // clear bits 4-7
478 buf[6] |= 0x40; // set UUID version
479 buf[8] &= 0x3f; // clear bits 6&7
480 buf[8] |= 0x80; // set bit 7
485 Kumu::GenRandomValue(SymmetricKey& Key)
487 byte_t tmp_buf[SymmetricKey_Length];
489 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
494 //------------------------------------------------------------------------------------------
495 // read a ber value from the buffer and compare with test value.
496 // Advances buffer to first character after BER value.
498 // read a ber value from the buffer and compare with test value.
499 // Advances buffer to first character after BER value.
502 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
507 if ( ( **buf & 0x80 ) == 0 )
511 ui8_t ber_size = ( **buf & 0x0f ) + 1;
516 for ( ui8_t i = 1; i < ber_size; i++ )
519 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
523 return ( val == test_value );
529 Kumu::read_BER(const byte_t* buf, ui64_t* val)
533 if ( buf == 0 || val == 0 )
536 if ( ( *buf & 0x80 ) == 0 )
540 ber_size = ( *buf & 0x0f ) + 1;
545 for ( i = 1; i < ber_size; i++ )
548 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
555 static const ui64_t ber_masks[9] =
556 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
557 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
558 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
559 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
566 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
572 { // calculate default length
573 if ( val < 0x01000000L )
575 else if ( val < ui64_C(0x0100000000000000) )
581 { // sanity check BER length
584 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
588 if ( val & ber_masks[ber_len - 1] )
590 ui64Printer tmp_i(val);
591 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
596 buf[0] = 0x80 + ( ber_len - 1 );
598 for ( ui32_t i = ber_len - 1; i > 0; i-- )
600 buf[i] = (ui8_t)(val & 0xff);
608 //------------------------------------------------------------------------------------------
611 #define TIMESTAMP_TO_SYSTIME(ts, t) \
612 (t)->wYear = (ts).Year; /* year */ \
613 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
614 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
615 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
616 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
617 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
618 (t)->wDayOfWeek = 0; \
619 (t)->wMilliseconds = 0
621 #define SYSTIME_TO_TIMESTAMP(t, ts) \
622 (ts).Year = (t)->wYear; /* year */ \
623 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
624 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
625 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
626 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
627 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
630 Kumu::Timestamp::Timestamp() :
631 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
634 GetSystemTime(&sys_time);
635 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
640 Kumu::Timestamp::operator<(const Timestamp& rhs) const
642 SYSTEMTIME lhst, rhst;
645 TIMESTAMP_TO_SYSTIME(*this, &lhst);
646 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
647 SystemTimeToFileTime(&lhst, &lft);
648 SystemTimeToFileTime(&rhst, &rft);
649 return ( CompareFileTime(&lft, &rft) == -1 );
654 Kumu::Timestamp::operator>(const Timestamp& rhs) const
656 SYSTEMTIME lhst, rhst;
659 TIMESTAMP_TO_SYSTIME(*this, &lhst);
660 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
661 SystemTimeToFileTime(&lhst, &lft);
662 SystemTimeToFileTime(&rhst, &rft);
663 return ( CompareFileTime(&lft, &rft) == 1 );
667 seconds_to_ns100(ui32_t seconds)
669 return ((ui64_t)seconds * 10000000);
674 Kumu::Timestamp::AddDays(i32_t days)
676 SYSTEMTIME current_st;
678 ULARGE_INTEGER current_ul;
682 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
683 SystemTimeToFileTime(¤t_st, ¤t_ft);
684 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
685 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
686 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
687 FileTimeToSystemTime(¤t_ft, ¤t_st);
688 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
694 Kumu::Timestamp::AddHours(i32_t hours)
696 SYSTEMTIME current_st;
698 ULARGE_INTEGER current_ul;
702 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
703 SystemTimeToFileTime(¤t_st, ¤t_ft);
704 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
705 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
706 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
707 FileTimeToSystemTime(¤t_ft, ¤t_st);
708 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
716 #define TIMESTAMP_TO_TM(ts, t) \
717 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
718 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
719 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
720 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
721 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
722 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
724 #define TM_TO_TIMESTAMP(t, ts) \
725 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
726 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
727 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
728 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
729 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
730 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
733 Kumu::Timestamp::Timestamp() :
734 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
736 time_t t_now = time(0);
737 struct tm* now = gmtime(&t_now);
738 TM_TO_TIMESTAMP(now, *this);
743 Kumu::Timestamp::operator<(const Timestamp& rhs) const
745 struct tm lhtm, rhtm;
746 TIMESTAMP_TO_TM(*this, &lhtm);
747 TIMESTAMP_TO_TM(rhs, &rhtm);
748 return ( timegm(&lhtm) < timegm(&rhtm) );
753 Kumu::Timestamp::operator>(const Timestamp& rhs) const
755 struct tm lhtm, rhtm;
756 TIMESTAMP_TO_TM(*this, &lhtm);
757 TIMESTAMP_TO_TM(rhs, &rhtm);
758 return ( timegm(&lhtm) > timegm(&rhtm) );
763 Kumu::Timestamp::AddDays(i32_t days)
769 TIMESTAMP_TO_TM(*this, ¤t);
770 time_t adj_time = timegm(¤t);
771 adj_time += 86400 * days;
772 struct tm* now = gmtime(&adj_time);
773 TM_TO_TIMESTAMP(now, *this);
779 Kumu::Timestamp::AddHours(i32_t hours)
785 TIMESTAMP_TO_TM(*this, ¤t);
786 time_t adj_time = timegm(¤t);
787 adj_time += 3600 * hours;
788 struct tm* now = gmtime(&adj_time);
789 TM_TO_TIMESTAMP(now, *this);
796 Kumu::Timestamp::Timestamp(const Timestamp& rhs)
806 Kumu::Timestamp::~Timestamp()
811 const Kumu::Timestamp&
812 Kumu::Timestamp::operator=(const Timestamp& rhs)
825 Kumu::Timestamp::operator==(const Timestamp& rhs) const
827 if ( Year == rhs.Year
828 && Month == rhs.Month
831 && Minute == rhs.Minute
832 && Second == rhs.Second )
840 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
842 if ( Year != rhs.Year
843 || Month != rhs.Month
846 || Minute != rhs.Minute
847 || Second != rhs.Second )
855 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
857 if ( buf_len < ( DateTimeLen + 1 ) )
860 // 2004-05-01T13:20:00-00:00
861 snprintf(str_buf, buf_len,
862 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu-00:00",
863 Year, Month, Day, Hour, Minute, Second);
870 Kumu::Timestamp::DecodeString(const char* datestr)
874 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
876 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
878 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
881 ui32_t char_count = 10;
882 TmpStamp.Year = atoi(datestr);
883 TmpStamp.Month = atoi(datestr + 5);
884 TmpStamp.Day = atoi(datestr + 8);
885 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
887 if ( datestr[10] == 'T' )
889 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
890 || datestr[13] != ':'
891 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
895 TmpStamp.Hour = atoi(datestr + 11);
896 TmpStamp.Minute = atoi(datestr + 14);
898 if ( datestr[16] == ':' )
900 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
904 TmpStamp.Second = atoi(datestr + 17);
907 if ( datestr[19] == '.' )
909 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
912 // we don't carry the ms value
916 if ( datestr[19] == '-' || datestr[19] == '+' )
918 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
919 || datestr[22] != ':'
920 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
924 ui32_t TZ_hh = atoi(datestr + 20);
925 ui32_t TZ_mm = atoi(datestr + 23);
928 DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
934 AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
938 if ( datestr[char_count] != 0 )
940 DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
941 datestr, char_count);
948 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
949 if ( SystemTimeToFileTime(&st, &ft) == 0 )
951 SYSTIME_TO_TIMESTAMP(&st, *this);
954 TIMESTAMP_TO_TM(TmpStamp, &stm);
955 if ( timegm(&stm) == 0 )
957 TM_TO_TIMESTAMP(&stm, *this);
965 Kumu::Timestamp::HasValue() const
967 if ( Year || Month || Day || Hour || Minute || Second )
975 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
978 if ( ! Reader->ReadUi16BE(&Year) ) return false;
979 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
985 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
988 if ( ! Writer->WriteUi16BE(Year) ) return false;
989 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
993 //------------------------------------------------------------------------------------------
995 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
996 : m_p(0), m_capacity(0), m_size(0)
999 m_capacity = Buf->Capacity();
1000 assert(m_p); assert(m_capacity);
1004 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1006 if ( ( m_size + ber_len ) > m_capacity )
1009 if ( ! write_BER(m_p + m_size, i, ber_len) )
1017 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1018 : m_p(0), m_capacity(0), m_size(0)
1020 m_p = Buf->RoData();
1021 m_capacity = Buf->Length();
1022 assert(m_p); assert(m_capacity);
1026 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1028 if ( i == 0 || ber_len == 0 ) return false;
1030 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1033 if ( ( m_size + *ber_len ) > m_capacity )
1036 if ( ! read_BER(m_p + m_size, i) )
1043 //------------------------------------------------------------------------------------------
1045 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1047 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1052 Kumu::ByteString::~ByteString()
1059 // copy the given data into the ByteString, set Length value.
1060 // Returns error if the ByteString is too small.
1062 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1064 if ( m_Capacity < buf_len )
1065 return RESULT_ALLOC;
1067 memcpy(m_Data, buf, buf_len);
1073 // copy the given data into the ByteString, set Length value.
1074 // Returns error if the ByteString is too small.
1076 Kumu::ByteString::Set(const ByteString& Buf)
1078 if ( m_Capacity < Buf.m_Capacity )
1079 return RESULT_ALLOC;
1081 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1082 m_Length = Buf.m_Length;
1087 // Sets the size of the internally allocate buffer.
1089 Kumu::ByteString::Capacity(ui32_t cap_size)
1091 if ( m_Capacity >= cap_size )
1094 byte_t* tmp_data = 0;
1103 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1104 return RESULT_ALLOC;
1106 if ( tmp_data != 0 )
1108 assert(m_Length > 0);
1109 memcpy(m_Data, tmp_data, m_Length);
1113 m_Capacity = cap_size;
1119 Kumu::ByteString::Append(const ByteString& Buf)
1121 Result_t result = RESULT_OK;
1122 ui32_t diff = m_Capacity - m_Length;
1124 if ( diff < Buf.Length() )
1125 result = Capacity(m_Capacity + Buf.Length());
1127 if ( KM_SUCCESS(result) )
1129 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1130 m_Length += Buf.Length();
1138 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1140 Result_t result = RESULT_OK;
1141 ui32_t diff = m_Capacity - m_Length;
1143 if ( diff < buf_len )
1144 result = Capacity(m_Capacity + buf_len);
1146 if ( KM_SUCCESS(result) )
1148 memcpy(m_Data + m_Length, buf, buf_len);
1149 m_Length += buf_len;