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>
45 return PACKAGE_VERSION;
49 //------------------------------------------------------------------------------------------
56 Kumu::Result_t* result;
59 const ui32_t MapMax = 1024;
60 const ui32_t MapSize = MapMax * (sizeof(struct map_entry_t));
61 static bool s_MapInit = false;
62 static struct map_entry_t s_ResultMap[MapSize];
66 Kumu::Result_t::Find(int v)
71 for ( ui32_t i = 0; s_ResultMap[i].result != 0 && i < MapMax; i++ )
73 if ( s_ResultMap[i].rcode == v )
74 return *s_ResultMap[i].result;
77 DefaultLogSink().Error("Unknown result code: %ld\n", v);
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;
376 // convert a memory region to a NULL-terminated hexadecimal string
379 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
383 || ((bin_len * 2) + 1) > str_len )
388 for ( ui32_t i = 0; i < bin_len; i++ )
390 *p = (bin_buf[i] >> 4) & 0x0f;
391 *p += *p < 10 ? 0x30 : 0x61 - 10;
394 *p = bin_buf[i] & 0x0f;
395 *p += *p < 10 ? 0x30 : 0x61 - 10;
404 // spew a range of bin data as hex
406 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
414 static ui32_t row_len = 16;
415 const byte_t* p = buf;
416 const byte_t* end_p = p + dump_len;
418 for ( ui32_t line = 0; p < end_p; line++ )
420 fprintf(stream, " %06x: ", line);
424 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
425 fprintf(stream, "%02x ", *pp);
427 while ( i++ < row_len )
430 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
431 fputc((isprint(*pp) ? *pp : '.'), stream);
440 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
444 if ( str_len < 34 || bin_len != UUID_Length )
447 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
451 for ( k = 19, i = 12; i > 0; i-- )
452 str_buf[k+i+4] = str_buf[k+i];
454 // shift the time (mid+hi+clk)
455 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
457 for ( i = 4; i > 0; i-- )
458 str_buf[k+i+j] = str_buf[k+i];
461 // add in the hyphens and trainling null
462 for ( i = 8; i < 24; i += 5 )
471 Kumu::GenRandomValue(UUID& ID)
473 byte_t tmp_buf[UUID_Length];
474 GenRandomUUID(tmp_buf);
480 Kumu::GenRandomUUID(byte_t* buf)
483 RNG.FillRandom(buf, UUID_Length);
484 buf[6] &= 0x0f; // clear bits 4-7
485 buf[6] |= 0x40; // set UUID version
486 buf[8] &= 0x3f; // clear bits 6&7
487 buf[8] |= 0x80; // set bit 7
492 Kumu::GenRandomValue(SymmetricKey& Key)
494 byte_t tmp_buf[SymmetricKey_Length];
496 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
501 //------------------------------------------------------------------------------------------
502 // read a ber value from the buffer and compare with test value.
503 // Advances buffer to first character after BER value.
505 // read a ber value from the buffer and compare with test value.
506 // Advances buffer to first character after BER value.
509 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
514 if ( ( **buf & 0x80 ) == 0 )
518 ui8_t ber_size = ( **buf & 0x0f ) + 1;
523 for ( ui8_t i = 1; i < ber_size; i++ )
526 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
530 return ( val == test_value );
536 Kumu::read_BER(const byte_t* buf, ui64_t* val)
540 if ( buf == 0 || val == 0 )
543 if ( ( *buf & 0x80 ) == 0 )
547 ber_size = ( *buf & 0x0f ) + 1;
552 for ( i = 1; i < ber_size; i++ )
555 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
562 static const ui64_t ber_masks[9] =
563 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
564 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
565 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
566 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
573 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
579 { // calculate default length
580 if ( val < 0x01000000L )
582 else if ( val < ui64_C(0x0100000000000000) )
588 { // sanity check BER length
591 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
595 if ( val & ber_masks[ber_len - 1] )
597 ui64Printer tmp_i(val);
598 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
603 buf[0] = 0x80 + ( ber_len - 1 );
605 for ( ui32_t i = ber_len - 1; i > 0; i-- )
607 buf[i] = (ui8_t)(val & 0xff);
615 //------------------------------------------------------------------------------------------
618 #define TIMESTAMP_TO_SYSTIME(ts, t) \
619 (t)->wYear = (ts).Year; /* year */ \
620 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
621 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
622 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
623 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
624 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
625 (t)->wDayOfWeek = 0; \
626 (t)->wMilliseconds = 0
628 #define SYSTIME_TO_TIMESTAMP(t, ts) \
629 (ts).Year = (t)->wYear; /* year */ \
630 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
631 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
632 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
633 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
634 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
637 Kumu::Timestamp::Timestamp() :
638 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
641 GetSystemTime(&sys_time);
642 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
647 Kumu::Timestamp::operator<(const Timestamp& rhs) const
649 SYSTEMTIME lhst, rhst;
652 TIMESTAMP_TO_SYSTIME(*this, &lhst);
653 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
654 SystemTimeToFileTime(&lhst, &lft);
655 SystemTimeToFileTime(&rhst, &rft);
656 return ( CompareFileTime(&lft, &rft) == -1 );
661 Kumu::Timestamp::operator>(const Timestamp& rhs) const
663 SYSTEMTIME lhst, rhst;
666 TIMESTAMP_TO_SYSTIME(*this, &lhst);
667 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
668 SystemTimeToFileTime(&lhst, &lft);
669 SystemTimeToFileTime(&rhst, &rft);
670 return ( CompareFileTime(&lft, &rft) == 1 );
674 seconds_to_ns100(ui32_t seconds)
676 return ((ui64_t)seconds * 10000000);
681 Kumu::Timestamp::AddDays(i32_t days)
683 SYSTEMTIME current_st;
685 ULARGE_INTEGER current_ul;
689 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
690 SystemTimeToFileTime(¤t_st, ¤t_ft);
691 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
692 current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
693 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
694 FileTimeToSystemTime(¤t_ft, ¤t_st);
695 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
701 Kumu::Timestamp::AddHours(i32_t hours)
703 SYSTEMTIME current_st;
705 ULARGE_INTEGER current_ul;
709 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
710 SystemTimeToFileTime(¤t_st, ¤t_ft);
711 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
712 current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
713 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
714 FileTimeToSystemTime(¤t_ft, ¤t_st);
715 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
723 #define TIMESTAMP_TO_TM(ts, t) \
724 (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \
725 (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \
726 (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \
727 (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \
728 (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \
729 (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */
731 #define TM_TO_TIMESTAMP(t, ts) \
732 (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \
733 (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \
734 (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \
735 (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \
736 (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \
737 (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */
740 Kumu::Timestamp::Timestamp() :
741 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
743 time_t t_now = time(0);
744 struct tm* now = gmtime(&t_now);
745 TM_TO_TIMESTAMP(now, *this);
750 Kumu::Timestamp::operator<(const Timestamp& rhs) const
752 struct tm lhtm, rhtm;
753 TIMESTAMP_TO_TM(*this, &lhtm);
754 TIMESTAMP_TO_TM(rhs, &rhtm);
755 return ( timegm(&lhtm) < timegm(&rhtm) );
760 Kumu::Timestamp::operator>(const Timestamp& rhs) const
762 struct tm lhtm, rhtm;
763 TIMESTAMP_TO_TM(*this, &lhtm);
764 TIMESTAMP_TO_TM(rhs, &rhtm);
765 return ( timegm(&lhtm) > timegm(&rhtm) );
770 Kumu::Timestamp::AddDays(i32_t days)
776 TIMESTAMP_TO_TM(*this, ¤t);
777 time_t adj_time = timegm(¤t);
778 adj_time += 86400 * days;
779 struct tm* now = gmtime(&adj_time);
780 TM_TO_TIMESTAMP(now, *this);
786 Kumu::Timestamp::AddHours(i32_t hours)
792 TIMESTAMP_TO_TM(*this, ¤t);
793 time_t adj_time = timegm(¤t);
794 adj_time += 3600 * hours;
795 struct tm* now = gmtime(&adj_time);
796 TM_TO_TIMESTAMP(now, *this);
803 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
813 Kumu::Timestamp::~Timestamp()
818 const Kumu::Timestamp&
819 Kumu::Timestamp::operator=(const Timestamp& rhs)
832 Kumu::Timestamp::operator==(const Timestamp& rhs) const
834 if ( Year == rhs.Year
835 && Month == rhs.Month
838 && Minute == rhs.Minute
839 && Second == rhs.Second )
847 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
849 if ( Year != rhs.Year
850 || Month != rhs.Month
853 || Minute != rhs.Minute
854 || Second != rhs.Second )
862 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
864 if ( buf_len < ( DateTimeLen + 1 ) )
867 // 2004-05-01T13:20:00-00:00
868 snprintf(str_buf, buf_len,
869 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu+00:00",
870 Year, Month, Day, Hour, Minute, Second);
877 Kumu::Timestamp::DecodeString(const char* datestr)
881 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
883 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
885 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
888 ui32_t char_count = 10;
889 TmpStamp.Year = atoi(datestr);
890 TmpStamp.Month = atoi(datestr + 5);
891 TmpStamp.Day = atoi(datestr + 8);
892 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
894 if ( datestr[10] == 'T' )
896 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
897 || datestr[13] != ':'
898 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
902 TmpStamp.Hour = atoi(datestr + 11);
903 TmpStamp.Minute = atoi(datestr + 14);
905 if ( datestr[16] == ':' )
907 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
911 TmpStamp.Second = atoi(datestr + 17);
914 if ( datestr[19] == '.' )
916 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
919 // we don't carry the ms value
923 if ( datestr[19] == '-' || datestr[19] == '+' )
925 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
926 || datestr[22] != ':'
927 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
931 ui32_t TZ_hh = atoi(datestr + 20);
932 ui32_t TZ_mm = atoi(datestr + 23);
935 DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm);
941 AddHours( (datestr[19] == '-' ? (0 - TZ_hh) : TZ_hh));
945 if ( datestr[char_count] != 0 )
947 DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
948 datestr, char_count);
955 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
956 if ( SystemTimeToFileTime(&st, &ft) == 0 )
958 SYSTIME_TO_TIMESTAMP(&st, *this);
961 TIMESTAMP_TO_TM(TmpStamp, &stm);
962 if ( timegm(&stm) == 0 )
964 TM_TO_TIMESTAMP(&stm, *this);
972 Kumu::Timestamp::HasValue() const
974 if ( Year || Month || Day || Hour || Minute || Second )
982 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
985 if ( ! Reader->ReadUi16BE(&Year) ) return false;
986 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
992 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
995 if ( ! Writer->WriteUi16BE(Year) ) return false;
996 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1000 //------------------------------------------------------------------------------------------
1002 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1003 : m_p(0), m_capacity(0), m_size(0)
1006 m_capacity = Buf->Capacity();
1007 assert(m_p); assert(m_capacity);
1011 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1013 if ( ( m_size + ber_len ) > m_capacity )
1016 if ( ! write_BER(m_p + m_size, i, ber_len) )
1024 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1025 : m_p(0), m_capacity(0), m_size(0)
1027 m_p = Buf->RoData();
1028 m_capacity = Buf->Length();
1029 assert(m_p); assert(m_capacity);
1033 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1035 if ( i == 0 || ber_len == 0 ) return false;
1037 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1040 if ( ( m_size + *ber_len ) > m_capacity )
1043 if ( ! read_BER(m_p + m_size, i) )
1050 //------------------------------------------------------------------------------------------
1052 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1054 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1059 Kumu::ByteString::~ByteString()
1066 // copy the given data into the ByteString, set Length value.
1067 // Returns error if the ByteString is too small.
1069 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1071 if ( m_Capacity < buf_len )
1072 return RESULT_ALLOC;
1074 memcpy(m_Data, buf, buf_len);
1080 // copy the given data into the ByteString, set Length value.
1081 // Returns error if the ByteString is too small.
1083 Kumu::ByteString::Set(const ByteString& Buf)
1085 if ( m_Capacity < Buf.m_Capacity )
1086 return RESULT_ALLOC;
1088 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1089 m_Length = Buf.m_Length;
1094 // Sets the size of the internally allocate buffer.
1096 Kumu::ByteString::Capacity(ui32_t cap_size)
1098 if ( m_Capacity >= cap_size )
1101 byte_t* tmp_data = 0;
1110 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1111 return RESULT_ALLOC;
1113 if ( tmp_data != 0 )
1115 assert(m_Length > 0);
1116 memcpy(m_Data, tmp_data, m_Length);
1120 m_Capacity = cap_size;
1126 Kumu::ByteString::Append(const ByteString& Buf)
1128 Result_t result = RESULT_OK;
1129 ui32_t diff = m_Capacity - m_Length;
1131 if ( diff < Buf.Length() )
1132 result = Capacity(m_Capacity + Buf.Length());
1134 if ( KM_SUCCESS(result) )
1136 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1137 m_Length += Buf.Length();
1145 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1147 Result_t result = RESULT_OK;
1148 ui32_t diff = m_Capacity - m_Length;
1150 if ( diff < buf_len )
1151 result = Capacity(m_Capacity + buf_len);
1153 if ( KM_SUCCESS(result) )
1155 memcpy(m_Data + m_Length, buf, buf_len);
1156 m_Length += buf_len;