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.
543 // read a ber value from the buffer and compare with test value.
544 // Advances buffer to first character after BER value.
547 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
552 if ( ( **buf & 0x80 ) == 0 )
556 ui8_t ber_size = ( **buf & 0x0f ) + 1;
561 for ( ui8_t i = 1; i < ber_size; i++ )
564 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
568 return ( val == test_value );
574 Kumu::read_BER(const byte_t* buf, ui64_t* val)
578 if ( buf == 0 || val == 0 )
581 if ( ( *buf & 0x80 ) == 0 )
585 ber_size = ( *buf & 0x0f ) + 1;
590 for ( i = 1; i < ber_size; i++ )
593 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
600 static const ui64_t ber_masks[9] =
601 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
602 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
603 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
604 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
611 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
617 { // calculate default length
618 if ( val < 0x01000000L )
620 else if ( val < ui64_C(0x0100000000000000) )
626 { // sanity check BER length
629 DefaultLogSink().Error("BER size %u exceeds maximum size of 9\n", ber_len);
633 if ( val & ber_masks[ber_len - 1] )
635 ui64Printer tmp_i(val);
636 DefaultLogSink().Error("BER size %u too small for value %s\n", tmp_i.c_str());
641 buf[0] = 0x80 + ( ber_len - 1 );
643 for ( ui32_t i = ber_len - 1; i > 0; i-- )
645 buf[i] = (ui8_t)(val & 0xff);
653 //------------------------------------------------------------------------------------------
656 #define TIMESTAMP_TO_SYSTIME(ts, t) \
657 (t)->wYear = (ts).Year; /* year */ \
658 (t)->wMonth = (ts).Month; /* month of year (1 - 12) */ \
659 (t)->wDay = (ts).Day; /* day of month (1 - 31) */ \
660 (t)->wHour = (ts).Hour; /* hours (0 - 23) */ \
661 (t)->wMinute = (ts).Minute; /* minutes (0 - 59) */ \
662 (t)->wSecond = (ts).Second; /* seconds (0 - 60) */ \
663 (t)->wDayOfWeek = 0; \
664 (t)->wMilliseconds = 0
666 #define SYSTIME_TO_TIMESTAMP(t, ts) \
667 (ts).Year = (t)->wYear; /* year */ \
668 (ts).Month = (t)->wMonth; /* month of year (1 - 12) */ \
669 (ts).Day = (t)->wDay; /* day of month (1 - 31) */ \
670 (ts).Hour = (t)->wHour; /* hours (0 - 23) */ \
671 (ts).Minute = (t)->wMinute; /* minutes (0 - 59) */ \
672 (ts).Second = (t)->wSecond; /* seconds (0 - 60) */
675 Kumu::Timestamp::Timestamp() :
676 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
679 GetSystemTime(&sys_time);
680 SYSTIME_TO_TIMESTAMP(&sys_time, *this);
685 Kumu::Timestamp::operator<(const Timestamp& rhs) const
687 SYSTEMTIME lhst, rhst;
690 TIMESTAMP_TO_SYSTIME(*this, &lhst);
691 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
692 SystemTimeToFileTime(&lhst, &lft);
693 SystemTimeToFileTime(&rhst, &rft);
694 return ( CompareFileTime(&lft, &rft) == -1 );
699 Kumu::Timestamp::operator>(const Timestamp& rhs) const
701 SYSTEMTIME lhst, rhst;
704 TIMESTAMP_TO_SYSTIME(*this, &lhst);
705 TIMESTAMP_TO_SYSTIME(rhs, &rhst);
706 SystemTimeToFileTime(&lhst, &lft);
707 SystemTimeToFileTime(&rhst, &rft);
708 return ( CompareFileTime(&lft, &rft) == 1 );
712 seconds_to_ns100(ui32_t seconds)
714 return ((ui64_t)seconds * 10000000);
719 Kumu::Timestamp::AddDays(i32_t days)
721 SYSTEMTIME current_st;
723 ULARGE_INTEGER current_ul;
727 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
728 SystemTimeToFileTime(¤t_st, ¤t_ft);
729 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
730 current_ul.QuadPart += ( seconds_to_ns100(86400) * (i64_t)days );
731 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
732 FileTimeToSystemTime(¤t_ft, ¤t_st);
733 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
739 Kumu::Timestamp::AddHours(i32_t hours)
741 SYSTEMTIME current_st;
743 ULARGE_INTEGER current_ul;
747 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
748 SystemTimeToFileTime(¤t_st, ¤t_ft);
749 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
750 current_ul.QuadPart += ( seconds_to_ns100(3600) * (i64_t)hours );
751 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
752 FileTimeToSystemTime(¤t_ft, ¤t_st);
753 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
759 Kumu::Timestamp::AddMinutes(i32_t minutes)
761 SYSTEMTIME current_st;
763 ULARGE_INTEGER current_ul;
767 TIMESTAMP_TO_SYSTIME(*this, ¤t_st);
768 SystemTimeToFileTime(¤t_st, ¤t_ft);
769 memcpy(¤t_ul, ¤t_ft, sizeof(current_ul));
770 current_ul.QuadPart += ( seconds_to_ns100(60) * (i64_t)minutes );
771 memcpy(¤t_ft, ¤t_ul, sizeof(current_ft));
772 FileTimeToSystemTime(¤t_ft, ¤t_st);
773 SYSTIME_TO_TIMESTAMP(¤t_st, *this);
781 #define TIMESTAMP_TO_CALTIME(ts, ct) \
782 (ct)->date.year = (ts).Year; /* year */ \
783 (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \
784 (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \
785 (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \
786 (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \
787 (ct)->second = (ts).Second; /* seconds (0 - 60) */ \
790 #define CALTIME_TO_TIMESTAMP(ct, ts) \
791 assert((ct)->offset == 0); \
792 (ts).Year = (ct)->date.year; /* year */ \
793 (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \
794 (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \
795 (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \
796 (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \
797 (ts).Second = (ct)->second; /* seconds (0 - 60) */
801 Kumu::Timestamp::Timestamp() :
802 Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0)
805 Kumu::TAI::caltime ct;
808 CALTIME_TO_TIMESTAMP(&ct, *this)
813 Kumu::Timestamp::operator<(const Timestamp& rhs) const
815 Kumu::TAI::caltime lh_ct, rh_ct;
816 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
817 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
819 Kumu::TAI::tai lh_tai, rh_tai;
823 return ( lh_tai.x < rh_tai.x );
828 Kumu::Timestamp::operator>(const Timestamp& rhs) const
830 Kumu::TAI::caltime lh_ct, rh_ct;
831 TIMESTAMP_TO_CALTIME(*this, &lh_ct)
832 TIMESTAMP_TO_CALTIME(rhs, &rh_ct)
834 Kumu::TAI::tai lh_tai, rh_tai;
838 return ( lh_tai.x > rh_tai.x );
843 Kumu::Timestamp::AddDays(i32_t days)
845 Kumu::TAI::caltime ct;
850 TIMESTAMP_TO_CALTIME(*this, &ct)
854 CALTIME_TO_TIMESTAMP(&ct, *this)
860 Kumu::Timestamp::AddHours(i32_t hours)
862 Kumu::TAI::caltime ct;
867 TIMESTAMP_TO_CALTIME(*this, &ct)
871 CALTIME_TO_TIMESTAMP(&ct, *this)
877 Kumu::Timestamp::AddMinutes(i32_t minutes)
879 Kumu::TAI::caltime ct;
884 TIMESTAMP_TO_CALTIME(*this, &ct)
886 t.add_minutes(minutes);
888 CALTIME_TO_TIMESTAMP(&ct, *this)
895 Kumu::Timestamp::Timestamp(const Timestamp& rhs) : IArchive()
905 Kumu::Timestamp::~Timestamp()
910 const Kumu::Timestamp&
911 Kumu::Timestamp::operator=(const Timestamp& rhs)
924 Kumu::Timestamp::operator==(const Timestamp& rhs) const
926 if ( Year == rhs.Year
927 && Month == rhs.Month
930 && Minute == rhs.Minute
931 && Second == rhs.Second )
939 Kumu::Timestamp::operator!=(const Timestamp& rhs) const
941 if ( Year != rhs.Year
942 || Month != rhs.Month
945 || Minute != rhs.Minute
946 || Second != rhs.Second )
954 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
956 return EncodeStringWithOffset(str_buf, buf_len, 0);
961 Kumu::Timestamp::EncodeStringWithOffset(char* str_buf, ui32_t buf_len,
962 i32_t offset_minutes) const
964 if ( buf_len < ( DateTimeLen + 1 ) )
967 // ensure offset is within +/- 14 hours
968 if ((offset_minutes < -14 * 60) || (offset_minutes > 14 * 60))
971 // set the apparent time
972 Kumu::Timestamp tmp_t(*this);
973 tmp_t.AddMinutes(offset_minutes);
975 char direction = '+';
976 if (offset_minutes < 0) {
978 // need absolute offset from zero
979 offset_minutes = -offset_minutes;
982 // 2004-05-01T13:20:00+00:00
983 snprintf(str_buf, buf_len,
984 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
985 tmp_t.Year, tmp_t.Month, tmp_t.Day,
986 tmp_t.Hour, tmp_t.Minute, tmp_t.Second,
989 offset_minutes % 60);
996 Kumu::Timestamp::DecodeString(const char* datestr)
1000 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
1001 || datestr[4] != '-'
1002 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
1003 || datestr[7] != '-'
1004 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
1007 ui32_t char_count = 10;
1008 TmpStamp.Year = atoi(datestr);
1009 TmpStamp.Month = atoi(datestr + 5);
1010 TmpStamp.Day = atoi(datestr + 8);
1011 TmpStamp.Hour = TmpStamp.Minute = TmpStamp.Second = 0;
1013 if ( datestr[10] == 'T' )
1015 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
1016 || datestr[13] != ':'
1017 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
1021 TmpStamp.Hour = atoi(datestr + 11);
1022 TmpStamp.Minute = atoi(datestr + 14);
1024 if ( datestr[16] == ':' )
1026 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
1030 TmpStamp.Second = atoi(datestr + 17);
1033 if ( datestr[19] == '.' )
1035 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
1038 // we don't carry the ms value
1042 if ( datestr[19] == '-' || datestr[19] == '+' )
1044 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
1045 || datestr[22] != ':'
1046 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
1051 ui32_t TZ_hh = atoi(datestr + 20);
1052 ui32_t TZ_mm = atoi(datestr + 23);
1053 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
1056 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
1057 if (datestr[19] == '-')
1058 TZ_offset = -TZ_offset;
1059 /* at this point, TZ_offset reflects the contents of the string */
1061 /* a negative offset is behind UTC and so needs to increment to
1062 * convert, while a positive offset must do the reverse */
1063 TmpStamp.AddMinutes(-TZ_offset);
1065 else if (datestr[19] == 'Z')
1067 /* act as if the offset were +00:00 */
1072 if ( datestr[char_count] != 0 )
1074 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
1075 datestr, char_count);
1082 TIMESTAMP_TO_SYSTIME(TmpStamp, &st);
1083 if ( SystemTimeToFileTime(&st, &ft) == 0 )
1085 SYSTIME_TO_TIMESTAMP(&st, *this);
1088 Kumu::TAI::caltime ct;
1089 TIMESTAMP_TO_CALTIME(TmpStamp, &ct);
1090 t = ct; // back and forth to tai to normalize offset
1092 CALTIME_TO_TIMESTAMP(&ct, *this)
1100 Kumu::Timestamp::HasValue() const
1102 if ( Year || Month || Day || Hour || Minute || Second )
1110 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
1113 if ( ! Reader->ReadUi16BE(&Year) ) return false;
1114 if ( ! Reader->ReadRaw(&Month, 6) ) return false;
1120 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1123 if ( ! Writer->WriteUi16BE(Year) ) return false;
1124 if ( ! Writer->WriteRaw(&Month, 6) ) return false;
1128 //------------------------------------------------------------------------------------------
1130 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1131 : m_p(0), m_capacity(0), m_size(0)
1134 m_capacity = Buf->Capacity();
1135 assert(m_p); assert(m_capacity);
1139 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1141 if ( ( m_size + ber_len ) > m_capacity )
1144 if ( ! write_BER(m_p + m_size, i, ber_len) )
1152 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1153 : m_p(0), m_capacity(0), m_size(0)
1155 m_p = Buf->RoData();
1156 m_capacity = Buf->Length();
1157 assert(m_p); assert(m_capacity);
1161 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1163 if ( i == 0 || ber_len == 0 ) return false;
1165 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1168 if ( ( m_size + *ber_len ) > m_capacity )
1171 if ( ! read_BER(m_p + m_size, i) )
1178 //------------------------------------------------------------------------------------------
1180 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1182 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1187 Kumu::ByteString::~ByteString()
1194 // copy the given data into the ByteString, set Length value.
1195 // Returns error if the ByteString is too small.
1197 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1199 if ( m_Capacity < buf_len )
1200 return RESULT_ALLOC;
1202 memcpy(m_Data, buf, buf_len);
1208 // copy the given data into the ByteString, set Length value.
1209 // Returns error if the ByteString is too small.
1211 Kumu::ByteString::Set(const ByteString& Buf)
1213 if ( m_Capacity < Buf.m_Capacity )
1214 return RESULT_ALLOC;
1216 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1217 m_Length = Buf.m_Length;
1222 // Sets the size of the internally allocate buffer.
1224 Kumu::ByteString::Capacity(ui32_t cap_size)
1226 if ( m_Capacity >= cap_size )
1229 byte_t* tmp_data = 0;
1238 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1239 return RESULT_ALLOC;
1241 if ( tmp_data != 0 )
1243 assert(m_Length > 0);
1244 memcpy(m_Data, tmp_data, m_Length);
1248 m_Capacity = cap_size;
1254 Kumu::ByteString::Append(const ByteString& Buf)
1256 Result_t result = RESULT_OK;
1257 ui32_t diff = m_Capacity - m_Length;
1259 if ( diff < Buf.Length() )
1260 result = Capacity(m_Capacity + Buf.Length());
1262 if ( KM_SUCCESS(result) )
1264 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1265 m_Length += Buf.Length();
1273 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1275 Result_t result = RESULT_OK;
1276 ui32_t diff = m_Capacity - m_Length;
1278 if ( diff < buf_len )
1279 result = Capacity(m_Capacity + buf_len);
1281 if ( KM_SUCCESS(result) )
1283 memcpy(m_Data + m_Length, buf, buf_len);
1284 m_Length += buf_len;