mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-08 22:50:08 +03:00
207 lines
4.9 KiB
C++
207 lines
4.9 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "pof.hpp"
|
|
|
|
enum pof_value_type {
|
|
POF_VALUE_INVALID = 0x0,
|
|
POF_VALUE_INT8 = 0x1,
|
|
POF_VALUE_INT16 = 0x2,
|
|
POF_VALUE_INT32 = 0x3,
|
|
};
|
|
|
|
inline static bool pof_length_get_size(uint32_t* length, size_t val);
|
|
static size_t pof_read_offsets_count(stream& s);
|
|
inline static bool pof_write_packed_value(stream& s, size_t val);
|
|
|
|
pof::pof() {
|
|
|
|
}
|
|
|
|
pof::~pof() {
|
|
|
|
}
|
|
|
|
void pof::add(stream& s, int64_t offset) {
|
|
vec.push_back(s.get_position() + offset);
|
|
}
|
|
|
|
void pof::read(stream& s, bool shift_x) {
|
|
vec.clear();
|
|
|
|
size_t length = pof_read_offsets_count(s);
|
|
|
|
uint8_t bit_shift = (uint8_t)(shift_x ? 3 : 2);
|
|
size_t l = s.read_uint32_t() - 4ULL;
|
|
|
|
vec.reserve(length);
|
|
|
|
size_t i = 0;
|
|
size_t j = 0;
|
|
size_t offset = 0;
|
|
while (i < l) {
|
|
size_t v = s.read_uint8_t();
|
|
pof_value_type value = (pof_value_type)((v >> 6) & 0x03);
|
|
v &= 0x3F;
|
|
|
|
if (value == POF_VALUE_INT32) {
|
|
v = (((((v << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t()) << 8) | s.read_uint8_t();
|
|
i += 3;
|
|
}
|
|
else if (value == POF_VALUE_INT16) {
|
|
v = (v << 8) | s.read_uint8_t();
|
|
i++;
|
|
}
|
|
else if (value == POF_VALUE_INVALID)
|
|
break;
|
|
|
|
offset += v;
|
|
vec.push_back(offset << bit_shift);
|
|
i++;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
void pof::write(stream& s, bool shift_x) {
|
|
size_t j = 0;
|
|
size_t o = 0;
|
|
uint8_t bit_shift = (uint8_t)(shift_x ? 3 : 2);
|
|
size_t v = ((size_t)1 << bit_shift) - 1;
|
|
size_t l = length(shift_x);
|
|
if (shift_x)
|
|
s.write_uint32_t((uint32_t)l);
|
|
else
|
|
s.write_uint32_t((uint32_t)align_val(l, 4));
|
|
|
|
for (int64_t& i : vec) {
|
|
o = i;
|
|
if (o & v) {
|
|
pof_write_packed_value(s, 0x7FFFFFFF);
|
|
break;
|
|
}
|
|
|
|
size_t k = o - j;
|
|
if (&i != vec.data() && !k)
|
|
continue;
|
|
j = o;
|
|
o = k;
|
|
|
|
pof_write_packed_value(s, o >> bit_shift);
|
|
}
|
|
|
|
size_t pos = s.get_position();
|
|
for (size_t c = align_val(pos, 0x10) - pos; c > 0; c--)
|
|
s.write_uint8_t(0);
|
|
}
|
|
|
|
uint32_t pof::length(bool shift_x) {
|
|
uint32_t l = 4;
|
|
size_t j = 0;
|
|
uint8_t bit_shift = (uint8_t)(shift_x ? 3 : 2);
|
|
size_t v = ((size_t)1 << bit_shift) - 1;
|
|
|
|
for (int64_t& i : vec) {
|
|
size_t o = i;
|
|
if (o & v)
|
|
break;
|
|
else if (&i != vec.data()) {
|
|
size_t k = o - j;
|
|
if (!k)
|
|
continue;
|
|
j = o;
|
|
o = k;
|
|
}
|
|
else
|
|
j = o;
|
|
|
|
if (pof_length_get_size(&l, o >> bit_shift))
|
|
break;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
inline void io_write_offset_pof_add(stream& s, int64_t val,
|
|
int32_t offset, bool is_x, pof* pof) {
|
|
if (!is_x) {
|
|
if (val)
|
|
val += offset;
|
|
pof->add(s, offset);
|
|
s.write_int32_t_reverse_endianness((int32_t)val);
|
|
}
|
|
else {
|
|
s.align_write(0x08);
|
|
pof->add(s, 0);
|
|
s.write_int64_t_reverse_endianness(val);
|
|
}
|
|
}
|
|
|
|
inline void io_write_offset_f2_pof_add(stream& s, int64_t val,
|
|
int32_t offset, pof* pof) {
|
|
if (val)
|
|
val += offset;
|
|
pof->add(s, offset);
|
|
s.write_int32_t_reverse_endianness((int32_t)val);
|
|
}
|
|
|
|
inline void io_write_offset_x_pof_add(stream& s, int64_t val, pof* pof) {
|
|
s.align_write(0x08);
|
|
pof->add(s, 0);
|
|
s.write_int64_t_reverse_endianness(val);
|
|
}
|
|
|
|
inline static bool pof_length_get_size(uint32_t* length, size_t val) {
|
|
*length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1;
|
|
return val >= 0x40000000;
|
|
}
|
|
|
|
static size_t pof_read_offsets_count(stream& s) {
|
|
size_t pos = s.get_position();
|
|
size_t i, j, l;
|
|
pof_value_type val;
|
|
|
|
l = s.read_uint32_t() - 4ULL;
|
|
i = 0;
|
|
j = 0;
|
|
while (i < l) {
|
|
val = (pof_value_type)((s.read_uint8_t() >> 6) & 0x03);
|
|
if (val == POF_VALUE_INT32) {
|
|
s.read_uint8_t();
|
|
s.read_uint8_t();
|
|
s.read_uint8_t();
|
|
i += 3;
|
|
}
|
|
else if (val == POF_VALUE_INT16) {
|
|
s.read_uint8_t();
|
|
i++;
|
|
}
|
|
else if (val != POF_VALUE_INT8)
|
|
break;
|
|
i++;
|
|
j++;
|
|
}
|
|
s.set_position( pos, SEEK_SET);
|
|
return j;
|
|
}
|
|
|
|
static bool pof_write_packed_value(stream& s, size_t val) {
|
|
if (val < 0x40)
|
|
s.write_uint8_t((uint8_t)((POF_VALUE_INT8 << 6) | (val & 0x3F)));
|
|
else if (val < 0x4000) {
|
|
s.write_uint8_t((uint8_t)((POF_VALUE_INT16 << 6) | ((val >> 8) & 0x3F)));
|
|
s.write_uint8_t((uint8_t)val);
|
|
}
|
|
else if (val < 0x40000000) {
|
|
s.write_uint8_t((uint8_t)((POF_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(POF_VALUE_INVALID << 6);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|