mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-08 22:50:08 +03:00
287 lines
8.4 KiB
C++
287 lines
8.4 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "enrs.hpp"
|
|
|
|
enum enrs_value_type {
|
|
ENRS_VALUE_INT8 = 0x0,
|
|
ENRS_VALUE_INT16 = 0x1,
|
|
ENRS_VALUE_INT32 = 0x2,
|
|
ENRS_VALUE_INVALID = 0x3,
|
|
};
|
|
|
|
inline static bool enrs_length_get_size_type(uint32_t* length, size_t val);
|
|
inline static bool enrs_length_get_size(uint32_t* length, size_t val);
|
|
static bool enrs_read_packed_value(stream& s, uint32_t* val);
|
|
static bool enrs_write_packed_value(stream& s, uint32_t val);
|
|
static bool enrs_read_packed_value_type(stream& s, uint32_t* val, enrs_type* type);
|
|
static bool enrs_write_packed_value_type(stream& s, uint32_t val, enrs_type type);
|
|
|
|
enrs_entry::enrs_entry(): offset(), count(), size(), repeat_count() {
|
|
|
|
}
|
|
|
|
enrs_entry::enrs_entry(uint32_t offset, uint32_t count, uint32_t size, uint32_t repeat_count) {
|
|
this->offset = offset;
|
|
this->count = count;
|
|
this->size = size;
|
|
this->repeat_count = repeat_count;
|
|
}
|
|
|
|
enrs_entry::~enrs_entry() {
|
|
|
|
}
|
|
|
|
void enrs_entry::append(uint32_t skip_bytes, uint32_t repeat_count, enrs_type type) {
|
|
sub.push_back({ skip_bytes, repeat_count, type });
|
|
}
|
|
|
|
void enrs_entry::append(enrs_sub_entry&& data) {
|
|
sub.push_back(data);
|
|
}
|
|
|
|
enrs::enrs() {
|
|
|
|
}
|
|
|
|
enrs::~enrs() {
|
|
|
|
}
|
|
|
|
void enrs::apply(void* data) {
|
|
if (!data)
|
|
return;
|
|
|
|
uint8_t* d = (uint8_t*)data;
|
|
uint8_t* temp;
|
|
for (enrs_entry& i : vec) {
|
|
d += i.offset;
|
|
for (size_t j = 0; j < i.repeat_count; j++) {
|
|
temp = d + i.size * j;
|
|
for (enrs_sub_entry& k : i.sub) {
|
|
temp += k.skip_bytes;
|
|
switch (k.type) {
|
|
case ENRS_WORD:
|
|
for (size_t l = k.repeat_count; l; l--) {
|
|
*(uint16_t*)temp = reverse_endianness_uint16_t(*(uint16_t*)temp);
|
|
temp += 2;
|
|
}
|
|
break;
|
|
case ENRS_DWORD:
|
|
for (size_t l = k.repeat_count; l; l--) {
|
|
*(uint32_t*)temp = reverse_endianness_uint32_t(*(uint32_t*)temp);
|
|
temp += 4;
|
|
}
|
|
break;
|
|
case ENRS_QWORD:
|
|
for (size_t l = k.repeat_count; l; l--) {
|
|
*(uint64_t*)temp = reverse_endianness_uint64_t(*(uint64_t*)temp);
|
|
temp += 8;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t enrs::length() {
|
|
uint32_t l = 0x10;
|
|
uint32_t o = 0;
|
|
for (enrs_entry& i : vec) {
|
|
uint32_t offset = i.offset;
|
|
i.count = (uint32_t)i.sub.size();
|
|
if (&i != vec.data() && (&i)[-1].count < 1) {
|
|
o += (uint32_t)((size_t)(&i)[-1].size * (&i)[-1].repeat_count);
|
|
if (i.count > 0) {
|
|
offset += o;
|
|
o = 0;
|
|
}
|
|
}
|
|
|
|
if (i.count < 1)
|
|
continue;
|
|
|
|
if (enrs_length_get_size(&l, offset)
|
|
|| enrs_length_get_size(&l, i.count)
|
|
|| enrs_length_get_size(&l, i.size)
|
|
|| enrs_length_get_size(&l, i.repeat_count))
|
|
goto End;
|
|
|
|
if (i.repeat_count < 1 || i.count > 0x40000000)
|
|
continue;
|
|
|
|
for (enrs_sub_entry& j : i.sub) {
|
|
if (enrs_length_get_size_type(&l, j.skip_bytes)
|
|
|| enrs_length_get_size(&l, j.repeat_count))
|
|
goto End;
|
|
}
|
|
}
|
|
End:
|
|
l = align_val(l, 0x10);
|
|
return l;
|
|
}
|
|
|
|
void enrs::read(stream& s) {
|
|
vec.clear();
|
|
|
|
s.read_uint32_t();
|
|
size_t l = s.read_uint32_t();
|
|
s.read_uint32_t();
|
|
s.read_uint32_t();
|
|
|
|
vec.reserve(l);
|
|
for (size_t i = 0; i < l; i++) {
|
|
enrs_entry entry;
|
|
if (enrs_read_packed_value(s, &entry.offset)
|
|
|| enrs_read_packed_value(s, &entry.count)
|
|
|| enrs_read_packed_value(s, &entry.size)
|
|
|| enrs_read_packed_value(s, &entry.repeat_count))
|
|
return;
|
|
|
|
if (!entry.count || !entry.repeat_count) {
|
|
vec.push_back(entry);
|
|
continue;
|
|
}
|
|
|
|
entry.sub.reserve(entry.count);
|
|
for (size_t j = 0; j < entry.count; j++) {
|
|
enrs_sub_entry sub_entry = {};
|
|
if (enrs_read_packed_value_type(s, &sub_entry.skip_bytes, &sub_entry.type)
|
|
|| enrs_read_packed_value(s, &sub_entry.repeat_count))
|
|
return;
|
|
entry.sub.push_back(sub_entry);
|
|
}
|
|
vec.push_back(entry);
|
|
}
|
|
}
|
|
|
|
void enrs::write(stream& s) {
|
|
uint32_t o = 0;
|
|
size_t length = enrs::length();
|
|
s.write_uint32_t(0);
|
|
s.write_uint32_t((uint32_t)vec.size());
|
|
s.write_uint32_t(0);
|
|
s.write_uint32_t(0);
|
|
for (enrs_entry& i : vec) {
|
|
uint32_t offset = i.offset;
|
|
i.count = (uint32_t)i.sub.size();
|
|
if (&i != vec.data() && (&i)[-1].count < 1) {
|
|
o += (uint32_t)((size_t)(&i)[-1].size * (&i)[-1].repeat_count);
|
|
if ((&i)->count > 0) {
|
|
offset += o;
|
|
o = 0;
|
|
}
|
|
}
|
|
|
|
if (i.count < 1)
|
|
continue;
|
|
|
|
if (enrs_write_packed_value(s, offset)
|
|
|| enrs_write_packed_value(s, i.count)
|
|
|| enrs_write_packed_value(s, i.size)
|
|
|| enrs_write_packed_value(s, i.repeat_count))
|
|
goto End;
|
|
|
|
if (i.repeat_count < 1)
|
|
continue;
|
|
|
|
for (enrs_sub_entry& j : i.sub)
|
|
if (enrs_write_packed_value_type(s, j.skip_bytes, j.type)
|
|
|| enrs_write_packed_value(s, j.repeat_count))
|
|
goto End;
|
|
}
|
|
|
|
End:
|
|
s.align_write(0x10);
|
|
}
|
|
|
|
inline static bool enrs_length_get_size_type(uint32_t* length, size_t val) {
|
|
*length += val < 0x10 ? 1 : val < 0x1000 ? 2 : val < 0x10000000 ? 4 : 1;
|
|
return val >= 0x10000000;
|
|
}
|
|
|
|
inline static bool enrs_length_get_size(uint32_t* length, size_t val) {
|
|
if (!length)
|
|
return true;
|
|
|
|
*length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1;
|
|
return val >= 0x40000000;
|
|
}
|
|
|
|
static bool enrs_read_packed_value(stream& s, uint32_t* val) {
|
|
*val = s.read_uint8_t();
|
|
enrs_value_type value = (enrs_value_type)((*val >> 6) & 0x3);
|
|
*val &= 0x3F;
|
|
|
|
if (value == ENRS_VALUE_INT32)
|
|
*val = (((((*val << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t();
|
|
else if (value == ENRS_VALUE_INT16)
|
|
*val = (*val << 8) | s.read_uint8_t();
|
|
else if (value == ENRS_VALUE_INVALID) {
|
|
*val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool enrs_write_packed_value(stream& s, uint32_t val) {
|
|
if (val < 0x40)
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT8 << 6) | (val & 0x3F)));
|
|
else if (val < 0x4000) {
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT16 << 6) | ((val >> 8) & 0x3F)));
|
|
s.write_uint8_t((uint8_t)val);
|
|
}
|
|
else if (val < 0x40000000) {
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT32 << 6) | ((val >> 24) & 0x3F)));
|
|
s.write_uint8_t((uint8_t)(val >> 16));
|
|
s.write_uint8_t((uint8_t)(val >> 8));
|
|
s.write_uint8_t((uint8_t)val);
|
|
}
|
|
else {
|
|
s.write_uint8_t(ENRS_VALUE_INVALID << 6);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool enrs_read_packed_value_type(stream& s, uint32_t* val, enrs_type* type) {
|
|
*val = s.read_uint8_t();
|
|
enrs_value_type value = (enrs_value_type)((*val >> 6) & 0x3);
|
|
*type = (enrs_type)((*val >> 4) & 0x3);
|
|
*val &= 0xF;
|
|
|
|
if (value == ENRS_VALUE_INT32)
|
|
*val = (((((*val << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t();
|
|
else if (value == ENRS_VALUE_INT16)
|
|
*val = (*val << 8) | s.read_uint8_t();
|
|
else if (value == ENRS_VALUE_INVALID) {
|
|
*val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool enrs_write_packed_value_type(stream& s, uint32_t val, enrs_type type) {
|
|
uint8_t t = ((uint8_t)type & 0x3) << 4;
|
|
if (val < 0x10)
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT8 << 6) | t | (val & 0xF)));
|
|
else if (val < 0x1000) {
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT16 << 6) | t | ((val >> 8) & 0xF)));
|
|
s.write_uint8_t((uint8_t)val);
|
|
}
|
|
else if (val < 0x10000000) {
|
|
s.write_uint8_t((uint8_t)((ENRS_VALUE_INT32 << 6) | t | ((val >> 24) & 0xF)));
|
|
s.write_uint8_t((uint8_t)(val >> 16));
|
|
s.write_uint8_t((uint8_t)(val >> 8));
|
|
s.write_uint8_t((uint8_t)val);
|
|
}
|
|
else {
|
|
s.write_uint8_t(ENRS_VALUE_INVALID << 6);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|