2 Copyright (c) 2005-2015, 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 std::string& s, const std::string& 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;
166 Kumu::Result_t::Result_t(const Result_t& rhs)
171 message = rhs.message;
174 Kumu::Result_t::~Result_t() {}
177 const Kumu::Result_t&
178 Kumu::Result_t::operator=(const Result_t& rhs)
183 message = rhs.message;
189 Kumu::Result_t::operator()(const std::string& message) const
191 Result_t result = *this;
192 result.message = message;
196 static int const MESSAGE_BUF_MAX = 2048;
200 Kumu::Result_t::operator()(const int& line, const char* filename) const
203 char buf[MESSAGE_BUF_MAX];
204 snprintf(buf, MESSAGE_BUF_MAX-1, "%s, line %d", filename, line);
206 Result_t result = *this;
207 result.message = buf;
213 Kumu::Result_t::operator()(const std::string& message, const int& line, const char* filename) const
216 char buf[MESSAGE_BUF_MAX];
217 snprintf(buf, MESSAGE_BUF_MAX-1, "%s, line %d", filename, line);
219 Result_t result = *this;
220 result.message = message + buf;
225 //------------------------------------------------------------------------------------------
228 static int s_DTraceSequence = 0;
230 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
231 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
233 m_Sequence = s_DTraceSequence++;
234 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
237 Kumu::DTrace_t::~DTrace_t()
240 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
242 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
245 //------------------------------------------------------------------------------------------
248 const char fill = '=';
249 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
251 const byte_t decode_map[] =
252 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
253 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
254 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
255 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
256 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
257 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
258 52, 53, 54, 55, 56, 57, 58, 59,
259 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
260 0xff, 0, 1, 2, 3, 4, 5, 6,
261 7, 8, 9, 10, 11, 12, 13, 14,
262 15, 16, 17, 18, 19, 20, 21, 22,
263 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
264 0xff, 26, 27, 28, 29, 30, 31, 32,
265 33, 34, 35, 36, 37, 38, 39, 40,
266 41, 42, 43, 44, 45, 46, 47, 48,
267 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
268 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
269 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
270 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
271 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
272 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
273 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
274 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
275 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
276 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
277 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
278 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
279 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
280 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
281 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
282 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
283 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
287 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
288 // if the binary buffer was large enough to hold the result. If the output buffer
289 // is too small or any of the pointer arguments are NULL, the subroutine will
293 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
296 ui32_t i, block_len, diff;
298 if ( buf == 0 || strbuf == 0 )
301 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
306 while ( block_len % 3 )
309 for ( i = 0; i < block_len; i += 3 )
311 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
312 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
313 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
314 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
324 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
328 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
329 strbuf[out_char++] = fill;
331 else if ( diff == 2 )
333 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
334 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
337 strbuf[out_char++] = fill;
340 strbuf[out_char] = 0;
347 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
348 // the binary buffer was large enough to hold the result. The output parameter
349 // 'char_count' will contain the length of the converted string. If the output
350 // buffer is too small or any of the pointer arguments are NULL, the subroutine
351 // will return -1 and set 'char_count' to the required buffer size. No data will
352 // be written to 'buf' if the subroutine fails.
355 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
357 register byte_t c = 0, d = 0;
358 register ui32_t phase = 0, i = 0;
360 if ( str == 0 || buf == 0 || char_count == 0 )
363 while ( *str != 0 && i < buf_len )
365 c = decode_map[(int)*str++];
366 if ( c == 0xff ) continue;
367 if ( c == 0xfe ) break;
376 buf[i - 1] |= c >> 4;
381 buf[i++] = ( d << 4 ) | ( c >> 2 );
386 buf[i++] = ( d << 6 ) | c;
396 //------------------------------------------------------------------------------------------
398 // convert utf-8 hext string to bin
400 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
404 KM_TEST_NULL_L(conv_size);
408 if ( str[0] == 0 ) // nothing to convert
411 for ( int j = 0; str[j]; j++ )
413 if ( isxdigit(str[j]) )
417 if ( *conv_size & 0x01 ) (*conv_size)++;
420 if ( *conv_size > buf_len )// maximum possible data size
425 int phase = 0; // track high/low nybble
427 // for each character, fill in the high nybble then the low
428 for ( int i = 0; str[i]; i++ )
430 if ( ! isxdigit(str[i]) )
433 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
437 buf[*conv_size] = val << 4;
442 buf[*conv_size] |= val;
451 #ifdef CONFIG_RANDOM_UUID
453 // convert a memory region to a NULL-terminated hexadecimal string
456 bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
460 || ((bin_len * 2) + 1) > str_len )
464 Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
465 Kumu::FortunaRNG RNG;
466 RNG.FillRandom(rand_buf, bin_len);
468 for ( ui32_t i = 0; i < bin_len; i++ )
470 *p = (bin_buf[i] >> 4) & 0x0f;
471 *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
474 *p = bin_buf[i] & 0x0f;
475 *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
484 // convert a memory region to a NULL-terminated hexadecimal string
487 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
491 || ((bin_len * 2) + 1) > str_len )
494 #ifdef CONFIG_RANDOM_UUID
495 const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
496 if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
497 return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
502 for ( ui32_t i = 0; i < bin_len; i++ )
504 *p = (bin_buf[i] >> 4) & 0x0f;
505 *p += *p < 10 ? 0x30 : 0x61 - 10;
508 *p = bin_buf[i] & 0x0f;
509 *p += *p < 10 ? 0x30 : 0x61 - 10;
518 // spew a range of bin data as hex
520 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
528 static ui32_t row_len = 16;
529 const byte_t* p = buf;
530 const byte_t* end_p = p + dump_len;
532 for ( ui32_t line = 0; p < end_p; line++ )
534 fprintf(stream, " %06x: ", line);
538 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
539 fprintf(stream, "%02x ", *pp);
541 while ( i++ < row_len )
544 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
545 fputc((isprint(*pp) ? *pp : '.'), stream);
554 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
558 if ( str_len < 34 || bin_len != UUID_Length )
561 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
565 for ( k = 19, i = 12; i > 0; i-- )
566 str_buf[k+i+4] = str_buf[k+i];
568 // shift the time (mid+hi+clk)
569 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
571 for ( i = 4; i > 0; i-- )
572 str_buf[k+i+j] = str_buf[k+i];
575 // add in the hyphens and trainling null
576 for ( i = 8; i < 24; i += 5 )
585 Kumu::GenRandomValue(UUID& ID)
587 byte_t tmp_buf[UUID_Length];
588 GenRandomUUID(tmp_buf);
594 Kumu::GenRandomUUID(byte_t* buf)
597 RNG.FillRandom(buf, UUID_Length);
598 buf[6] &= 0x0f; // clear bits 4-7
599 buf[6] |= 0x40; // set UUID version
600 buf[8] &= 0x3f; // clear bits 6&7
601 buf[8] |= 0x80; // set bit 7
606 Kumu::GenRandomValue(SymmetricKey& Key)
608 byte_t tmp_buf[SymmetricKey_Length];
610 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
615 //------------------------------------------------------------------------------------------
616 // read a ber value from the buffer and compare with test value.
617 // Advances buffer to first character after BER value.
620 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
625 if ( ( **buf & 0x80 ) == 0 )
629 ui8_t ber_size = ( **buf & 0x0f ) + 1;
634 for ( ui8_t i = 1; i < ber_size; i++ )
637 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
641 return ( val == test_value );
647 Kumu::read_BER(const byte_t* buf, ui64_t* val)
651 if ( buf == 0 || val == 0 )
654 if ( ( *buf & 0x80 ) == 0 )
658 ber_size = ( *buf & 0x0f ) + 1;
663 for ( i = 1; i < ber_size; i++ )
666 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
673 static const ui64_t ber_masks[9] =
674 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
675 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
676 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
677 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
683 Kumu::get_BER_length_for_value(ui64_t val)
685 for ( ui32_t i = 0; i < 9; i++ )
687 if ( ( val & ber_masks[i] ) == 0 )
691 ui64Printer tmp_i(val);
692 DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
698 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
704 { // calculate default length
705 if ( val < 0x01000000L )
707 else if ( val < ui64_C(0x0100000000000000) )
713 { // sanity check BER length
716 DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len);
720 if ( ( val & ber_masks[ber_len - 1] ) != 0 )
722 ui64Printer tmp_i(val);
723 DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str());
728 buf[0] = 0x80 + ( ber_len - 1 );
730 for ( ui32_t i = ber_len - 1; i > 0; i-- )
732 buf[i] = (ui8_t)(val & 0xff);
740 //------------------------------------------------------------------------------------------
747 Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) {
751 Kumu::Timestamp::Timestamp(const Timestamp& rhs) {
752 m_Timestamp = rhs.m_Timestamp;
753 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
756 Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) {
757 DecodeString(datestr);
760 Kumu::Timestamp::~Timestamp() {
764 const Kumu::Timestamp&
765 Kumu::Timestamp::operator=(const Timestamp& rhs)
767 m_Timestamp = rhs.m_Timestamp;
768 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
772 bool Kumu::Timestamp::operator<(const Timestamp& rhs) const {
773 return m_Timestamp.x < rhs.m_Timestamp.x;
776 bool Kumu::Timestamp::operator>(const Timestamp& rhs) const {
777 return m_Timestamp.x > rhs.m_Timestamp.x;
780 bool Kumu::Timestamp::operator==(const Timestamp& rhs) const {
781 return m_Timestamp.x == rhs.m_Timestamp.x;
784 bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const {
785 return m_Timestamp.x != rhs.m_Timestamp.x;
790 Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
791 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const
796 Month = ct.date.month;
805 Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
806 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second)
810 ct.date.month = Month;
817 m_TZOffsetMinutes = 0;
820 // returns false if the requested adjustment is out of range
822 Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes)
824 static const i32_t tz_limit = 14 * 60 * 60;
826 if ( minutes < ( - tz_limit) || minutes > tz_limit )
829 m_TZOffsetMinutes = minutes;
835 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
837 if ( buf_len < ( DateTimeLen + 1 ) )
841 ui8_t month, day, hour, minute, second;
842 ui32_t ofst_hours = 0, ofst_minutes = 0;
843 char direction = '+';
845 if ( m_TZOffsetMinutes == 0 )
847 GetComponents(year, month, day, hour, minute, second);
851 // calculate local time
852 Kumu::Timestamp tmp_t(*this);
853 tmp_t.AddMinutes(m_TZOffsetMinutes);
854 tmp_t.GetComponents(year, month, day, hour, minute, second);
856 ofst_hours = Kumu::xabs(m_TZOffsetMinutes) / 60;
857 ofst_minutes = Kumu::xabs(m_TZOffsetMinutes) % 60;
859 if ( m_TZOffsetMinutes < 0 )
863 // 2004-05-01T13:20:00+00:00
864 snprintf(str_buf, buf_len,
865 "%04hu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu%c%02u:%02u",
866 year, month, day, hour, minute, second,
867 direction, ofst_hours, ofst_minutes);
872 // ^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(?:([+-]\d{2}):(\d{2}))?)?$
874 Kumu::Timestamp::DecodeString(const char* datestr)
876 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
878 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
880 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
883 ui32_t char_count = 10;
889 YMDhms.date.year = strtol(datestr, 0, 10);
890 YMDhms.date.month = strtol(datestr + 5, 0, 10);
891 YMDhms.date.day = strtol(datestr + 8, 0, 10);
893 if ( datestr[10] == 'T' )
895 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
896 || datestr[13] != ':'
897 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
901 YMDhms.hour = strtol(datestr + 11, 0, 10);
902 YMDhms.minute = strtol(datestr + 14, 0, 10);
904 if ( datestr[16] == ':' )
906 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
910 YMDhms.second = strtol(datestr + 17, 0, 10);
913 if ( datestr[19] == '.' )
915 if ( ! isdigit(datestr[20]) )
920 // we don't carry the ms value
921 while ( isdigit(datestr[20]) )
929 if ( datestr[19] == '-' || datestr[19] == '+' )
931 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
932 || datestr[22] != ':'
933 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
938 ui32_t TZ_hh = strtol(datestr + 20, 0, 10);
939 ui32_t TZ_mm = strtol(datestr + 23, 0, 10);
940 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
943 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
944 if (datestr[19] == '-')
945 TZ_offset = -TZ_offset;
946 /* at this point, TZ_offset reflects the contents of the string */
948 /* a negative offset is behind UTC and so needs to increment to
949 * convert, while a positive offset must do the reverse */
950 YMDhms.offset = TZ_offset;
952 else if (datestr[19] == 'Z')
954 /* act as if the offset were +00:00 */
959 if ( datestr[char_count] != 0 )
961 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
962 datestr, char_count);
966 m_Timestamp = YMDhms;
967 m_TZOffsetMinutes = YMDhms.offset;
973 Kumu::Timestamp::HasValue() const
980 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
983 ui8_t month, day, hour, minute, second, tick;
986 if ( ! Reader->ReadUi16BE(&year) ) return false;
987 if ( ! Reader->ReadUi8(&month) ) return false;
988 if ( ! Reader->ReadUi8(&day) ) return false;
989 if ( ! Reader->ReadUi8(&hour) ) return false;
990 if ( ! Reader->ReadUi8(&minute) ) return false;
991 if ( ! Reader->ReadUi8(&second) ) return false;
992 if ( ! Reader->ReadUi8(&tick) ) return false;
993 SetComponents(year, month, day, hour, minute, second);
999 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
1004 ui8_t month, day, hour, minute, second, tick = 0;
1005 GetComponents(year, month, day, hour, minute, second);
1007 if ( ! Writer->WriteUi16BE(year) ) return false;
1008 if ( ! Writer->WriteUi8(month) ) return false;
1009 if ( ! Writer->WriteUi8(day) ) return false;
1010 if ( ! Writer->WriteUi8(hour) ) return false;
1011 if ( ! Writer->WriteUi8(minute) ) return false;
1012 if ( ! Writer->WriteUi8(second) ) return false;
1013 if ( ! Writer->WriteUi8(tick) ) return false;
1019 Kumu::Timestamp::GetCTime() const
1021 return m_Timestamp.x - ui64_C(4611686018427387914);
1026 Kumu::Timestamp::SetCTime(const ui64_t& ctime)
1028 m_Timestamp.x = ctime + ui64_C(4611686018427387914);
1034 //------------------------------------------------------------------------------------------
1036 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
1037 : m_p(0), m_capacity(0), m_size(0)
1040 m_capacity = Buf->Capacity();
1041 assert(m_p); assert(m_capacity);
1045 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
1047 if ( ( m_size + ber_len ) > m_capacity )
1050 if ( ! write_BER(m_p + m_size, i, ber_len) )
1058 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1059 : m_p(0), m_capacity(0), m_size(0)
1061 m_p = Buf->RoData();
1062 m_capacity = Buf->Length();
1063 assert(m_p); assert(m_capacity);
1067 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1069 if ( i == 0 || ber_len == 0 ) return false;
1071 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1074 if ( ( m_size + *ber_len ) > m_capacity )
1077 if ( ! read_BER(m_p + m_size, i) )
1084 //------------------------------------------------------------------------------------------
1086 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1088 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1093 Kumu::ByteString::~ByteString()
1100 // copy the given data into the ByteString, set Length value.
1101 // Returns error if the ByteString is too small.
1103 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1105 if ( m_Capacity < buf_len )
1106 return RESULT_ALLOC;
1108 memcpy(m_Data, buf, buf_len);
1114 // copy the given data into the ByteString, set Length value.
1115 // Returns error if the ByteString is too small.
1117 Kumu::ByteString::Set(const ByteString& Buf)
1119 if ( m_Capacity < Buf.m_Capacity )
1120 return RESULT_ALLOC;
1122 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1123 m_Length = Buf.m_Length;
1128 // Sets the size of the internally allocate buffer.
1130 Kumu::ByteString::Capacity(ui32_t cap_size)
1132 if ( m_Capacity >= cap_size )
1135 byte_t* tmp_data = 0;
1144 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1145 return RESULT_ALLOC;
1147 if ( tmp_data != 0 )
1149 assert(m_Length > 0);
1150 memcpy(m_Data, tmp_data, m_Length);
1154 m_Capacity = cap_size;
1160 Kumu::ByteString::Append(const ByteString& Buf)
1162 Result_t result = RESULT_OK;
1163 ui32_t diff = m_Capacity - m_Length;
1165 if ( diff < Buf.Length() )
1166 result = Capacity(m_Capacity + Buf.Length());
1168 if ( KM_SUCCESS(result) )
1170 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1171 m_Length += Buf.Length();
1179 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1181 Result_t result = RESULT_OK;
1182 ui32_t diff = m_Capacity - m_Length;
1184 if ( diff < buf_len )
1185 result = Capacity(m_Capacity + buf_len);
1187 if ( KM_SUCCESS(result) )
1189 memcpy(m_Data + m_Length, buf, buf_len);
1190 m_Length += buf_len;
1196 //------------------------------------------------------------------------------------------
1200 Kumu::km_strnstr(const char *s, const char *find, size_t slen)
1205 if ( ( c = *find++ ) != '\0' )
1212 if ( slen-- < 1 || ( sc = *s++ ) == '\0' )
1220 while ( strncmp(s, find, len) != 0 );
1228 std::list<std::string>
1229 Kumu::km_token_split(const std::string& str, const std::string& separator)
1231 std::list<std::string> components;
1232 const char* pstr = str.c_str();
1233 const char* r = strstr(pstr, separator.c_str());
1238 std::string tmp_str;
1239 tmp_str.assign(pstr, r - pstr);
1240 components.push_back(tmp_str);
1241 pstr = r + separator.size();
1242 r = strstr(pstr, separator.c_str());
1245 components.push_back(std::string(pstr));