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.
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), symbol(s), label(l)
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);
815 // ^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(?:([+-]\d{2}):(\d{2}))?)?$
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;
832 YMDhms.date.year = atoi(datestr);
833 YMDhms.date.month = atoi(datestr + 5);
834 YMDhms.date.day = atoi(datestr + 8);
836 if ( datestr[10] == 'T' )
838 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
839 || datestr[13] != ':'
840 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
844 YMDhms.hour = atoi(datestr + 11);
845 YMDhms.minute = atoi(datestr + 14);
847 if ( datestr[16] == ':' )
849 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
853 YMDhms.second = atoi(datestr + 17);
856 if ( datestr[19] == '.' )
858 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
861 // we don't carry the ms value
865 if ( datestr[19] == '-' || datestr[19] == '+' )
867 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
868 || datestr[22] != ':'
869 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
874 ui32_t TZ_hh = atoi(datestr + 20);
875 ui32_t TZ_mm = atoi(datestr + 23);
876 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
879 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
880 if (datestr[19] == '-')
881 TZ_offset = -TZ_offset;
882 /* at this point, TZ_offset reflects the contents of the string */
884 /* a negative offset is behind UTC and so needs to increment to
885 * convert, while a positive offset must do the reverse */
886 YMDhms.offset = TZ_offset;
888 else if (datestr[19] == 'Z')
890 /* act as if the offset were +00:00 */
895 if ( datestr[char_count] != 0 )
897 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
898 datestr, char_count);
902 m_Timestamp = YMDhms;
903 m_TZOffsetMinutes = YMDhms.offset;
909 Kumu::Timestamp::HasValue() const
916 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
919 ui8_t month, day, hour, minute, second, tick;
922 if ( ! Reader->ReadUi16BE(&year) ) return false;
923 if ( ! Reader->ReadUi8(&month) ) return false;
924 if ( ! Reader->ReadUi8(&day) ) return false;
925 if ( ! Reader->ReadUi8(&hour) ) return false;
926 if ( ! Reader->ReadUi8(&minute) ) return false;
927 if ( ! Reader->ReadUi8(&second) ) return false;
928 if ( ! Reader->ReadUi8(&tick) ) return false;
929 SetComponents(year, month, day, hour, minute, second);
935 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
940 ui8_t month, day, hour, minute, second, tick = 0;
941 GetComponents(year, month, day, hour, minute, second);
943 if ( ! Writer->WriteUi16BE(year) ) return false;
944 if ( ! Writer->WriteUi8(month) ) return false;
945 if ( ! Writer->WriteUi8(day) ) return false;
946 if ( ! Writer->WriteUi8(hour) ) return false;
947 if ( ! Writer->WriteUi8(minute) ) return false;
948 if ( ! Writer->WriteUi8(second) ) return false;
949 if ( ! Writer->WriteUi8(tick) ) return false;
955 Kumu::Timestamp::GetCTime() const
957 return m_Timestamp.x - ui64_C(4611686018427387914);
962 Kumu::Timestamp::SetCTime(const ui64_t& ctime)
964 m_Timestamp.x = ctime + ui64_C(4611686018427387914);
970 //------------------------------------------------------------------------------------------
972 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
973 : m_p(0), m_capacity(0), m_size(0)
976 m_capacity = Buf->Capacity();
977 assert(m_p); assert(m_capacity);
981 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
983 if ( ( m_size + ber_len ) > m_capacity )
986 if ( ! write_BER(m_p + m_size, i, ber_len) )
994 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
995 : m_p(0), m_capacity(0), m_size(0)
998 m_capacity = Buf->Length();
999 assert(m_p); assert(m_capacity);
1003 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1005 if ( i == 0 || ber_len == 0 ) return false;
1007 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1010 if ( ( m_size + *ber_len ) > m_capacity )
1013 if ( ! read_BER(m_p + m_size, i) )
1020 //------------------------------------------------------------------------------------------
1022 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1024 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1029 Kumu::ByteString::~ByteString()
1036 // copy the given data into the ByteString, set Length value.
1037 // Returns error if the ByteString is too small.
1039 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1041 if ( m_Capacity < buf_len )
1042 return RESULT_ALLOC;
1044 memcpy(m_Data, buf, buf_len);
1050 // copy the given data into the ByteString, set Length value.
1051 // Returns error if the ByteString is too small.
1053 Kumu::ByteString::Set(const ByteString& Buf)
1055 if ( m_Capacity < Buf.m_Capacity )
1056 return RESULT_ALLOC;
1058 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1059 m_Length = Buf.m_Length;
1064 // Sets the size of the internally allocate buffer.
1066 Kumu::ByteString::Capacity(ui32_t cap_size)
1068 if ( m_Capacity >= cap_size )
1071 byte_t* tmp_data = 0;
1080 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1081 return RESULT_ALLOC;
1083 if ( tmp_data != 0 )
1085 assert(m_Length > 0);
1086 memcpy(m_Data, tmp_data, m_Length);
1090 m_Capacity = cap_size;
1096 Kumu::ByteString::Append(const ByteString& Buf)
1098 Result_t result = RESULT_OK;
1099 ui32_t diff = m_Capacity - m_Length;
1101 if ( diff < Buf.Length() )
1102 result = Capacity(m_Capacity + Buf.Length());
1104 if ( KM_SUCCESS(result) )
1106 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1107 m_Length += Buf.Length();
1115 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1117 Result_t result = RESULT_OK;
1118 ui32_t diff = m_Capacity - m_Length;
1120 if ( diff < buf_len )
1121 result = Capacity(m_Capacity + buf_len);
1123 if ( KM_SUCCESS(result) )
1125 memcpy(m_Data + m_Length, buf, buf_len);
1126 m_Length += buf_len;
1132 //------------------------------------------------------------------------------------------
1136 Kumu::km_strnstr(const char *s, const char *find, size_t slen)
1141 if ( ( c = *find++ ) != '\0' )
1148 if ( slen-- < 1 || ( sc = *s++ ) == '\0' )
1156 while ( strncmp(s, find, len) != 0 );
1164 std::list<std::string>
1165 Kumu::km_token_split(const std::string& str, const std::string& separator)
1167 std::list<std::string> components;
1168 const char* pstr = str.c_str();
1169 const char* r = strstr(pstr, separator.c_str());
1176 std::string tmp_str;
1177 tmp_str.assign(pstr, r - pstr);
1178 components.push_back(tmp_str);
1181 pstr = r + separator.size();
1182 r = strstr(pstr, separator.c_str());
1185 if( strlen(pstr) > 0 )
1186 components.push_back(std::string(pstr));