2 Copyright (c) 2005-2012, 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.
28 \version $Id: KM_util.cpp,v 1.40 2012/02/22 19:20:33 jhurst Exp $
29 \brief Utility functions
35 #include <KM_fileio.h>
46 return PACKAGE_VERSION;
50 //------------------------------------------------------------------------------------------
57 Kumu::Result_t* result;
61 // WIN32 does not init this in time for use with Result_t(...) below, so it is
62 // now a pointer that Result_t(...) fills in when it needs it.
63 static Kumu::Mutex* s_MapLock = 0;
65 static ui32_t s_MapSize = 0;
66 static const ui32_t MapMax = 2048;
67 static struct map_entry_t s_ResultMap[MapMax];
72 Kumu::Result_t::Find(int v)
78 AutoMutex L(*s_MapLock);
80 for ( ui32_t i = 0; i < s_MapSize; ++i )
82 if ( s_ResultMap[i].rcode == v )
83 return *s_ResultMap[i].result;
86 return RESULT_UNKNOWN;
91 Kumu::Result_t::Delete(int v)
93 if ( v < -99 || v > 99 )
95 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
100 AutoMutex L(*s_MapLock);
102 for ( ui32_t i = 0; i < s_MapSize; ++i )
104 if ( s_ResultMap[i].rcode == v )
106 for ( ++i; i < s_MapSize; ++i )
107 s_ResultMap[i-1] = s_ResultMap[i];
119 Kumu::Result_t::End()
125 const Kumu::Result_t&
126 Kumu::Result_t::Get(unsigned int i)
128 return *s_ResultMap[i].result;
132 Kumu::Result_t::Result_t(int v, const char* s, const char* l) : value(v), label(l), symbol(s)
140 // This may seem tricky, but it is certain that the static values declared in KM_error.h will
141 // be created (and thus this method will be called) before main(...) is called. It is not
142 // until then that threads could be created, thus the mutex will exist before multi-threaded
143 // access could occur.
144 if ( s_MapLock == 0 )
145 s_MapLock = new Kumu::Mutex;
148 AutoMutex L(*s_MapLock);
150 for ( ui32_t i = 0; i < s_MapSize; ++i )
152 if ( s_ResultMap[i].rcode == v )
156 assert(s_MapSize+1 < MapMax);
158 s_ResultMap[s_MapSize].rcode = v;
159 s_ResultMap[s_MapSize].result = this;
165 Kumu::Result_t::~Result_t() {}
168 //------------------------------------------------------------------------------------------
171 static int s_DTraceSequence = 0;
173 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
174 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
176 m_Sequence = s_DTraceSequence++;
177 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
180 Kumu::DTrace_t::~DTrace_t()
183 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
185 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
188 //------------------------------------------------------------------------------------------
191 const char fill = '=';
192 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
194 const byte_t decode_map[] =
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, 62, 0xff, 0xff, 0xff, 63,
201 52, 53, 54, 55, 56, 57, 58, 59,
202 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
203 0xff, 0, 1, 2, 3, 4, 5, 6,
204 7, 8, 9, 10, 11, 12, 13, 14,
205 15, 16, 17, 18, 19, 20, 21, 22,
206 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
207 0xff, 26, 27, 28, 29, 30, 31, 32,
208 33, 34, 35, 36, 37, 38, 39, 40,
209 41, 42, 43, 44, 45, 46, 47, 48,
210 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
215 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
230 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
231 // if the binary buffer was large enough to hold the result. If the output buffer
232 // is too small or any of the pointer arguments are NULL, the subroutine will
236 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
239 ui32_t i, block_len, diff;
241 if ( buf == 0 || strbuf == 0 )
244 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
249 while ( block_len % 3 )
252 for ( i = 0; i < block_len; i += 3 )
254 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
255 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
256 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
257 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
267 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
271 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
272 strbuf[out_char++] = fill;
274 else if ( diff == 2 )
276 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
277 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
280 strbuf[out_char++] = fill;
283 strbuf[out_char] = 0;
290 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
291 // the binary buffer was large enough to hold the result. The output parameter
292 // 'char_count' will contain the length of the converted string. If the output
293 // buffer is too small or any of the pointer arguments are NULL, the subroutine
294 // will return -1 and set 'char_count' to the required buffer size. No data will
295 // be written to 'buf' if the subroutine fails.
298 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
300 register byte_t c = 0, d = 0;
301 register ui32_t phase = 0, i = 0;
303 if ( str == 0 || buf == 0 || char_count == 0 )
306 while ( *str != 0 && i < buf_len )
308 c = decode_map[(int)*str++];
309 if ( c == 0xff ) continue;
310 if ( c == 0xfe ) break;
319 buf[i - 1] |= c >> 4;
324 buf[i++] = ( d << 4 ) | ( c >> 2 );
329 buf[i++] = ( d << 6 ) | c;
339 //------------------------------------------------------------------------------------------
341 // convert utf-8 hext string to bin
343 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
347 KM_TEST_NULL_L(conv_size);
351 if ( str[0] == 0 ) // nothing to convert
354 for ( int j = 0; str[j]; j++ )
356 if ( isxdigit(str[j]) )
360 if ( *conv_size & 0x01 ) (*conv_size)++;
363 if ( *conv_size > buf_len )// maximum possible data size
368 int phase = 0; // track high/low nybble
370 // for each character, fill in the high nybble then the low
371 for ( int i = 0; str[i]; i++ )
373 if ( ! isxdigit(str[i]) )
376 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
380 buf[*conv_size] = val << 4;
385 buf[*conv_size] |= val;
394 #ifdef CONFIG_RANDOM_UUID
396 // convert a memory region to a NULL-terminated hexadecimal string
399 bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
403 || ((bin_len * 2) + 1) > str_len )
407 Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
408 Kumu::FortunaRNG RNG;
409 RNG.FillRandom(rand_buf, bin_len);
411 for ( ui32_t i = 0; i < bin_len; i++ )
413 *p = (bin_buf[i] >> 4) & 0x0f;
414 *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
417 *p = bin_buf[i] & 0x0f;
418 *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
427 // convert a memory region to a NULL-terminated hexadecimal string
430 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
434 || ((bin_len * 2) + 1) > str_len )
437 #ifdef CONFIG_RANDOM_UUID
438 const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
439 if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
440 return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
445 for ( ui32_t i = 0; i < bin_len; i++ )
447 *p = (bin_buf[i] >> 4) & 0x0f;
448 *p += *p < 10 ? 0x30 : 0x61 - 10;
451 *p = bin_buf[i] & 0x0f;
452 *p += *p < 10 ? 0x30 : 0x61 - 10;
461 // spew a range of bin data as hex
463 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
471 static ui32_t row_len = 16;
472 const byte_t* p = buf;
473 const byte_t* end_p = p + dump_len;
475 for ( ui32_t line = 0; p < end_p; line++ )
477 fprintf(stream, " %06x: ", line);
481 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
482 fprintf(stream, "%02x ", *pp);
484 while ( i++ < row_len )
487 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
488 fputc((isprint(*pp) ? *pp : '.'), stream);
497 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
501 if ( str_len < 34 || bin_len != UUID_Length )
504 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
508 for ( k = 19, i = 12; i > 0; i-- )
509 str_buf[k+i+4] = str_buf[k+i];
511 // shift the time (mid+hi+clk)
512 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
514 for ( i = 4; i > 0; i-- )
515 str_buf[k+i+j] = str_buf[k+i];
518 // add in the hyphens and trainling null
519 for ( i = 8; i < 24; i += 5 )
528 Kumu::GenRandomValue(UUID& ID)
530 byte_t tmp_buf[UUID_Length];
531 GenRandomUUID(tmp_buf);
537 Kumu::GenRandomUUID(byte_t* buf)
540 RNG.FillRandom(buf, UUID_Length);
541 buf[6] &= 0x0f; // clear bits 4-7
542 buf[6] |= 0x40; // set UUID version
543 buf[8] &= 0x3f; // clear bits 6&7
544 buf[8] |= 0x80; // set bit 7
549 Kumu::GenRandomValue(SymmetricKey& Key)
551 byte_t tmp_buf[SymmetricKey_Length];
553 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
558 //------------------------------------------------------------------------------------------
559 // read a ber value from the buffer and compare with test value.
560 // Advances buffer to first character after BER value.
563 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
568 if ( ( **buf & 0x80 ) == 0 )
572 ui8_t ber_size = ( **buf & 0x0f ) + 1;
577 for ( ui8_t i = 1; i < ber_size; i++ )
580 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
584 return ( val == test_value );
590 Kumu::read_BER(const byte_t* buf, ui64_t* val)
594 if ( buf == 0 || val == 0 )
597 if ( ( *buf & 0x80 ) == 0 )
601 ber_size = ( *buf & 0x0f ) + 1;
606 for ( i = 1; i < ber_size; i++ )
609 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
616 static const ui64_t ber_masks[9] =
617 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
618 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
619 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
620 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
626 Kumu::get_BER_length_for_value(ui64_t val)
628 for ( ui32_t i = 0; i < 9; i++ )
630 if ( ( val & ber_masks[i] ) == 0 )
634 ui64Printer tmp_i(val);
635 DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
641 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
647 { // calculate default length
648 if ( val < 0x01000000L )
650 else if ( val < ui64_C(0x0100000000000000) )
656 { // sanity check BER length
659 DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len);
663 if ( ( val & ber_masks[ber_len - 1] ) != 0 )
665 ui64Printer tmp_i(val);
666 DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str());
671 buf[0] = 0x80 + ( ber_len - 1 );
673 for ( ui32_t i = ber_len - 1; i > 0; i-- )
675 buf[i] = (ui8_t)(val & 0xff);
683 //------------------------------------------------------------------------------------------
690 Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) {
694 Kumu::Timestamp::Timestamp(const Timestamp& rhs) {
695 m_Timestamp = rhs.m_Timestamp;
696 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
699 Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) {
700 DecodeString(datestr);
703 Kumu::Timestamp::~Timestamp() {
707 const Kumu::Timestamp&
708 Kumu::Timestamp::operator=(const Timestamp& rhs)
710 m_Timestamp = rhs.m_Timestamp;
711 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
715 bool Kumu::Timestamp::operator<(const Timestamp& rhs) const {
716 return m_Timestamp.x < rhs.m_Timestamp.x;
719 bool Kumu::Timestamp::operator>(const Timestamp& rhs) const {
720 return m_Timestamp.x > rhs.m_Timestamp.x;
723 bool Kumu::Timestamp::operator==(const Timestamp& rhs) const {
724 return m_Timestamp.x == rhs.m_Timestamp.x;
727 bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const {
728 return m_Timestamp.x != rhs.m_Timestamp.x;
733 Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
734 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const
739 Month = ct.date.month;
748 Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
749 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second)
753 ct.date.month = Month;
760 m_TZOffsetMinutes = 0;
763 // returns false if the requested adjustment is out of range
765 Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes)
767 static const i32_t tz_limit = 14 * 60 * 60;
769 if ( minutes < ( - tz_limit) || minutes > tz_limit )
772 m_TZOffsetMinutes = minutes;
778 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
780 if ( buf_len < ( DateTimeLen + 1 ) )
784 ui8_t month, day, hour, minute, second;
785 ui32_t ofst_hours = 0, ofst_minutes = 0;
786 char direction = '+';
788 if ( m_TZOffsetMinutes == 0 )
790 GetComponents(year, month, day, hour, minute, second);
794 // calculate local time
795 Kumu::Timestamp tmp_t(*this);
796 tmp_t.AddMinutes(m_TZOffsetMinutes);
797 tmp_t.GetComponents(year, month, day, hour, minute, second);
799 ofst_hours = abs(m_TZOffsetMinutes) / 60;
800 ofst_minutes = abs(m_TZOffsetMinutes) % 60;
802 if ( m_TZOffsetMinutes < 0 )
806 // 2004-05-01T13:20:00+00:00
807 snprintf(str_buf, buf_len,
808 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
809 year, month, day, hour, minute, second,
810 direction, ofst_hours, ofst_minutes);
817 Kumu::Timestamp::DecodeString(const char* datestr)
819 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
821 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
823 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
826 ui32_t char_count = 10;
829 YMDhms.date.year = atoi(datestr);
830 YMDhms.date.month = atoi(datestr + 5);
831 YMDhms.date.day = atoi(datestr + 8);
833 if ( datestr[10] == 'T' )
835 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
836 || datestr[13] != ':'
837 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
841 YMDhms.hour = atoi(datestr + 11);
842 YMDhms.minute = atoi(datestr + 14);
844 if ( datestr[16] == ':' )
846 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
850 YMDhms.second = atoi(datestr + 17);
853 if ( datestr[19] == '.' )
855 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
858 // we don't carry the ms value
862 if ( datestr[19] == '-' || datestr[19] == '+' )
864 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
865 || datestr[22] != ':'
866 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
871 ui32_t TZ_hh = atoi(datestr + 20);
872 ui32_t TZ_mm = atoi(datestr + 23);
873 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
876 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
877 if (datestr[19] == '-')
878 TZ_offset = -TZ_offset;
879 /* at this point, TZ_offset reflects the contents of the string */
881 /* a negative offset is behind UTC and so needs to increment to
882 * convert, while a positive offset must do the reverse */
883 YMDhms.offset = TZ_offset;
885 else if (datestr[19] == 'Z')
887 /* act as if the offset were +00:00 */
892 if ( datestr[char_count] != 0 )
894 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
895 datestr, char_count);
899 m_Timestamp = YMDhms;
900 m_TZOffsetMinutes = YMDhms.offset;
906 Kumu::Timestamp::HasValue() const
913 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
916 ui8_t month, day, hour, minute, second, tick;
919 if ( ! Reader->ReadUi16BE(&year) ) return false;
920 if ( ! Reader->ReadUi8(&month) ) return false;
921 if ( ! Reader->ReadUi8(&day) ) return false;
922 if ( ! Reader->ReadUi8(&hour) ) return false;
923 if ( ! Reader->ReadUi8(&minute) ) return false;
924 if ( ! Reader->ReadUi8(&second) ) return false;
925 if ( ! Reader->ReadUi8(&tick) ) return false;
926 SetComponents(year, month, day, hour, minute, second);
932 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
937 ui8_t month, day, hour, minute, second, tick = 0;
938 GetComponents(year, month, day, hour, minute, second);
940 if ( ! Writer->WriteUi16BE(year) ) return false;
941 if ( ! Writer->WriteUi8(month) ) return false;
942 if ( ! Writer->WriteUi8(day) ) return false;
943 if ( ! Writer->WriteUi8(hour) ) return false;
944 if ( ! Writer->WriteUi8(minute) ) return false;
945 if ( ! Writer->WriteUi8(second) ) return false;
946 if ( ! Writer->WriteUi8(tick) ) return false;
952 Kumu::Timestamp::GetCTime() const
954 return m_Timestamp.x - ui64_C(4611686018427387914);
958 //------------------------------------------------------------------------------------------
960 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
961 : m_p(0), m_capacity(0), m_size(0)
964 m_capacity = Buf->Capacity();
965 assert(m_p); assert(m_capacity);
969 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
971 if ( ( m_size + ber_len ) > m_capacity )
974 if ( ! write_BER(m_p + m_size, i, ber_len) )
982 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
983 : m_p(0), m_capacity(0), m_size(0)
986 m_capacity = Buf->Length();
987 assert(m_p); assert(m_capacity);
991 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
993 if ( i == 0 || ber_len == 0 ) return false;
995 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
998 if ( ( m_size + *ber_len ) > m_capacity )
1001 if ( ! read_BER(m_p + m_size, i) )
1008 //------------------------------------------------------------------------------------------
1010 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1012 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1017 Kumu::ByteString::~ByteString()
1024 // copy the given data into the ByteString, set Length value.
1025 // Returns error if the ByteString is too small.
1027 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1029 if ( m_Capacity < buf_len )
1030 return RESULT_ALLOC;
1032 memcpy(m_Data, buf, buf_len);
1038 // copy the given data into the ByteString, set Length value.
1039 // Returns error if the ByteString is too small.
1041 Kumu::ByteString::Set(const ByteString& Buf)
1043 if ( m_Capacity < Buf.m_Capacity )
1044 return RESULT_ALLOC;
1046 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1047 m_Length = Buf.m_Length;
1052 // Sets the size of the internally allocate buffer.
1054 Kumu::ByteString::Capacity(ui32_t cap_size)
1056 if ( m_Capacity >= cap_size )
1059 byte_t* tmp_data = 0;
1068 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1069 return RESULT_ALLOC;
1071 if ( tmp_data != 0 )
1073 assert(m_Length > 0);
1074 memcpy(m_Data, tmp_data, m_Length);
1078 m_Capacity = cap_size;
1084 Kumu::ByteString::Append(const ByteString& Buf)
1086 Result_t result = RESULT_OK;
1087 ui32_t diff = m_Capacity - m_Length;
1089 if ( diff < Buf.Length() )
1090 result = Capacity(m_Capacity + Buf.Length());
1092 if ( KM_SUCCESS(result) )
1094 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1095 m_Length += Buf.Length();
1103 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1105 Result_t result = RESULT_OK;
1106 ui32_t diff = m_Capacity - m_Length;
1108 if ( diff < buf_len )
1109 result = Capacity(m_Capacity + buf_len);
1111 if ( KM_SUCCESS(result) )
1113 memcpy(m_Data + m_Length, buf, buf_len);
1114 m_Length += buf_len;