457 lines
10 KiB
C++
457 lines
10 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
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "bitstream.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("size"), &BitStream::size);
|
||
|
|
||
|
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("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_array_uint8", "length"), &BitStream::get_array_uint8);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
int BitStream::size()
|
||
|
{
|
||
|
return (this->_pos + 7) / 8;
|
||
|
}
|
||
|
|
||
|
int BitStream::size_data()
|
||
|
{
|
||
|
return this->_pos;
|
||
|
}
|
||
|
|
||
|
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_sint64(int64_t value)
|
||
|
{
|
||
|
if(little_endian)
|
||
|
{
|
||
|
this->put_serial(value>>32, 32);
|
||
|
this->put_serial(value, 32);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this->put_serial(value, 32);
|
||
|
this->put_serial(value>>32, 32);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BitStream::put_uint64(uint64_t value)
|
||
|
{
|
||
|
if(little_endian)
|
||
|
{
|
||
|
this->put_serial(value>>32, 32);
|
||
|
this->put_serial(value, 32);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this->put_serial(value, 32);
|
||
|
this->put_serial(value>>32, 32);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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 );
|
||
|
strsize = String(&c) + strsize;
|
||
|
t /= 10;
|
||
|
}
|
||
|
|
||
|
String strpos;
|
||
|
t = this->_pos;
|
||
|
if ( t == 0) strpos = "0";
|
||
|
while ( t > 0 )
|
||
|
{
|
||
|
const char c = '0' + ( t % 10 );
|
||
|
strpos = String(&c) + strpos;
|
||
|
t /= 10;
|
||
|
}
|
||
|
|
||
|
return "[size:" + strsize + ", pos:" + 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;
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
int64_t BitStream::get_sint64()
|
||
|
{
|
||
|
int64_t v1;
|
||
|
int64_t v2;
|
||
|
if(little_endian)
|
||
|
{
|
||
|
v1 = this->get_serial(32);
|
||
|
v2 = this->get_serial(32);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
v2 = this->get_serial(32);
|
||
|
v1 = this->get_serial(32);
|
||
|
}
|
||
|
return (v1 << 32) | v2;
|
||
|
}
|
||
|
|
||
|
uint64_t BitStream::get_uint64()
|
||
|
{
|
||
|
int64_t v1;
|
||
|
int64_t v2;
|
||
|
if(little_endian)
|
||
|
{
|
||
|
v1 = this->get_serial(32);
|
||
|
v2 = this->get_serial(32);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
v2 = this->get_serial(32);
|
||
|
v1 = this->get_serial(32);
|
||
|
}
|
||
|
return (v1 << 32) | v2;
|
||
|
}
|
||
|
|
||
|
PoolByteArray BitStream::get_array_uint8(uint32_t length)
|
||
|
{
|
||
|
PoolByteArray ret;
|
||
|
while(length != 0)
|
||
|
{
|
||
|
ret.append(this->get_serial(8));
|
||
|
--length;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|