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>
43 bool Kumu::libdcp_test = false;
48 return PACKAGE_VERSION;
52 //------------------------------------------------------------------------------------------
59 Kumu::Result_t* result;
63 // WIN32 does not init this in time for use with Result_t(...) below, so it is
64 // now a pointer that Result_t(...) fills in when it needs it.
65 static Kumu::Mutex* s_MapLock = 0;
67 static ui32_t s_MapSize = 0;
68 static const ui32_t MapMax = 2048;
69 static struct map_entry_t s_ResultMap[MapMax];
74 Kumu::Result_t::Find(int v)
80 AutoMutex L(*s_MapLock);
82 for ( ui32_t i = 0; i < s_MapSize; ++i )
84 if ( s_ResultMap[i].rcode == v )
85 return *s_ResultMap[i].result;
88 return RESULT_UNKNOWN;
93 Kumu::Result_t::Delete(int v)
95 if ( v < -99 || v > 99 )
97 DefaultLogSink().Error("Cannot delete core result code: %ld\n", v);
102 AutoMutex L(*s_MapLock);
104 for ( ui32_t i = 0; i < s_MapSize; ++i )
106 if ( s_ResultMap[i].rcode == v )
108 for ( ++i; i < s_MapSize; ++i )
109 s_ResultMap[i-1] = s_ResultMap[i];
121 Kumu::Result_t::End()
127 const Kumu::Result_t&
128 Kumu::Result_t::Get(unsigned int i)
130 return *s_ResultMap[i].result;
134 Kumu::Result_t::Result_t(int v, const char* s, const char* l) : value(v), label(l), symbol(s)
142 // This may seem tricky, but it is certain that the static values declared in KM_error.h will
143 // be created (and thus this method will be called) before main(...) is called. It is not
144 // until then that threads could be created, thus the mutex will exist before multi-threaded
145 // access could occur.
146 if ( s_MapLock == 0 )
147 s_MapLock = new Kumu::Mutex;
150 AutoMutex L(*s_MapLock);
152 for ( ui32_t i = 0; i < s_MapSize; ++i )
154 if ( s_ResultMap[i].rcode == v )
158 assert(s_MapSize+1 < MapMax);
160 s_ResultMap[s_MapSize].rcode = v;
161 s_ResultMap[s_MapSize].result = this;
167 Kumu::Result_t::~Result_t() {}
170 //------------------------------------------------------------------------------------------
173 static int s_DTraceSequence = 0;
175 Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File)
176 : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File)
178 m_Sequence = s_DTraceSequence++;
179 DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line);
182 Kumu::DTrace_t::~DTrace_t()
185 DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label());
187 DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence);
190 //------------------------------------------------------------------------------------------
193 const char fill = '=';
194 const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
196 const byte_t decode_map[] =
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, 62, 0xff, 0xff, 0xff, 63,
203 52, 53, 54, 55, 56, 57, 58, 59,
204 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
205 0xff, 0, 1, 2, 3, 4, 5, 6,
206 7, 8, 9, 10, 11, 12, 13, 14,
207 15, 16, 17, 18, 19, 20, 21, 22,
208 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
209 0xff, 26, 27, 28, 29, 30, 31, 32,
210 33, 34, 35, 36, 37, 38, 39, 40,
211 41, 42, 43, 44, 45, 46, 47, 48,
212 49, 50, 51, 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,
227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
228 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
232 // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
233 // if the binary buffer was large enough to hold the result. If the output buffer
234 // is too small or any of the pointer arguments are NULL, the subroutine will
238 Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len)
241 ui32_t i, block_len, diff;
243 if ( buf == 0 || strbuf == 0 )
246 if ( strbuf_len < base64_encode_length(buf_len) + 1 )
251 while ( block_len % 3 )
254 for ( i = 0; i < block_len; i += 3 )
256 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
257 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
258 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )];
259 strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )];
269 strbuf[out_char++] = base64_chars[( buf[0] >> 2 )];
273 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )];
274 strbuf[out_char++] = fill;
276 else if ( diff == 2 )
278 strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )];
279 strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )];
282 strbuf[out_char++] = fill;
285 strbuf[out_char] = 0;
292 // Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if
293 // the binary buffer was large enough to hold the result. The output parameter
294 // 'char_count' will contain the length of the converted string. If the output
295 // buffer is too small or any of the pointer arguments are NULL, the subroutine
296 // will return -1 and set 'char_count' to the required buffer size. No data will
297 // be written to 'buf' if the subroutine fails.
300 Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count)
302 register byte_t c = 0, d = 0;
303 register ui32_t phase = 0, i = 0;
305 if ( str == 0 || buf == 0 || char_count == 0 )
308 while ( *str != 0 && i < buf_len )
310 c = decode_map[(int)*str++];
311 if ( c == 0xff ) continue;
312 if ( c == 0xfe ) break;
321 buf[i - 1] |= c >> 4;
326 buf[i++] = ( d << 4 ) | ( c >> 2 );
331 buf[i++] = ( d << 6 ) | c;
341 //------------------------------------------------------------------------------------------
343 // convert utf-8 hext string to bin
345 Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
349 KM_TEST_NULL_L(conv_size);
353 if ( str[0] == 0 ) // nothing to convert
356 for ( int j = 0; str[j]; j++ )
358 if ( isxdigit(str[j]) )
362 if ( *conv_size & 0x01 ) (*conv_size)++;
365 if ( *conv_size > buf_len )// maximum possible data size
370 int phase = 0; // track high/low nybble
372 // for each character, fill in the high nybble then the low
373 for ( int i = 0; str[i]; i++ )
375 if ( ! isxdigit(str[i]) )
378 byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
382 buf[*conv_size] = val << 4;
387 buf[*conv_size] |= val;
396 #ifdef CONFIG_RANDOM_UUID
398 // convert a memory region to a NULL-terminated hexadecimal string
401 bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
405 || ((bin_len * 2) + 1) > str_len )
409 Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
410 Kumu::FortunaRNG RNG;
411 RNG.FillRandom(rand_buf, bin_len);
413 for ( ui32_t i = 0; i < bin_len; i++ )
415 *p = (bin_buf[i] >> 4) & 0x0f;
416 *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
419 *p = bin_buf[i] & 0x0f;
420 *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
429 // convert a memory region to a NULL-terminated hexadecimal string
432 Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
436 || ((bin_len * 2) + 1) > str_len )
439 #ifdef CONFIG_RANDOM_UUID
440 const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID");
441 if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
442 return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
447 for ( ui32_t i = 0; i < bin_len; i++ )
449 *p = (bin_buf[i] >> 4) & 0x0f;
450 *p += *p < 10 ? 0x30 : 0x61 - 10;
453 *p = bin_buf[i] & 0x0f;
454 *p += *p < 10 ? 0x30 : 0x61 - 10;
463 // spew a range of bin data as hex
465 Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
473 static ui32_t row_len = 16;
474 const byte_t* p = buf;
475 const byte_t* end_p = p + dump_len;
477 for ( ui32_t line = 0; p < end_p; line++ )
479 fprintf(stream, " %06x: ", line);
483 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
484 fprintf(stream, "%02x ", *pp);
486 while ( i++ < row_len )
489 for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
490 fputc((isprint(*pp) ? *pp : '.'), stream);
499 Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
503 if ( str_len < 34 || bin_len != UUID_Length )
506 if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 )
510 for ( k = 19, i = 12; i > 0; i-- )
511 str_buf[k+i+4] = str_buf[k+i];
513 // shift the time (mid+hi+clk)
514 for ( k = 15, j = 3; k > 6; k -= 4, j-- )
516 for ( i = 4; i > 0; i-- )
517 str_buf[k+i+j] = str_buf[k+i];
520 // add in the hyphens and trainling null
521 for ( i = 8; i < 24; i += 5 )
530 Kumu::GenRandomValue(UUID& ID)
532 byte_t tmp_buf[UUID_Length];
533 GenRandomUUID(tmp_buf);
548 Kumu::GenRandomUUID(byte_t* buf)
551 RNG.FillRandom(buf, UUID_Length);
552 buf[6] &= 0x0f; // clear bits 4-7
553 buf[6] |= 0x40; // set UUID version
554 buf[8] &= 0x3f; // clear bits 6&7
555 buf[8] |= 0x80; // set bit 7
560 Kumu::GenRandomValue(SymmetricKey& Key)
562 byte_t tmp_buf[SymmetricKey_Length];
564 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
569 //------------------------------------------------------------------------------------------
570 // read a ber value from the buffer and compare with test value.
571 // Advances buffer to first character after BER value.
574 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
579 if ( ( **buf & 0x80 ) == 0 )
583 ui8_t ber_size = ( **buf & 0x0f ) + 1;
588 for ( ui8_t i = 1; i < ber_size; i++ )
591 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
595 return ( val == test_value );
601 Kumu::read_BER(const byte_t* buf, ui64_t* val)
605 if ( buf == 0 || val == 0 )
608 if ( ( *buf & 0x80 ) == 0 )
612 ber_size = ( *buf & 0x0f ) + 1;
617 for ( i = 1; i < ber_size; i++ )
620 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
627 static const ui64_t ber_masks[9] =
628 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
629 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
630 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
631 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
637 Kumu::get_BER_length_for_value(ui64_t val)
639 for ( ui32_t i = 0; i < 9; i++ )
641 if ( ( val & ber_masks[i] ) == 0 )
645 ui64Printer tmp_i(val);
646 DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
652 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
658 { // calculate default length
659 if ( val < 0x01000000L )
661 else if ( val < ui64_C(0x0100000000000000) )
667 { // sanity check BER length
670 DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len);
674 if ( ( val & ber_masks[ber_len - 1] ) != 0 )
676 ui64Printer tmp_i(val);
677 DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str());
682 buf[0] = 0x80 + ( ber_len - 1 );
684 for ( ui32_t i = ber_len - 1; i > 0; i-- )
686 buf[i] = (ui8_t)(val & 0xff);
694 //------------------------------------------------------------------------------------------
701 Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) {
712 Kumu::Timestamp::Timestamp(const Timestamp& rhs) {
713 m_Timestamp = rhs.m_Timestamp;
714 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
717 Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) {
718 DecodeString(datestr);
721 Kumu::Timestamp::~Timestamp() {
725 const Kumu::Timestamp&
726 Kumu::Timestamp::operator=(const Timestamp& rhs)
728 m_Timestamp = rhs.m_Timestamp;
729 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
733 bool Kumu::Timestamp::operator<(const Timestamp& rhs) const {
734 return m_Timestamp.x < rhs.m_Timestamp.x;
737 bool Kumu::Timestamp::operator>(const Timestamp& rhs) const {
738 return m_Timestamp.x > rhs.m_Timestamp.x;
741 bool Kumu::Timestamp::operator==(const Timestamp& rhs) const {
742 return m_Timestamp.x == rhs.m_Timestamp.x;
745 bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const {
746 return m_Timestamp.x != rhs.m_Timestamp.x;
751 Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
752 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const
757 Month = ct.date.month;
766 Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
767 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second)
771 ct.date.month = Month;
778 m_TZOffsetMinutes = 0;
781 // returns false if the requested adjustment is out of range
783 Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes)
785 static const i32_t tz_limit = 14 * 60 * 60;
787 if ( minutes < ( - tz_limit) || minutes > tz_limit )
790 m_TZOffsetMinutes = minutes;
796 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
798 if ( buf_len < ( DateTimeLen + 1 ) )
802 ui8_t month, day, hour, minute, second;
803 ui32_t ofst_hours = 0, ofst_minutes = 0;
804 char direction = '+';
806 if ( m_TZOffsetMinutes == 0 )
808 GetComponents(year, month, day, hour, minute, second);
812 // calculate local time
813 Kumu::Timestamp tmp_t(*this);
814 tmp_t.AddMinutes(m_TZOffsetMinutes);
815 tmp_t.GetComponents(year, month, day, hour, minute, second);
817 ofst_hours = abs(m_TZOffsetMinutes) / 60;
818 ofst_minutes = abs(m_TZOffsetMinutes) % 60;
820 if ( m_TZOffsetMinutes < 0 )
824 // 2004-05-01T13:20:00+00:00
825 snprintf(str_buf, buf_len,
826 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
827 year, month, day, hour, minute, second,
828 direction, ofst_hours, ofst_minutes);
835 Kumu::Timestamp::DecodeString(const char* datestr)
837 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
839 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
841 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
844 ui32_t char_count = 10;
847 YMDhms.date.year = atoi(datestr);
848 YMDhms.date.month = atoi(datestr + 5);
849 YMDhms.date.day = atoi(datestr + 8);
851 if ( datestr[10] == 'T' )
853 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
854 || datestr[13] != ':'
855 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
859 YMDhms.hour = atoi(datestr + 11);
860 YMDhms.minute = atoi(datestr + 14);
862 if ( datestr[16] == ':' )
864 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
868 YMDhms.second = atoi(datestr + 17);
871 if ( datestr[19] == '.' )
873 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
876 // we don't carry the ms value
880 if ( datestr[19] == '-' || datestr[19] == '+' )
882 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
883 || datestr[22] != ':'
884 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
889 ui32_t TZ_hh = atoi(datestr + 20);
890 ui32_t TZ_mm = atoi(datestr + 23);
891 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
894 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
895 if (datestr[19] == '-')
896 TZ_offset = -TZ_offset;
897 /* at this point, TZ_offset reflects the contents of the string */
899 /* a negative offset is behind UTC and so needs to increment to
900 * convert, while a positive offset must do the reverse */
901 YMDhms.offset = TZ_offset;
903 else if (datestr[19] == 'Z')
905 /* act as if the offset were +00:00 */
910 if ( datestr[char_count] != 0 )
912 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
913 datestr, char_count);
917 m_Timestamp = YMDhms;
918 m_TZOffsetMinutes = YMDhms.offset;
924 Kumu::Timestamp::HasValue() const
931 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
934 ui8_t month, day, hour, minute, second, tick;
937 if ( ! Reader->ReadUi16BE(&year) ) return false;
938 if ( ! Reader->ReadUi8(&month) ) return false;
939 if ( ! Reader->ReadUi8(&day) ) return false;
940 if ( ! Reader->ReadUi8(&hour) ) return false;
941 if ( ! Reader->ReadUi8(&minute) ) return false;
942 if ( ! Reader->ReadUi8(&second) ) return false;
943 if ( ! Reader->ReadUi8(&tick) ) return false;
944 SetComponents(year, month, day, hour, minute, second);
950 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
955 ui8_t month, day, hour, minute, second, tick = 0;
956 GetComponents(year, month, day, hour, minute, second);
958 if ( ! Writer->WriteUi16BE(year) ) return false;
959 if ( ! Writer->WriteUi8(month) ) return false;
960 if ( ! Writer->WriteUi8(day) ) return false;
961 if ( ! Writer->WriteUi8(hour) ) return false;
962 if ( ! Writer->WriteUi8(minute) ) return false;
963 if ( ! Writer->WriteUi8(second) ) return false;
964 if ( ! Writer->WriteUi8(tick) ) return false;
970 Kumu::Timestamp::GetCTime() const
972 return m_Timestamp.x - ui64_C(4611686018427387914);
976 //------------------------------------------------------------------------------------------
978 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
979 : m_p(0), m_capacity(0), m_size(0)
982 m_capacity = Buf->Capacity();
983 assert(m_p); assert(m_capacity);
987 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
989 if ( ( m_size + ber_len ) > m_capacity )
992 if ( ! write_BER(m_p + m_size, i, ber_len) )
1000 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
1001 : m_p(0), m_capacity(0), m_size(0)
1003 m_p = Buf->RoData();
1004 m_capacity = Buf->Length();
1005 assert(m_p); assert(m_capacity);
1009 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1011 if ( i == 0 || ber_len == 0 ) return false;
1013 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1016 if ( ( m_size + *ber_len ) > m_capacity )
1019 if ( ! read_BER(m_p + m_size, i) )
1026 //------------------------------------------------------------------------------------------
1028 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1030 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1035 Kumu::ByteString::~ByteString()
1042 // copy the given data into the ByteString, set Length value.
1043 // Returns error if the ByteString is too small.
1045 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1047 if ( m_Capacity < buf_len )
1048 return RESULT_ALLOC;
1050 memcpy(m_Data, buf, buf_len);
1056 // copy the given data into the ByteString, set Length value.
1057 // Returns error if the ByteString is too small.
1059 Kumu::ByteString::Set(const ByteString& Buf)
1061 if ( m_Capacity < Buf.m_Capacity )
1062 return RESULT_ALLOC;
1064 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1065 m_Length = Buf.m_Length;
1070 // Sets the size of the internally allocate buffer.
1072 Kumu::ByteString::Capacity(ui32_t cap_size)
1074 if ( m_Capacity >= cap_size )
1077 byte_t* tmp_data = 0;
1086 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1087 return RESULT_ALLOC;
1089 if ( tmp_data != 0 )
1091 assert(m_Length > 0);
1092 memcpy(m_Data, tmp_data, m_Length);
1096 m_Capacity = cap_size;
1102 Kumu::ByteString::Append(const ByteString& Buf)
1104 Result_t result = RESULT_OK;
1105 ui32_t diff = m_Capacity - m_Length;
1107 if ( diff < Buf.Length() )
1108 result = Capacity(m_Capacity + Buf.Length());
1110 if ( KM_SUCCESS(result) )
1112 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1113 m_Length += Buf.Length();
1121 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1123 Result_t result = RESULT_OK;
1124 ui32_t diff = m_Capacity - m_Length;
1126 if ( diff < buf_len )
1127 result = Capacity(m_Capacity + buf_len);
1129 if ( KM_SUCCESS(result) )
1131 memcpy(m_Data + m_Length, buf, buf_len);
1132 m_Length += buf_len;