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.
544 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
549 if ( ( **buf & 0x80 ) == 0 )
553 ui8_t ber_size = ( **buf & 0x0f ) + 1;
558 for ( ui8_t i = 1; i < ber_size; i++ )
561 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
565 return ( val == test_value );
571 Kumu::read_BER(const byte_t* buf, ui64_t* val)
575 if ( buf == 0 || val == 0 )
578 if ( ( *buf & 0x80 ) == 0 )
582 ber_size = ( *buf & 0x0f ) + 1;
587 for ( i = 1; i < ber_size; i++ )
590 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
597 static const ui64_t ber_masks[9] =
598 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
599 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
600 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
601 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
607 Kumu::get_BER_length_for_value(ui64_t val)
609 for ( ui32_t i = 0; i < 9; i++ )
611 if ( ( val & ber_masks[i] ) == 0 )
615 ui64Printer tmp_i(val);
616 DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
622 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
628 { // calculate default length
629 if ( val < 0x01000000L )
631 else if ( val < ui64_C(0x0100000000000000) )
637 { // sanity check BER length
640 DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len);
644 if ( ( val & ber_masks[ber_len - 1] ) != 0 )
646 ui64Printer tmp_i(val);
647 DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str());
652 buf[0] = 0x80 + ( ber_len - 1 );
654 for ( ui32_t i = ber_len - 1; i > 0; i-- )
656 buf[i] = (ui8_t)(val & 0xff);
664 //------------------------------------------------------------------------------------------
667 #define TIMESTAMP_TO_SYSTIME(ts, t) \
668 (t)->wYear = (ts).Year; /* year */ \
669 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
670 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
671 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
672 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
673 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
674 (t)->wDayOfWeek = 0; \
675 (t)->wMilliseconds = 0
677 #define SYSTIME_TO_TIMESTAMP(t, ts) \
678 (ts).Year = (t)->wYear; /* year */ \
679 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
680 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
681 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
682 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
683 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
686 Kumu::Timestamp::Timestamp() :
687 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
690 GetSystemTime(&sys_time);
691 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
696 Kumu::Timestamp::operator<(const Timestamp& rhs) const
698 SYSTEMTIME lhst, rhst;
701 TIMESTAMP_TO_SYSTIME(*this, &lhst);
702 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
703 SystemTimeToFileTime(&lhst, &lft);
704 SystemTimeToFileTime(&rhst, &rft);
705 return ( CompareFileTime(&lft, &rft) == -1 );
710 Kumu::Timestamp::operator>(const Timestamp& rhs) const
712 SYSTEMTIME lhst, rhst;
715 TIMESTAMP_TO_SYSTIME(*this, &lhst);
716 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
717 SystemTimeToFileTime(&lhst, &lft);
718 SystemTimeToFileTime(&rhst, &rft);
719 return ( CompareFileTime(&lft, &rft) == 1 );
723 seconds_to_ns100(ui32_t seconds)
725 return ((ui64_t)seconds * 10000000);
730 Kumu::Timestamp::AddDays(i32_t days)
732 SYSTEMTIME current_st;
734 ULARGE_INTEGER current_ul;
738 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
739 SystemTimeToFileTime(¤t_st, ¤t_ft);
740 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
741 current_ul.QuadPart += ( seconds_to_ns100(86400) * (i64_t)days );
742 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
743 FileTimeToSystemTime(¤t_ft, ¤t_st);
744 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
750 Kumu::Timestamp::AddHours(i32_t hours)
752 SYSTEMTIME current_st;
754 ULARGE_INTEGER current_ul;
758 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
759 SystemTimeToFileTime(¤t_st, ¤t_ft);
760 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
761 current_ul.QuadPart += ( seconds_to_ns100(3600) * (i64_t)hours );
762 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
763 FileTimeToSystemTime(¤t_ft, ¤t_st);
764 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
770 Kumu::Timestamp::AddMinutes(i32_t minutes)
772 SYSTEMTIME current_st;
774 ULARGE_INTEGER current_ul;
778 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
779 SystemTimeToFileTime(¤t_st, ¤t_ft);
780 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
781 current_ul.QuadPart += ( seconds_to_ns100(60) * (i64_t)minutes );
782 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
783 FileTimeToSystemTime(¤t_ft, ¤t_st);
784 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
790 Kumu::Timestamp::AddSeconds(i32_t seconds)
792 SYSTEMTIME current_st;
794 ULARGE_INTEGER current_ul;
798 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
799 SystemTimeToFileTime(¤t_st, ¤t_ft);
800 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
801 current_ul.QuadPart += ( seconds_to_ns100(1) * (i64_t)seconds );
802 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
803 FileTimeToSystemTime(¤t_ft, ¤t_st);
804 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
812 #define TIMESTAMP_TO_CALTIME(ts, ct) \
813 (ct)->date.year = (ts).Year; /* year */ \
814 (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \
815 (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \
816 (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \
817 (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \
818 (ct)->second = (ts).Second; /* seconds (0 - 60) */ \
821 #define CALTIME_TO_TIMESTAMP(ct, ts) \
822 assert((ct)->offset == 0); \
823 (ts).Year = (ct)->date.year; /* year */ \
824 (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \
825 (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \
826 (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \
827 (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \
828 (ts).Second = (ct)->second; /* seconds (0 - 60) */
832 Kumu::Timestamp::Timestamp() :
833 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
836 Kumu::TAI::caltime ct;
839 CALTIME_TO_TIMESTAMP(&ct, *this)
844 Kumu::Timestamp::operator<(const Timestamp& rhs) const
846 Kumu::TAI::caltime lh_ct, rh_ct;
847 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
848 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
850 Kumu::TAI::tai lh_tai, rh_tai;
854 return ( lh_tai.x < rh_tai.x );
859 Kumu::Timestamp::operator>(const Timestamp& rhs) const
861 Kumu::TAI::caltime lh_ct, rh_ct;
862 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
863 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
865 Kumu::TAI::tai lh_tai, rh_tai;
869 return ( lh_tai.x > rh_tai.x );
874 Kumu::Timestamp::AddDays(i32_t days)
876 Kumu::TAI::caltime ct;
881 TIMESTAMP_TO_CALTIME(*this, &ct)
885 CALTIME_TO_TIMESTAMP(&ct, *this)
891 Kumu::Timestamp::AddHours(i32_t hours)
893 Kumu::TAI::caltime ct;
898 TIMESTAMP_TO_CALTIME(*this, &ct)
902 CALTIME_TO_TIMESTAMP(&ct, *this)
908 Kumu::Timestamp::AddMinutes(i32_t minutes)
910 Kumu::TAI::caltime ct;
915 TIMESTAMP_TO_CALTIME(*this, &ct)
917 t.add_minutes(minutes);
919 CALTIME_TO_TIMESTAMP(&ct, *this)
925 Kumu::Timestamp::AddSeconds(i32_t seconds)
927 Kumu::TAI::caltime ct;
932 TIMESTAMP_TO_CALTIME(*this, &ct)
934 t.add_seconds(seconds);
936 CALTIME_TO_TIMESTAMP(&ct, *this)
943 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
953 Kumu::Timestamp::~Timestamp()
958 const Kumu::Timestamp&
959 Kumu::Timestamp::operator=(const Timestamp& rhs)
972 Kumu::Timestamp::operator==(const Timestamp& rhs) const
974 if ( Year == rhs.Year
975 && Month == rhs.Month
978 && Minute == rhs.Minute
979 && Second == rhs.Second )
987 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
989 if ( Year != rhs.Year
990 || Month != rhs.Month
993 || Minute != rhs.Minute
994 || Second != rhs.Second )
1002 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
1004 return EncodeStringWithOffset(str_buf, buf_len, 0);
1009 Kumu::Timestamp::EncodeStringWithOffset(char* str_buf, ui32_t buf_len,
1010 i32_t offset_minutes) const
1012 if ( buf_len < ( DateTimeLen + 1 ) )
1015 // ensure offset is within +/- 14 hours
1016 if ((offset_minutes < -14 * 60) || (offset_minutes > 14 * 60))
1019 // set the apparent time
1020 Kumu::Timestamp tmp_t(*this);
1021 tmp_t.AddMinutes(offset_minutes);
1023 char direction = '+';
1024 if (offset_minutes < 0) {
1026 // need absolute offset from zero
1027 offset_minutes = -offset_minutes;
1030 // 2004-05-01T13:20:00+00:00
1031 snprintf(str_buf, buf_len,
1032 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
1033 tmp_t.Year, tmp_t.Month, tmp_t.Day,
1034 tmp_t.Hour, tmp_t.Minute, tmp_t.Second,
1036 offset_minutes / 60,
1037 offset_minutes % 60);
1044 Kumu::Timestamp::DecodeString(const char* datestr)
1048 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
1049 || datestr[4] != '-'
1050 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
1051 || datestr[7] != '-'
1052 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
1055 ui32_t char_count = 10;
1056 TmpStamp.Year = atoi(datestr);
1057 TmpStamp.Month = atoi(datestr + 5);
1058 TmpStamp.Day = atoi(datestr + 8);
1059 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
1061 if ( datestr[10] == 'T' )
1063 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
1064 || datestr[13] != ':'
1065 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
1069 TmpStamp.Hour = atoi(datestr + 11);
1070 TmpStamp.Minute = atoi(datestr + 14);
1072 if ( datestr[16] == ':' )
1074 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
1078 TmpStamp.Second = atoi(datestr + 17);
1081 if ( datestr[19] == '.' )
1083 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
1086 // we don't carry the ms value
1090 if ( datestr[19] == '-' || datestr[19] == '+' )
1092 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
1093 || datestr[22] != ':'
1094 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
1099 ui32_t TZ_hh = atoi(datestr + 20);
1100 ui32_t TZ_mm = atoi(datestr + 23);
1101 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
1104 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
1105 if (datestr[19] == '-')
1106 TZ_offset = -TZ_offset;
1107 /* at this point, TZ_offset reflects the contents of the string */
1109 /* a negative offset is behind UTC and so needs to increment to
1110 * convert, while a positive offset must do the reverse */
1111 TmpStamp.AddMinutes(-TZ_offset);
1113 else if (datestr[19] == 'Z')
1115 /* act as if the offset were +00:00 */
1120 if ( datestr[char_count] != 0 )
1122 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
1123 datestr, char_count);
1130 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
1131 if ( SystemTimeToFileTime(&st, &ft) == 0 )
1133 SYSTIME_TO_TIMESTAMP(&st, *this);
1136 Kumu::TAI::caltime ct;
1137 TIMESTAMP_TO_CALTIME(TmpStamp, &ct);
1138 t = ct; // back and forth to tai to normalize offset
1140 CALTIME_TO_TIMESTAMP(&ct, *this)
1148 Kumu::Timestamp::HasValue() const
1150 if ( Year || Month || Day || Hour || Minute || Second )
1158 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
1161 if ( ! Reader->ReadUi16BE(&Year) ) return false;
1162 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
1168 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1171 if ( ! Writer->WriteUi16BE(Year) ) return false;
1172 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1178 Kumu::Timestamp::GetSecondsSinceEpoch(void) const
1182 TIMESTAMP_TO_SYSTIME(*this, &timeST);
1184 SystemTimeToFileTime(&timeST, &timeFT);
1185 ULARGE_INTEGER timeUL;
1186 timeUL.LowPart = timeFT.dwLowDateTime;
1187 timeUL.HighPart = timeFT.dwHighDateTime;
1190 epochST.wYear = 1970;
1192 epochST.wDayOfWeek = 4;
1195 epochST.wMinute = 0;
1196 epochST.wSecond = 0;
1197 epochST.wMilliseconds = 0;
1199 SystemTimeToFileTime(&epochST, &epochFT);
1200 ULARGE_INTEGER epochUL;
1201 epochUL.LowPart = epochFT.dwLowDateTime;
1202 epochUL.HighPart = epochFT.dwHighDateTime;
1204 return (timeUL.QuadPart - epochUL.QuadPart) / 10000000;
1206 Kumu::TAI::caltime ct;
1208 TIMESTAMP_TO_CALTIME(*this, &ct);
1211 return (long) (t.x - ui64_C(4611686018427387914));
1215 //------------------------------------------------------------------------------------------
1217 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1218 : m_p(0), m_capacity(0), m_size(0)
1221 m_capacity = Buf->Capacity();
1222 assert(m_p); assert(m_capacity);
1226 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1228 if ( ( m_size + ber_len ) > m_capacity )
1231 if ( ! write_BER(m_p + m_size, i, ber_len) )
1239 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1240 : m_p(0), m_capacity(0), m_size(0)
1242 m_p = Buf->RoData();
1243 m_capacity = Buf->Length();
1244 assert(m_p); assert(m_capacity);
1248 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1250 if ( i == 0 || ber_len == 0 ) return false;
1252 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1255 if ( ( m_size + *ber_len ) > m_capacity )
1258 if ( ! read_BER(m_p + m_size, i) )
1265 //------------------------------------------------------------------------------------------
1267 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1269 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1274 Kumu::ByteString::~ByteString()
1281 // copy the given data into the ByteString, set Length value.
1282 // Returns error if the ByteString is too small.
1284 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1286 if ( m_Capacity < buf_len )
1287 return RESULT_ALLOC;
1289 memcpy(m_Data, buf, buf_len);
1295 // copy the given data into the ByteString, set Length value.
1296 // Returns error if the ByteString is too small.
1298 Kumu::ByteString::Set(const ByteString& Buf)
1300 if ( m_Capacity < Buf.m_Capacity )
1301 return RESULT_ALLOC;
1303 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1304 m_Length = Buf.m_Length;
1309 // Sets the size of the internally allocate buffer.
1311 Kumu::ByteString::Capacity(ui32_t cap_size)
1313 if ( m_Capacity >= cap_size )
1316 byte_t* tmp_data = 0;
1325 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1326 return RESULT_ALLOC;
1328 if ( tmp_data != 0 )
1330 assert(m_Length > 0);
1331 memcpy(m_Data, tmp_data, m_Length);
1335 m_Capacity = cap_size;
1341 Kumu::ByteString::Append(const ByteString& Buf)
1343 Result_t result = RESULT_OK;
1344 ui32_t diff = m_Capacity - m_Length;
1346 if ( diff < Buf.Length() )
1347 result = Capacity(m_Capacity + Buf.Length());
1349 if ( KM_SUCCESS(result) )
1351 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1352 m_Length += Buf.Length();
1360 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1362 Result_t result = RESULT_OK;
1363 ui32_t diff = m_Capacity - m_Length;
1365 if ( diff < buf_len )
1366 result = Capacity(m_Capacity + buf_len);
1368 if ( KM_SUCCESS(result) )
1370 memcpy(m_Data + m_Length, buf, buf_len);
1371 m_Length += buf_len;