add byteutil library

This commit is contained in:
MihailRis 2024-12-27 08:33:52 +03:00
parent 83d8254d69
commit cca153b66b
6 changed files with 253 additions and 28 deletions

View File

@ -6,6 +6,10 @@
#include "util/data_io.hpp" #include "util/data_io.hpp"
ByteBuilder::ByteBuilder(size_t size) {
buffer.reserve(size);
}
void ByteBuilder::put(ubyte b) { void ByteBuilder::put(ubyte b) {
buffer.push_back(b); buffer.push_back(b);
} }
@ -31,37 +35,37 @@ void ByteBuilder::put(const ubyte* arr, size_t size) {
} }
} }
void ByteBuilder::putInt16(int16_t val) { void ByteBuilder::putInt16(int16_t val, bool bigEndian) {
size_t size = buffer.size(); size_t size = buffer.size();
buffer.resize(buffer.size() + sizeof(int16_t)); buffer.resize(buffer.size() + sizeof(int16_t));
val = dataio::h2le(val); val = bigEndian ? dataio::h2be(val) : dataio::h2le(val);
std::memcpy(buffer.data()+size, &val, sizeof(int16_t)); std::memcpy(buffer.data()+size, &val, sizeof(int16_t));
} }
void ByteBuilder::putInt32(int32_t val) { void ByteBuilder::putInt32(int32_t val, bool bigEndian) {
size_t size = buffer.size(); size_t size = buffer.size();
buffer.resize(buffer.size() + sizeof(int32_t)); buffer.resize(buffer.size() + sizeof(int32_t));
val = dataio::h2le(val); val = bigEndian ? dataio::h2be(val) : dataio::h2le(val);
std::memcpy(buffer.data()+size, &val, sizeof(int32_t)); std::memcpy(buffer.data()+size, &val, sizeof(int32_t));
} }
void ByteBuilder::putInt64(int64_t val) { void ByteBuilder::putInt64(int64_t val, bool bigEndian) {
size_t size = buffer.size(); size_t size = buffer.size();
buffer.resize(buffer.size() + sizeof(int64_t)); buffer.resize(buffer.size() + sizeof(int64_t));
val = dataio::h2le(val); val = bigEndian ? dataio::h2be(val) : dataio::h2le(val);
std::memcpy(buffer.data()+size, &val, sizeof(int64_t)); std::memcpy(buffer.data()+size, &val, sizeof(int64_t));
} }
void ByteBuilder::putFloat32(float val) { void ByteBuilder::putFloat32(float val, bool bigEndian) {
int32_t i32_val; int32_t i32_val;
std::memcpy(&i32_val, &val, sizeof(int32_t)); std::memcpy(&i32_val, &val, sizeof(int32_t));
putInt32(i32_val); putInt32(i32_val, bigEndian);
} }
void ByteBuilder::putFloat64(double val) { void ByteBuilder::putFloat64(double val, bool bigEndian) {
int64_t i64_val; int64_t i64_val;
std::memcpy(&i64_val, &val, sizeof(int64_t)); std::memcpy(&i64_val, &val, sizeof(int64_t));
putInt64(i64_val); putInt64(i64_val, bigEndian);
} }
void ByteBuilder::set(size_t position, ubyte val) { void ByteBuilder::set(size_t position, ubyte val) {
@ -95,6 +99,10 @@ ByteReader::ByteReader(const ubyte* data) : data(data), size(4), pos(0) {
size = getInt32(); size = getInt32();
} }
ByteReader::ByteReader(const std::vector<ubyte>& data)
: data(data.data()), size(data.size()), pos(0) {
}
void ByteReader::checkMagic(const char* data, size_t size) { void ByteReader::checkMagic(const char* data, size_t size) {
if (pos + size >= this->size) { if (pos + size >= this->size) {
throw std::runtime_error("invalid magic number"); throw std::runtime_error("invalid magic number");
@ -129,45 +137,51 @@ ubyte ByteReader::peek() {
return data[pos]; return data[pos];
} }
int16_t ByteReader::getInt16() { int16_t ByteReader::getInt16(bool bigEndian) {
if (pos + sizeof(int16_t) > size) { if (pos + sizeof(int16_t) > size) {
throw std::runtime_error("buffer underflow"); throw std::runtime_error("buffer underflow");
} }
int16_t value; int16_t value;
std::memcpy(&value, data + pos, sizeof(int16_t)); std::memcpy(&value, data + pos, sizeof(int16_t));
pos += sizeof(int16_t); pos += sizeof(int16_t);
return dataio::le2h(value); return bigEndian ? dataio::be2h(value) : dataio::le2h(value);
} }
int32_t ByteReader::getInt32() { int32_t ByteReader::getInt32(bool bigEndian) {
if (pos + sizeof(int32_t) > size) { if (pos + sizeof(int32_t) > size) {
throw std::runtime_error("buffer underflow"); throw std::runtime_error("buffer underflow");
} }
int32_t value; int32_t value;
std::memcpy(&value, data + pos, sizeof(int32_t)); std::memcpy(&value, data + pos, sizeof(int32_t));
pos += sizeof(int32_t); pos += sizeof(int32_t);
return dataio::le2h(value); return bigEndian ? dataio::be2h(value) : dataio::le2h(value);
} }
int64_t ByteReader::getInt64() { int64_t ByteReader::getInt64(bool bigEndian) {
if (pos + sizeof(int64_t) > size) { if (pos + sizeof(int64_t) > size) {
throw std::runtime_error("buffer underflow"); throw std::runtime_error("buffer underflow");
} }
int64_t value; int64_t value;
std::memcpy(&value, data + pos, sizeof(int64_t)); std::memcpy(&value, data + pos, sizeof(int64_t));
pos += sizeof(int64_t); pos += sizeof(int64_t);
return dataio::le2h(value); return bigEndian ? dataio::be2h(value) : dataio::le2h(value);
} }
float ByteReader::getFloat32() { float ByteReader::getFloat32(bool bigEndian) {
int32_t i32_val = getInt32(); int32_t i32_val = getInt32();
if (bigEndian) {
i32_val = dataio::be2h(i32_val);
}
float val; float val;
std::memcpy(&val, &i32_val, sizeof(float)); std::memcpy(&val, &i32_val, sizeof(float));
return val; return val;
} }
double ByteReader::getFloat64() { double ByteReader::getFloat64(bool bigEndian) {
int64_t i64_val = getInt64(); int64_t i64_val = getInt64();
if (bigEndian) {
i64_val = dataio::be2h(i64_val);
}
double val; double val;
std::memcpy(&val, &i64_val, sizeof(double)); std::memcpy(&val, &i64_val, sizeof(double));
return val; return val;

View File

@ -8,20 +8,23 @@
class ByteBuilder { class ByteBuilder {
std::vector<ubyte> buffer; std::vector<ubyte> buffer;
public: public:
ByteBuilder() = default;
ByteBuilder(size_t size);
/// @brief Write one byte (8 bit unsigned integer) /// @brief Write one byte (8 bit unsigned integer)
void put(ubyte b); void put(ubyte b);
/// @brief Write c-string (bytes array terminated with '\00') /// @brief Write c-string (bytes array terminated with '\00')
void putCStr(const char* str); void putCStr(const char* str);
/// @brief Write signed 16 bit little-endian integer /// @brief Write signed 16 bit little-endian integer
void putInt16(int16_t val); void putInt16(int16_t val, bool bigEndian = false);
/// @brief Write signed 32 bit integer /// @brief Write signed 32 bit integer
void putInt32(int32_t val); void putInt32(int32_t val, bool bigEndian = false);
/// @brief Write signed 64 bit integer /// @brief Write signed 64 bit integer
void putInt64(int64_t val); void putInt64(int64_t val, bool bigEndian = false);
/// @brief Write 32 bit floating-point number /// @brief Write 32 bit floating-point number
void putFloat32(float val); void putFloat32(float val, bool bigEndian = false);
/// @brief Write 64 bit floating-point number /// @brief Write 64 bit floating-point number
void putFloat64(double val); void putFloat64(double val, bool bigEndian = false);
/// @brief Write string (uint32 length + bytes) /// @brief Write string (uint32 length + bytes)
void put(const std::string& s); void put(const std::string& s);
@ -50,6 +53,7 @@ class ByteReader {
public: public:
ByteReader(const ubyte* data, size_t size); ByteReader(const ubyte* data, size_t size);
ByteReader(const ubyte* data); ByteReader(const ubyte* data);
ByteReader(const std::vector<ubyte>& data);
void checkMagic(const char* data, size_t size); void checkMagic(const char* data, size_t size);
/// @brief Get N bytes /// @brief Get N bytes
@ -59,15 +63,15 @@ public:
/// @brief Read one byte (unsigned 8 bit integer) without pointer move /// @brief Read one byte (unsigned 8 bit integer) without pointer move
ubyte peek(); ubyte peek();
/// @brief Read signed 16 bit little-endian integer /// @brief Read signed 16 bit little-endian integer
int16_t getInt16(); int16_t getInt16(bool bigEndian = false);
/// @brief Read signed 32 bit little-endian integer /// @brief Read signed 32 bit little-endian integer
int32_t getInt32(); int32_t getInt32(bool bigEndian = false);
/// @brief Read signed 64 bit little-endian integer /// @brief Read signed 64 bit little-endian integer
int64_t getInt64(); int64_t getInt64(bool bigEndian = false);
/// @brief Read 32 bit floating-point number /// @brief Read 32 bit floating-point number
float getFloat32(); float getFloat32(bool bigEndian = false);
/// @brief Read 64 bit floating-point number /// @brief Read 64 bit floating-point number
double getFloat64(); double getFloat64(bool bigEndian = false);
/// @brief Read C-String /// @brief Read C-String
const char* getCString(); const char* getCString();
/// @brief Read string with unsigned 32 bit number before (length) /// @brief Read string with unsigned 32 bit number before (length)

View File

@ -19,6 +19,7 @@ extern const luaL_Reg base64lib[];
extern const luaL_Reg bjsonlib[]; extern const luaL_Reg bjsonlib[];
extern const luaL_Reg blocklib[]; extern const luaL_Reg blocklib[];
extern const luaL_Reg blockwrapslib[]; // gfx.blockwraps extern const luaL_Reg blockwrapslib[]; // gfx.blockwraps
extern const luaL_Reg byteutillib[];
extern const luaL_Reg cameralib[]; extern const luaL_Reg cameralib[];
extern const luaL_Reg consolelib[]; extern const luaL_Reg consolelib[];
extern const luaL_Reg corelib[]; extern const luaL_Reg corelib[];

View File

@ -0,0 +1,194 @@
#include "api_lua.hpp"
#include <string>
#include "coders/byte_utils.hpp"
#include "util/data_io.hpp"
static size_t calc_size(const char* format) {
size_t outSize = 0;
for (size_t i = 0; format[i]; i++) {
switch (format[i]) {
case 'b':
case 'B':
outSize += 1;
break;
case 'h':
case 'H':
outSize += 2;
break;
case 'i':
case 'I':
case 'f':
outSize += 4;
break;
case 'd':
case 'l':
case 'L':
outSize += 8;
break;
default:
break;
}
}
return outSize;
}
static int pack(lua::State* L, const char* format, bool usetable) {
size_t outSize = calc_size(format);
bool bigEndian = false;
ByteBuilder builder(outSize);
int index = 2;
for (int i = 0; format[i]; i++) {
switch (format[i]) {
case 'b':
builder.put(lua::tointeger(L, index) & 0xFF);
break;
case 'h':
builder.putInt16(lua::tointeger(L, index), bigEndian);
break;
case 'H':
builder.putInt16(lua::tointeger(L, index) & 0xFFFFU, bigEndian);
break;
case 'i':
builder.putInt32(lua::tointeger(L, index), bigEndian);
break;
case 'I':
builder.putInt32(lua::tointeger(L, index) & 0xFFFFFFFFULL, bigEndian);
break;
case 'l':
case 'L':
builder.putInt64(lua::tointeger(L, index), bigEndian);
break;
case 'f':
builder.putFloat32(lua::tonumber(L, index), bigEndian);
break;
case 'd':
builder.putFloat64(lua::tonumber(L, index), bigEndian);
break;
case '!':
case '>':
bigEndian = true;
continue;
case '<':
bigEndian = false;
continue;
case '@':
case '=':
bigEndian = dataio::is_big_endian();
continue;
default:
continue;
}
index++;
}
if (usetable) {
lua::createtable(L, outSize, 0);
const ubyte* data = builder.data();
for (size_t i = 0; i < outSize; i++) {
lua::pushinteger(L, data[i]);
lua::rawseti(L, i + 1);
}
return 1;
} else {
return lua::newuserdata<lua::LuaBytearray>(L, builder.build());
}
}
static int count_elements(const char* format) {
int count = 0;
for (size_t i = 0; format[i]; i++) {
switch (format[i]) {
case 'b':
case 'B':
case 'h':
case 'H':
case 'i':
case 'I':
case 'l':
case 'L':
case 'f':
case 'd':
count++;
break;
default:
break;
}
}
return count;
}
static int l_unpack(lua::State* L) {
const char* format = lua::require_string(L, 1);
int count = count_elements(format);
auto bytes = lua::require_bytearray(L, 2);
ByteReader reader(bytes);
bool bigEndian = false;
int index = 1;
lua::createtable(L, count, 0);
for (size_t i = 0; format[i]; i++) {
switch (format[i]) {
case 'b':
lua::pushinteger(L, reader.get());
break;
case 'h':
lua::pushinteger(L, reader.getInt16(bigEndian));
break;
case 'H':
lua::pushinteger(L, reader.getInt16(bigEndian) & 0xFFFF);
break;
case 'i':
lua::pushinteger(L, reader.getInt32(bigEndian));
break;
case 'I':
lua::pushinteger(L, reader.getInt32(bigEndian) & 0xFFFFFFFF);
break;
case 'l':
lua::pushinteger(L, reader.getInt64(bigEndian));
break;
case 'L':
lua::pushinteger(L, reader.getInt64(bigEndian));
break;
case 'f':
lua::pushnumber(L, reader.getFloat32(bigEndian));
break;
case 'd':
lua::pushnumber(L, reader.getFloat64(bigEndian));
break;
case '!':
case '>':
bigEndian = true;
continue;
case '<':
bigEndian = false;
continue;
case '@':
case '=':
bigEndian = dataio::is_big_endian();
continue;
default:
continue;
}
lua::rawseti(L, index++);
}
return 1;
}
static int l_pack(lua::State* L) {
const char* format = lua::require_string(L, 1);
return pack(L, format, false);
}
static int l_tpack(lua::State* L) {
const char* format = lua::require_string(L, 1);
return pack(L, format, true);
}
const luaL_Reg byteutillib[] = {
{"pack", l_pack},
{"tpack", l_tpack},
{"unpack", l_unpack},
{NULL, NULL}
};

View File

@ -43,6 +43,7 @@ static void create_libs(State* L, StateType stateType) {
openlib(L, "base64", base64lib); openlib(L, "base64", base64lib);
openlib(L, "bjson", bjsonlib); openlib(L, "bjson", bjsonlib);
openlib(L, "block", blocklib); openlib(L, "block", blocklib);
openlib(L, "byteutil", byteutillib);
openlib(L, "core", corelib); openlib(L, "core", corelib);
openlib(L, "file", filelib); openlib(L, "file", filelib);
openlib(L, "generation", generationlib); openlib(L, "generation", generationlib);

View File

@ -720,4 +720,15 @@ namespace lua {
} }
} }
} }
inline std::vector<ubyte> require_bytearray(lua::State* L, int idx) {
if (auto* bytearray = lua::touserdata<LuaBytearray>(L, idx)) {
return bytearray->data();
} else if (lua::istable(L, idx)) {
std::vector<ubyte> bytes;
read_bytes_from_table(L, idx, bytes);
return bytes;
}
throw std::runtime_error("bytearray expected");
}
} }