700 lines
No EOL
17 KiB
C++
700 lines
No EOL
17 KiB
C++
/*
|
|
|
|
Copyright (C) 2019 AleaJactaEst
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Build :
|
|
scons platform=linux bits=64
|
|
|
|
*/
|
|
|
|
// Temporary workaround until c++11 alignas()
|
|
#ifdef __GNUC__
|
|
#define GCC_ALIGNED_8 __attribute__((aligned(8)))
|
|
#else
|
|
#define GCC_ALIGNED_8
|
|
#endif
|
|
|
|
#include "modules/bitstream/bitstream.h"
|
|
#include "modules/debug/debug.h"
|
|
#include "modules/bitstream/convert_utf16.h"
|
|
|
|
// TODO - check if on godot we have a function or variable to get if processor is little_endian or not
|
|
bool little_endian = false;
|
|
|
|
void BitStream::_bind_methods()
|
|
{
|
|
BitStream::init();
|
|
|
|
ClassDB::bind_method(D_METHOD("is_little_endian"), &BitStream::is_little_endian);
|
|
|
|
ClassDB::bind_method(D_METHOD("complet_byte"), &BitStream::complet_byte);
|
|
ClassDB::bind_method(D_METHOD("size"), &BitStream::size);
|
|
ClassDB::bind_method(D_METHOD("size_data"), &BitStream::size_data);
|
|
ClassDB::bind_method(D_METHOD("number_bit_not_read"), &BitStream::number_bit_not_read);
|
|
|
|
ClassDB::bind_method(D_METHOD("put_serial", "value", "nbits"), &BitStream::put_serial);
|
|
ClassDB::bind_method(D_METHOD("put_bool", "value"), &BitStream::put_bool);
|
|
ClassDB::bind_method(D_METHOD("put_char", "value"), &BitStream::put_char);
|
|
ClassDB::bind_method(D_METHOD("put_uint8", "value"), &BitStream::put_uint8);
|
|
ClassDB::bind_method(D_METHOD("put_sint8", "value"), &BitStream::put_sint8);
|
|
ClassDB::bind_method(D_METHOD("put_sint16", "value"), &BitStream::put_sint16);
|
|
ClassDB::bind_method(D_METHOD("put_uint16", "value"), &BitStream::put_uint16);
|
|
ClassDB::bind_method(D_METHOD("put_sint32", "value"), &BitStream::put_sint32);
|
|
ClassDB::bind_method(D_METHOD("put_uint32", "value"), &BitStream::put_uint32);
|
|
ClassDB::bind_method(D_METHOD("put_sint64", "value"), &BitStream::put_sint64);
|
|
ClassDB::bind_method(D_METHOD("put_uint64", "value"), &BitStream::put_uint64);
|
|
ClassDB::bind_method(D_METHOD("put_string", "value"), &BitStream::put_string);
|
|
ClassDB::bind_method(D_METHOD("put_string_hexa32", "hexa"), &BitStream::put_string_hexa32);
|
|
ClassDB::bind_method(D_METHOD("put_array_uint8", "value"), &BitStream::put_array_uint8);
|
|
ClassDB::bind_method(D_METHOD("put_version", "value"), &BitStream::put_version);
|
|
ClassDB::bind_method(D_METHOD("put_string_utf16", "value"), &BitStream::put_string_utf16);
|
|
|
|
ClassDB::bind_method(D_METHOD("show"), &BitStream::show);
|
|
ClassDB::bind_method(D_METHOD("show_detail"), &BitStream::show_detail);
|
|
ClassDB::bind_method(D_METHOD("show_counter"), &BitStream::show_counter);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_data"), &BitStream::get_data);
|
|
ClassDB::bind_method(D_METHOD("put_data", "value"), &BitStream::put_data);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_serial", "nbits"), &BitStream::get_serial);
|
|
ClassDB::bind_method(D_METHOD("get_bool"), &BitStream::get_bool);
|
|
ClassDB::bind_method(D_METHOD("get_sint8"), &BitStream::get_sint8);
|
|
ClassDB::bind_method(D_METHOD("get_uint8"), &BitStream::get_uint8);
|
|
ClassDB::bind_method(D_METHOD("get_sint16"), &BitStream::get_sint16);
|
|
ClassDB::bind_method(D_METHOD("get_uint16"), &BitStream::get_uint16);
|
|
ClassDB::bind_method(D_METHOD("get_sint32"), &BitStream::get_sint32);
|
|
ClassDB::bind_method(D_METHOD("get_uint32"), &BitStream::get_uint32);
|
|
ClassDB::bind_method(D_METHOD("get_sint64"), &BitStream::get_sint64);
|
|
ClassDB::bind_method(D_METHOD("get_uint64"), &BitStream::get_uint64);
|
|
ClassDB::bind_method(D_METHOD("get_version"), &BitStream::get_version);
|
|
ClassDB::bind_method(D_METHOD("get_array_uint8", "length"), &BitStream::get_array_uint8);
|
|
//ClassDB::bind_method(D_METHOD("get_bitstream", "length"), &BitStream::get_bitstream);
|
|
ClassDB::bind_method(D_METHOD("get_string"), &BitStream::get_string);
|
|
ClassDB::bind_method(D_METHOD("get_string_utf16"), &BitStream::get_string_utf16);
|
|
ClassDB::bind_method(D_METHOD("get_string_utf8"), &BitStream::get_string_utf8);
|
|
|
|
}
|
|
|
|
void BitStream::clear()
|
|
{
|
|
this->_pos = 0;
|
|
this->_read = 0;
|
|
}
|
|
|
|
BitStream::BitStream()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
BitStream::~BitStream()
|
|
{
|
|
// add your cleanup here
|
|
}
|
|
|
|
void BitStream::init()
|
|
{
|
|
uint32_t i=0x12345678;
|
|
if ( (*((uint8_t*)(&i))) == 0x78 )
|
|
little_endian = true;
|
|
else
|
|
little_endian = false;
|
|
}
|
|
|
|
bool BitStream::is_little_endian()
|
|
{
|
|
return little_endian;
|
|
}
|
|
|
|
void BitStream::complet_byte()
|
|
{
|
|
// function to add 0 and have size multiple of 8 bit
|
|
this->_pos = ((this->_pos + 7) / 8) * 8;
|
|
}
|
|
|
|
uint32_t BitStream::size()
|
|
{
|
|
return (this->_pos + 7) / 8;
|
|
}
|
|
|
|
uint32_t BitStream::size_data()
|
|
{
|
|
return this->_pos;
|
|
}
|
|
|
|
uint32_t BitStream::number_bit_not_read()
|
|
{
|
|
return this->_pos - this->_read;
|
|
}
|
|
|
|
void BitStream::put_serial(uint32_t value, uint32_t nbits)
|
|
{
|
|
uint32_t v;
|
|
uint32_t mask;
|
|
uint32_t freeBits;
|
|
uint32_t pos;
|
|
|
|
if ( nbits == 0 )
|
|
return;
|
|
else if ( nbits > 32 )
|
|
throw "Out of range";
|
|
if ( this->_pos % 8 == 0 ) // Increase node
|
|
this->_data.append(0);
|
|
if ( nbits != 32 )
|
|
{
|
|
mask = (1 << nbits) - 1;
|
|
v = value & mask;
|
|
}
|
|
else
|
|
{
|
|
v = value;
|
|
}
|
|
freeBits = 8 - (this->_pos % 8);
|
|
pos = this->_data.size() - 1;
|
|
if(nbits > freeBits)
|
|
{
|
|
this->_data.set(pos, this->_data[pos] | (v >> (nbits - freeBits)));
|
|
this->_pos += freeBits;
|
|
this->put_serial(v, nbits - freeBits);
|
|
}
|
|
else
|
|
{
|
|
this->_data.set(pos, this->_data[pos] | (v << (freeBits - nbits)));
|
|
this->_pos += nbits;
|
|
}
|
|
}
|
|
|
|
void BitStream::put_bool(bool value)
|
|
{
|
|
this->put_serial(value, 1);
|
|
}
|
|
|
|
void BitStream::put_sint8(int8_t value)
|
|
{
|
|
this->put_serial(value, 8);
|
|
}
|
|
|
|
void BitStream::put_uint8(uint8_t value)
|
|
{
|
|
this->put_serial(value, 8);
|
|
}
|
|
|
|
void BitStream::put_sint16(int16_t value)
|
|
{
|
|
this->put_serial(value, 16);
|
|
}
|
|
|
|
void BitStream::put_uint16(uint16_t value)
|
|
{
|
|
this->put_serial(value, 16);
|
|
}
|
|
|
|
void BitStream::put_sint32(int32_t value)
|
|
{
|
|
this->put_serial(value, 32);
|
|
}
|
|
|
|
void BitStream::put_uint32(uint32_t value)
|
|
{
|
|
this->put_serial(value, 32);
|
|
}
|
|
|
|
void BitStream::put_uint64(uint64_t value)
|
|
{
|
|
// khanat-opennel-code/code/nel/include/nel/misc/stream_inline.h inline void IStream::serial(uint64 &b)
|
|
// khanat-opennel-code/code/nel/include/nel/misc/stream.h #define NLMISC_BSWAP64(src) (src) = (((src)>>56)&0xFF) | ((((src)>>48)&0xFF)<<8) | ((((src)>>40)&0xFF)<<16) | ((((src)>>32)&0xFF)<<24) | ((((src)>>24)&0xFF)<<32) | ((((src)>>16)&0xFF)<<40) | ((((src)>>8)&0xFF)<<48) | (((src)&0xFF)<<56)
|
|
union {
|
|
uint64_t full;
|
|
uint8_t key[8];
|
|
} v GCC_ALIGNED_8;
|
|
v.full = value;
|
|
if(little_endian)
|
|
{
|
|
this->put_uint8(v.key[3]);
|
|
this->put_uint8(v.key[2]);
|
|
this->put_uint8(v.key[1]);
|
|
this->put_uint8(v.key[0]);
|
|
this->put_uint8(v.key[7]);
|
|
this->put_uint8(v.key[6]);
|
|
this->put_uint8(v.key[5]);
|
|
this->put_uint8(v.key[4]);
|
|
}
|
|
else
|
|
{
|
|
this->put_uint8(v.key[0]);
|
|
this->put_uint8(v.key[1]);
|
|
this->put_uint8(v.key[2]);
|
|
this->put_uint8(v.key[3]);
|
|
this->put_uint8(v.key[4]);
|
|
this->put_uint8(v.key[5]);
|
|
this->put_uint8(v.key[6]);
|
|
this->put_uint8(v.key[7]);
|
|
}
|
|
}
|
|
|
|
void BitStream::put_sint64(int64_t value)
|
|
{
|
|
put_uint64((uint64_t) value);
|
|
}
|
|
|
|
void BitStream::put_string_hexa32(String hexa)
|
|
{
|
|
uint32_t res = 0;
|
|
CharString tmp = hexa.ascii();
|
|
for(const char * c = tmp.get_data(); *c != 0; c++)
|
|
{
|
|
res <<= 4;
|
|
if ( *c >= '0' && *c <= '9')
|
|
res += *c - '0';
|
|
else if ( *c >= 'A' && *c <= 'F')
|
|
res += *c - 'A' + 10;
|
|
}
|
|
this->put_serial(res,32);
|
|
}
|
|
|
|
void BitStream::put_char(String value)
|
|
{
|
|
if ( value.length() >= 1)
|
|
this->put_uint8( value[0] );
|
|
else
|
|
this->put_uint8( 0 );
|
|
}
|
|
|
|
void BitStream::put_string(String value)
|
|
{
|
|
CharString data = value.ascii();
|
|
int lenvalue = data.size() - 1;
|
|
this->put_uint32(lenvalue);
|
|
for(int i = 0; i < lenvalue; ++i)
|
|
{
|
|
this->put_uint8(data[i]);
|
|
}
|
|
}
|
|
|
|
void BitStream::put_array_uint8(PoolByteArray value)
|
|
{
|
|
for(int i = 0; i < value.size() ; ++i)
|
|
this->put_serial(value[i], 8);
|
|
}
|
|
|
|
void BitStream::put_bitstream(BitStream & value)
|
|
{
|
|
uint32_t last_read;
|
|
uint32_t nb;
|
|
last_read = value._read;
|
|
value._read = 0;
|
|
while ( value.number_bit_not_read() >= 32 )
|
|
put_uint32(value.get_uint32());
|
|
while ( value.number_bit_not_read() >= 16 )
|
|
put_uint16(value.get_uint16());
|
|
while ( value.number_bit_not_read() >= 8 )
|
|
put_uint8(value.get_uint8());
|
|
nb = value.number_bit_not_read();
|
|
if( nb > 0 )
|
|
put_serial(value.get_serial(nb), nb);
|
|
|
|
// restore pos read
|
|
value._read = last_read;
|
|
}
|
|
|
|
void BitStream::put_bitstream(BitStream * value)
|
|
{
|
|
uint32_t last_read;
|
|
uint32_t nb;
|
|
last_read = value->_read;
|
|
value->_read = 0;
|
|
while ( value->number_bit_not_read() >= 32 )
|
|
put_uint32(value->get_uint32());
|
|
while ( value->number_bit_not_read() >= 16 )
|
|
put_uint16(value->get_uint16());
|
|
while ( value->number_bit_not_read() >= 8 )
|
|
put_uint8(value->get_uint8());
|
|
nb = value->number_bit_not_read();
|
|
if( nb > 0 )
|
|
put_serial(value->get_serial(nb), nb);
|
|
DBG_PRINT("put_bitstream: " + itos(nb) + " / " + itos(_pos));
|
|
|
|
// restore pos read
|
|
value->_read = last_read;
|
|
}
|
|
|
|
void BitStream::put_version(uint32_t value)
|
|
{
|
|
if ( value < 255 ) // 0xff
|
|
{
|
|
this->put_uint8(value);
|
|
}
|
|
else
|
|
{
|
|
this->put_uint8(255);
|
|
this->put_uint32(value);
|
|
}
|
|
}
|
|
|
|
void BitStream::put_float(float value)
|
|
{
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} data GCC_ALIGNED_8;
|
|
data.f = value;
|
|
put_uint32(data.u);
|
|
}
|
|
|
|
void BitStream::put_string_utf16(String value)
|
|
{
|
|
uint16_t * u16_buf = NULL;
|
|
size_t u16_len = 0;
|
|
convert_utf8_to_utf16(value, &u16_buf, &u16_len);
|
|
|
|
this->put_uint32(u16_len);
|
|
|
|
if ( u16_len == 0 )
|
|
return;
|
|
|
|
for(uint32_t i=0;i<u16_len;++i)
|
|
{
|
|
this->put_uint16(u16_buf[i]);
|
|
}
|
|
delete [] u16_buf;
|
|
}
|
|
|
|
String BitStream::show()
|
|
{
|
|
String ret;
|
|
uint32_t pos = 0;
|
|
for(int i = 0; i < this->_data.size(); ++i)
|
|
{
|
|
uint8_t c = this->_data[i];
|
|
uint8_t mask = 0x80;
|
|
while(mask)
|
|
{
|
|
if ( (c & mask) != 0 )
|
|
ret += String("1");
|
|
else
|
|
ret += String("0");
|
|
mask >>= 1;
|
|
pos += 1;
|
|
if (pos >= this->_pos)
|
|
break;
|
|
}
|
|
if (pos >= this->_pos)
|
|
break;
|
|
}
|
|
return ret ;
|
|
}
|
|
|
|
String BitStream::show_detail()
|
|
{
|
|
String ret;
|
|
uint32_t pos = 0;
|
|
for(int i = 0; i < this->_data.size(); ++i)
|
|
{
|
|
uint8_t c = this->_data[i];
|
|
uint8_t mask = 0x80;
|
|
while(mask)
|
|
{
|
|
if ( (c & mask) != 0 )
|
|
ret += String("1");
|
|
else
|
|
ret += String("0");
|
|
mask >>= 1;
|
|
pos += 1;
|
|
if (pos >= this->_pos)
|
|
break;
|
|
}
|
|
if (pos >= this->_pos)
|
|
break;
|
|
}
|
|
String strsize;
|
|
uint32_t t = this->_data.size();
|
|
if ( t == 0) strsize = "0";
|
|
while ( t > 0 )
|
|
{
|
|
const char c = '0' + ( t % 10 );
|
|
CharString tmp ;
|
|
tmp += c;
|
|
strsize = tmp + strsize;
|
|
t /= 10;
|
|
}
|
|
|
|
String strpos;
|
|
t = this->_pos;
|
|
if ( t == 0) strpos = "0";
|
|
while ( t > 0 )
|
|
{
|
|
const char c = '0' + ( t % 10 );
|
|
CharString tmp ;
|
|
tmp += c;
|
|
strpos = tmp + strpos;
|
|
t /= 10;
|
|
}
|
|
|
|
return "[size:" + String(strsize) + ", pos:" + String(strpos) + "]" + ret ;
|
|
}
|
|
|
|
String BitStream::show_counter()
|
|
{
|
|
String ret = "[" + String::num_int64(this->_read) + " / " + String::num_int64(this->_pos) + "]";
|
|
|
|
return ret;
|
|
}
|
|
|
|
PoolByteArray BitStream::get_data()
|
|
{
|
|
return this->_data;
|
|
}
|
|
|
|
void BitStream::put_data(PoolByteArray value)
|
|
{
|
|
this->_data = value;
|
|
this->_pos = value.size() * 8;
|
|
}
|
|
|
|
|
|
void BitStream::copy_ref_bitstream(Ref<BitStream> value)
|
|
{
|
|
this->_data = value->_data; //*value.ptr();
|
|
this->_pos = value->_pos; // ->size() * 8;
|
|
this->_read = value->_read;
|
|
}
|
|
|
|
void BitStream::copy_bitstream(BitStream & value)
|
|
{
|
|
this->_data = value._data; //*value.ptr();
|
|
this->_pos = value._pos; // ->size() * 8;
|
|
this->_read = value._read;
|
|
}
|
|
|
|
uint32_t BitStream::get_serial(uint32_t nbits)
|
|
{
|
|
uint32_t value;
|
|
uint32_t pos;
|
|
uint32_t freeBits;
|
|
uint32_t v;
|
|
|
|
if ( nbits == 0 )
|
|
return 0;
|
|
else if ( nbits > 32 )
|
|
{
|
|
ERR_PRINT("Out of range (BitStream::get_serial)");
|
|
throw "Out of range";
|
|
}
|
|
if (this->_read + nbits > this->_pos)
|
|
{
|
|
ERR_PRINT("Out of range (BitStream::get_serial)");
|
|
throw "Out of range";
|
|
}
|
|
value = 0;
|
|
pos = this->_read / 8;
|
|
freeBits = 8 - (this->_read % 8);
|
|
v = this->_data[pos] & ((1 << freeBits) - 1);
|
|
if(nbits > freeBits)
|
|
{
|
|
value |= (v << (nbits-freeBits));
|
|
this->_read += freeBits;
|
|
value |= this->get_serial(nbits - freeBits);
|
|
}
|
|
else
|
|
{
|
|
value |= (v >> (freeBits-nbits));
|
|
this->_read += nbits;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
bool BitStream::get_bool()
|
|
{
|
|
if(this->get_serial(1) == 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
int8_t BitStream::get_sint8()
|
|
{
|
|
return this->get_serial(8);
|
|
}
|
|
|
|
uint8_t BitStream::get_uint8()
|
|
{
|
|
return this->get_serial(8);
|
|
}
|
|
|
|
int16_t BitStream::get_sint16()
|
|
{
|
|
return this->get_serial(16);
|
|
}
|
|
|
|
uint16_t BitStream::get_uint16()
|
|
{
|
|
return this->get_serial(16);
|
|
}
|
|
|
|
int32_t BitStream::get_sint32()
|
|
{
|
|
return this->get_serial(32);
|
|
}
|
|
|
|
uint32_t BitStream::get_uint32()
|
|
{
|
|
return this->get_serial(32);
|
|
}
|
|
|
|
uint64_t BitStream::get_uint64()
|
|
{
|
|
// khanat-opennel-code/code/nel/include/nel/misc/stream_inline.h inline void IStream::serial(uint64 &b)
|
|
// khanat-opennel-code/code/nel/include/nel/misc/stream.h #define NLMISC_BSWAP64(src) (src) = (((src)>>56)&0xFF) | ((((src)>>48)&0xFF)<<8) | ((((src)>>40)&0xFF)<<16) | ((((src)>>32)&0xFF)<<24) | ((((src)>>24)&0xFF)<<32) | ((((src)>>16)&0xFF)<<40) | ((((src)>>8)&0xFF)<<48) | (((src)&0xFF)<<56)
|
|
union S {
|
|
uint64_t full;
|
|
uint8_t key[8];
|
|
} v GCC_ALIGNED_8;
|
|
if(little_endian)
|
|
{
|
|
v.key[3] = this->get_uint8();
|
|
v.key[2] = this->get_uint8();
|
|
v.key[1] = this->get_uint8();
|
|
v.key[0] = this->get_uint8();
|
|
v.key[7] = this->get_uint8();
|
|
v.key[6] = this->get_uint8();
|
|
v.key[5] = this->get_uint8();
|
|
v.key[4] = this->get_uint8();
|
|
}
|
|
else
|
|
{
|
|
v.key[0] = this->get_uint8();
|
|
v.key[1] = this->get_uint8();
|
|
v.key[2] = this->get_uint8();
|
|
v.key[3] = this->get_uint8();
|
|
v.key[4] = this->get_uint8();
|
|
v.key[5] = this->get_uint8();
|
|
v.key[6] = this->get_uint8();
|
|
v.key[7] = this->get_uint8();
|
|
}
|
|
return v.full;
|
|
}
|
|
|
|
int64_t BitStream::get_sint64()
|
|
{
|
|
return (int64_t) get_uint64();
|
|
}
|
|
|
|
uint32_t BitStream::get_version()
|
|
{
|
|
uint32_t ret;
|
|
ret = this->get_uint8();
|
|
if ( ret == 255 ) // 0xff
|
|
{
|
|
ret = this->get_uint32();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
float BitStream::get_float()
|
|
{
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} data GCC_ALIGNED_8;
|
|
data.u = get_uint32();
|
|
return data.f;
|
|
}
|
|
|
|
PoolByteArray BitStream::get_array_uint8(uint32_t length)
|
|
{
|
|
PoolByteArray ret;
|
|
while(length > 0)
|
|
{
|
|
ret.append(this->get_serial(8));
|
|
--length;
|
|
}
|
|
/*
|
|
if (length == 1)
|
|
{
|
|
int nb = this->number_bit_not_read();
|
|
ret.append(this->get_serial(nb));
|
|
}
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
BitStream BitStream::get_bitstream(uint32_t length)
|
|
{
|
|
BitStream a;
|
|
while(length != 0)
|
|
{
|
|
a.put_uint8(this->get_serial(8));
|
|
--length;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
String BitStream::get_string()
|
|
{
|
|
String ret;
|
|
uint32_t size = this->get_uint32();
|
|
while(size > 0)
|
|
{
|
|
union
|
|
{
|
|
uint8_t v;
|
|
char c;
|
|
} x GCC_ALIGNED_8;
|
|
x.v = this->get_uint8();
|
|
CharString cs;
|
|
cs += x.c;
|
|
ret += cs;
|
|
--size;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
String BitStream::get_string_utf16()
|
|
{
|
|
// https://en.wikipedia.org/wiki/UTF-16
|
|
// https://gist.github.com/rsms/716794
|
|
String ret;
|
|
uint32_t size = this->get_uint32();
|
|
uint32_t i = 0;
|
|
uint8_t tmp[size];
|
|
for(i=0;i<size;++i)
|
|
{
|
|
tmp[i] = this->get_uint16();
|
|
}
|
|
ret = convert_utf16_to_utf8(tmp, i);
|
|
return ret;
|
|
}
|
|
|
|
String BitStream::get_string_utf8()
|
|
{
|
|
// https://en.wikipedia.org/wiki/UTF-8
|
|
String ret;
|
|
uint32_t i;
|
|
uint32_t size = this->get_uint32();
|
|
char * src = new char[size+1];
|
|
src[size] = 0;
|
|
|
|
for(i=0;i<size;++i)
|
|
{
|
|
union {
|
|
uint8_t v;
|
|
char c;
|
|
} x GCC_ALIGNED_8;;
|
|
x.v = this->get_uint8();
|
|
src[i] = x.c;
|
|
}
|
|
ret = String::utf8(src);
|
|
delete [] src;
|
|
return ret;
|
|
} |