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);
539 Kumu::GenRandomUUID(byte_t* buf)
542 RNG.FillRandom(buf, UUID_Length);
543 buf[6] &= 0x0f; // clear bits 4-7
544 buf[6] |= 0x40; // set UUID version
545 buf[8] &= 0x3f; // clear bits 6&7
546 buf[8] |= 0x80; // set bit 7
551 Kumu::GenRandomValue(SymmetricKey& Key)
553 byte_t tmp_buf[SymmetricKey_Length];
555 RNG.FillRandom(tmp_buf, SymmetricKey_Length);
560 //------------------------------------------------------------------------------------------
561 // read a ber value from the buffer and compare with test value.
562 // Advances buffer to first character after BER value.
565 Kumu::read_test_BER(byte_t **buf, ui64_t test_value)
570 if ( ( **buf & 0x80 ) == 0 )
574 ui8_t ber_size = ( **buf & 0x0f ) + 1;
579 for ( ui8_t i = 1; i < ber_size; i++ )
582 val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
586 return ( val == test_value );
592 Kumu::read_BER(const byte_t* buf, ui64_t* val)
596 if ( buf == 0 || val == 0 )
599 if ( ( *buf & 0x80 ) == 0 )
603 ber_size = ( *buf & 0x0f ) + 1;
608 for ( i = 1; i < ber_size; i++ )
611 *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
618 static const ui64_t ber_masks[9] =
619 { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
620 ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
621 ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
622 ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
628 Kumu::get_BER_length_for_value(ui64_t val)
630 for ( ui32_t i = 0; i < 9; i++ )
632 if ( ( val & ber_masks[i] ) == 0 )
636 ui64Printer tmp_i(val);
637 DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str());
643 Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
649 { // calculate default length
650 if ( val < 0x01000000L )
652 else if ( val < ui64_C(0x0100000000000000) )
658 { // sanity check BER length
661 DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len);
665 if ( ( val & ber_masks[ber_len - 1] ) != 0 )
667 ui64Printer tmp_i(val);
668 DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str());
673 buf[0] = 0x80 + ( ber_len - 1 );
675 for ( ui32_t i = ber_len - 1; i > 0; i-- )
677 buf[i] = (ui8_t)(val & 0xff);
685 //------------------------------------------------------------------------------------------
692 Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) {
703 Kumu::Timestamp::Timestamp(const Timestamp& rhs) {
704 m_Timestamp = rhs.m_Timestamp;
705 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
708 Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) {
709 DecodeString(datestr);
712 Kumu::Timestamp::~Timestamp() {
716 const Kumu::Timestamp&
717 Kumu::Timestamp::operator=(const Timestamp& rhs)
719 m_Timestamp = rhs.m_Timestamp;
720 m_TZOffsetMinutes = rhs.m_TZOffsetMinutes;
724 bool Kumu::Timestamp::operator<(const Timestamp& rhs) const {
725 return m_Timestamp.x < rhs.m_Timestamp.x;
728 bool Kumu::Timestamp::operator>(const Timestamp& rhs) const {
729 return m_Timestamp.x > rhs.m_Timestamp.x;
732 bool Kumu::Timestamp::operator==(const Timestamp& rhs) const {
733 return m_Timestamp.x == rhs.m_Timestamp.x;
736 bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const {
737 return m_Timestamp.x != rhs.m_Timestamp.x;
742 Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day,
743 ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const
748 Month = ct.date.month;
757 Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day,
758 const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second)
762 ct.date.month = Month;
769 m_TZOffsetMinutes = 0;
772 // returns false if the requested adjustment is out of range
774 Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes)
776 static const i32_t tz_limit = 14 * 60 * 60;
778 if ( minutes < ( - tz_limit) || minutes > tz_limit )
781 m_TZOffsetMinutes = minutes;
787 Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const
789 if ( buf_len < ( DateTimeLen + 1 ) )
793 ui8_t month, day, hour, minute, second;
794 ui32_t ofst_hours = 0, ofst_minutes = 0;
795 char direction = '+';
797 if ( m_TZOffsetMinutes == 0 )
799 GetComponents(year, month, day, hour, minute, second);
803 // calculate local time
804 Kumu::Timestamp tmp_t(*this);
805 tmp_t.AddMinutes(m_TZOffsetMinutes);
806 tmp_t.GetComponents(year, month, day, hour, minute, second);
808 ofst_hours = abs(m_TZOffsetMinutes) / 60;
809 ofst_minutes = abs(m_TZOffsetMinutes) % 60;
811 if ( m_TZOffsetMinutes < 0 )
815 // 2004-05-01T13:20:00+00:00
816 snprintf(str_buf, buf_len,
817 "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu",
818 year, month, day, hour, minute, second,
819 direction, ofst_hours, ofst_minutes);
826 Kumu::Timestamp::DecodeString(const char* datestr)
828 if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) )
830 || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) )
832 || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) )
835 ui32_t char_count = 10;
838 YMDhms.date.year = atoi(datestr);
839 YMDhms.date.month = atoi(datestr + 5);
840 YMDhms.date.day = atoi(datestr + 8);
842 if ( datestr[10] == 'T' )
844 if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) )
845 || datestr[13] != ':'
846 || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) )
850 YMDhms.hour = atoi(datestr + 11);
851 YMDhms.minute = atoi(datestr + 14);
853 if ( datestr[16] == ':' )
855 if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) )
859 YMDhms.second = atoi(datestr + 17);
862 if ( datestr[19] == '.' )
864 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) )
867 // we don't carry the ms value
871 if ( datestr[19] == '-' || datestr[19] == '+' )
873 if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) )
874 || datestr[22] != ':'
875 || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) )
880 ui32_t TZ_hh = atoi(datestr + 20);
881 ui32_t TZ_mm = atoi(datestr + 23);
882 if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0)))
885 i32_t TZ_offset = 60 * TZ_hh + TZ_mm;
886 if (datestr[19] == '-')
887 TZ_offset = -TZ_offset;
888 /* at this point, TZ_offset reflects the contents of the string */
890 /* a negative offset is behind UTC and so needs to increment to
891 * convert, while a positive offset must do the reverse */
892 YMDhms.offset = TZ_offset;
894 else if (datestr[19] == 'Z')
896 /* act as if the offset were +00:00 */
901 if ( datestr[char_count] != 0 )
903 Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n",
904 datestr, char_count);
908 m_Timestamp = YMDhms;
909 m_TZOffsetMinutes = YMDhms.offset;
915 Kumu::Timestamp::HasValue() const
922 Kumu::Timestamp::Unarchive(MemIOReader* Reader)
925 ui8_t month, day, hour, minute, second, tick;
928 if ( ! Reader->ReadUi16BE(&year) ) return false;
929 if ( ! Reader->ReadUi8(&month) ) return false;
930 if ( ! Reader->ReadUi8(&day) ) return false;
931 if ( ! Reader->ReadUi8(&hour) ) return false;
932 if ( ! Reader->ReadUi8(&minute) ) return false;
933 if ( ! Reader->ReadUi8(&second) ) return false;
934 if ( ! Reader->ReadUi8(&tick) ) return false;
935 SetComponents(year, month, day, hour, minute, second);
941 Kumu::Timestamp::Archive(MemIOWriter* Writer) const
946 ui8_t month, day, hour, minute, second, tick = 0;
947 GetComponents(year, month, day, hour, minute, second);
949 if ( ! Writer->WriteUi16BE(year) ) return false;
950 if ( ! Writer->WriteUi8(month) ) return false;
951 if ( ! Writer->WriteUi8(day) ) return false;
952 if ( ! Writer->WriteUi8(hour) ) return false;
953 if ( ! Writer->WriteUi8(minute) ) return false;
954 if ( ! Writer->WriteUi8(second) ) return false;
955 if ( ! Writer->WriteUi8(tick) ) return false;
961 Kumu::Timestamp::GetCTime() const
963 return m_Timestamp.x - ui64_C(4611686018427387914);
967 //------------------------------------------------------------------------------------------
969 Kumu::MemIOWriter::MemIOWriter(ByteString* Buf)
970 : m_p(0), m_capacity(0), m_size(0)
973 m_capacity = Buf->Capacity();
974 assert(m_p); assert(m_capacity);
978 Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len)
980 if ( ( m_size + ber_len ) > m_capacity )
983 if ( ! write_BER(m_p + m_size, i, ber_len) )
991 Kumu::MemIOReader::MemIOReader(const ByteString* Buf)
992 : m_p(0), m_capacity(0), m_size(0)
995 m_capacity = Buf->Length();
996 assert(m_p); assert(m_capacity);
1000 Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len)
1002 if ( i == 0 || ber_len == 0 ) return false;
1004 if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 )
1007 if ( ( m_size + *ber_len ) > m_capacity )
1010 if ( ! read_BER(m_p + m_size, i) )
1017 //------------------------------------------------------------------------------------------
1019 Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {}
1021 Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0)
1026 Kumu::ByteString::~ByteString()
1033 // copy the given data into the ByteString, set Length value.
1034 // Returns error if the ByteString is too small.
1036 Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len)
1038 if ( m_Capacity < buf_len )
1039 return RESULT_ALLOC;
1041 memcpy(m_Data, buf, buf_len);
1047 // copy the given data into the ByteString, set Length value.
1048 // Returns error if the ByteString is too small.
1050 Kumu::ByteString::Set(const ByteString& Buf)
1052 if ( m_Capacity < Buf.m_Capacity )
1053 return RESULT_ALLOC;
1055 memcpy(m_Data, Buf.m_Data, Buf.m_Length);
1056 m_Length = Buf.m_Length;
1061 // Sets the size of the internally allocate buffer.
1063 Kumu::ByteString::Capacity(ui32_t cap_size)
1065 if ( m_Capacity >= cap_size )
1068 byte_t* tmp_data = 0;
1077 if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 )
1078 return RESULT_ALLOC;
1080 if ( tmp_data != 0 )
1082 assert(m_Length > 0);
1083 memcpy(m_Data, tmp_data, m_Length);
1087 m_Capacity = cap_size;
1093 Kumu::ByteString::Append(const ByteString& Buf)
1095 Result_t result = RESULT_OK;
1096 ui32_t diff = m_Capacity - m_Length;
1098 if ( diff < Buf.Length() )
1099 result = Capacity(m_Capacity + Buf.Length());
1101 if ( KM_SUCCESS(result) )
1103 memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length());
1104 m_Length += Buf.Length();
1112 Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len)
1114 Result_t result = RESULT_OK;
1115 ui32_t diff = m_Capacity - m_Length;
1117 if ( diff < buf_len )
1118 result = Capacity(m_Capacity + buf_len);
1120 if ( KM_SUCCESS(result) )
1122 memcpy(m_Data + m_Length, buf, buf_len);
1123 m_Length += buf_len;