mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-03 20:28:10 +03:00
247 lines
6.7 KiB
C++
247 lines
6.7 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "struct.hpp"
|
|
#include "../io/file_stream.hpp"
|
|
#include "../io/memory_stream.hpp"
|
|
#include "../io/path.hpp"
|
|
#include "../divafile.hpp"
|
|
|
|
static void f2_struct_read_data(stream& s, f2_struct* st, f2_header* h);
|
|
static void f2_struct_write_inner(stream& s, f2_struct* st, uint32_t depth, bool use_depth, bool shift_x);
|
|
static void f2_struct_get_length(f2_struct* s, bool shift_x);
|
|
static void f2_struct_write_pof(stream& s, pof* pof, uint32_t depth, bool shift_x);
|
|
static void f2_struct_write_enrs(stream& s, enrs* enrs, uint32_t depth);
|
|
|
|
f2_struct::f2_struct() : header() {
|
|
|
|
}
|
|
|
|
f2_struct::~f2_struct() {
|
|
|
|
}
|
|
|
|
void f2_struct::read(const char* path) {
|
|
if (!path)
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, "rb");
|
|
if (s.check_not_null()) {
|
|
memory_stream ms;
|
|
divafile::decrypt(s, ms);
|
|
|
|
f2_header h;
|
|
f2_header_read(ms, &h);
|
|
f2_struct_read_data(ms, this, &h);
|
|
}
|
|
}
|
|
|
|
void f2_struct::read(const wchar_t* path) {
|
|
if (!path)
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, L"rb");
|
|
if (s.check_not_null()) {
|
|
memory_stream ms;
|
|
divafile::decrypt(s, ms);
|
|
|
|
f2_header h;
|
|
f2_header_read(ms, &h);
|
|
f2_struct_read_data(ms, this, &h);
|
|
}
|
|
}
|
|
|
|
void f2_struct::read(const void* data, size_t size) {
|
|
if (!data || !size)
|
|
return;
|
|
|
|
memory_stream s;
|
|
s.open(data, size);
|
|
if (s.check_not_null()) {
|
|
memory_stream ms;
|
|
divafile::decrypt(s, ms);
|
|
|
|
f2_header h;
|
|
f2_header_read(ms, &h);
|
|
f2_struct_read_data(ms, this, &h);
|
|
}
|
|
}
|
|
|
|
void f2_struct::read(stream& s) {
|
|
if (s.check_null())
|
|
return;
|
|
|
|
memory_stream ms;
|
|
divafile::decrypt(s, ms);
|
|
|
|
f2_header h;
|
|
f2_header_read(ms, &h);
|
|
f2_struct_read_data(ms, this, &h);
|
|
}
|
|
|
|
void f2_struct::write(const char* path, bool use_depth, bool shift_x) {
|
|
if (!path)
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, "wb");
|
|
if (s.check_not_null()) {
|
|
f2_struct_get_length(this, shift_x);
|
|
f2_struct_write_inner(s, this, 0, use_depth, shift_x);
|
|
}
|
|
}
|
|
|
|
void f2_struct::write(const wchar_t* path, bool use_depth, bool shift_x) {
|
|
if (!path)
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, L"wb");
|
|
if (s.check_not_null()) {
|
|
f2_struct_get_length(this, shift_x);
|
|
f2_struct_write_inner(s, this, 0, use_depth, shift_x);
|
|
}
|
|
}
|
|
|
|
void f2_struct::write(void** data, size_t* size, bool use_depth, bool shift_x) {
|
|
if (!data || !size)
|
|
return;
|
|
|
|
f2_struct_get_length(this, shift_x);
|
|
memory_stream s;
|
|
s.open(0, header.data_size + 0x40ULL);
|
|
f2_struct_write_inner(s, this, 0, use_depth, shift_x);
|
|
|
|
s.copy(data, size);
|
|
}
|
|
|
|
void f2_struct::write(stream& s, bool use_depth, bool shift_x) {
|
|
if (s.check_null())
|
|
return;
|
|
|
|
|
|
f2_struct_get_length(this, shift_x);
|
|
f2_struct_write_inner(s, this, 0, use_depth, shift_x);
|
|
|
|
}
|
|
|
|
static void f2_struct_get_length(f2_struct* s, bool shift_x) {
|
|
bool has_pof = s->pof.vec.size() > 0 ? true : false;
|
|
bool has_enrs = s->enrs.vec.size() > 0 ? true : false;
|
|
bool has_sub_structs = s->sub_structs.size() > 0 ? true : false;
|
|
|
|
s->header.section_size = (uint32_t)s->data.size();
|
|
|
|
uint32_t l = s->header.section_size;
|
|
if (has_enrs) {
|
|
uint32_t len = s->enrs.length();
|
|
l += 0x20 + align_val(len, 0x10);
|
|
}
|
|
|
|
if (has_pof) {
|
|
s->pof.shift_x = shift_x;
|
|
uint32_t len = s->pof.length();
|
|
l += 0x20 + align_val(len, 0x10);
|
|
}
|
|
|
|
if (has_sub_structs)
|
|
for (f2_struct& i : s->sub_structs) {
|
|
f2_struct_get_length(&i, shift_x);
|
|
l += i.header.data_size;
|
|
l += i.header.length;
|
|
}
|
|
|
|
if (has_enrs || has_pof || has_sub_structs)
|
|
l += 0x20;
|
|
|
|
s->header.data_size = l;
|
|
}
|
|
|
|
static void f2_struct_read_data(stream& s, f2_struct* st, f2_header* h) {
|
|
uint32_t l = h->use_section_size ? h->section_size : h->data_size;
|
|
uint32_t depth = h->depth;
|
|
st->header = *h;
|
|
if (l) {
|
|
st->data.resize(l);
|
|
s.read(st->data.data(), l);
|
|
}
|
|
|
|
uint32_t sig;
|
|
size_t length = (size_t)h->data_size - l;
|
|
size_t position = 0;
|
|
while (length > position) {
|
|
f2_header_read(s, h);
|
|
sig = reverse_endianness_uint32_t(h->signature);
|
|
l = h->use_section_size ? h->section_size : h->data_size;
|
|
position += (size_t)h->length + l;
|
|
if (sig == 'EOFC')
|
|
break;
|
|
else if (sig == 'ENRS') {
|
|
size_t pos = s.get_position();
|
|
st->enrs.read(s);
|
|
s.set_position(pos + l, SEEK_SET);
|
|
}
|
|
else if ((sig & 0xFFFFFFF0) == 'POF0') {
|
|
size_t pos = s.get_position();
|
|
st->pof.shift_x = sig == 'POF1';
|
|
st->pof.read(s);
|
|
s.set_position(pos + l, SEEK_SET);
|
|
}
|
|
else {
|
|
st->sub_structs.push_back({});
|
|
f2_struct_read_data(s, &st->sub_structs.back(), h);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void f2_struct_write_inner(stream& s, f2_struct* st, uint32_t depth, bool use_depth, bool shift_x) {
|
|
bool has_pof = st->pof.vec.size() > 0 ? true : false;
|
|
bool has_enrs = st->enrs.vec.size() > 0 ? true : false;
|
|
bool has_sub_structs = st->sub_structs.size() > 0 ? true : false;
|
|
|
|
st->header.depth = use_depth ? depth : 0;
|
|
f2_header_write(s, &st->header, st->header.length == 0x40);
|
|
if (st->data.size())
|
|
s.write(st->data.data(), st->data.size());
|
|
if (has_enrs)
|
|
f2_struct_write_enrs(s, &st->enrs, use_depth ? depth + 1 : 0);
|
|
if (has_pof)
|
|
f2_struct_write_pof(s, &st->pof, use_depth ? depth + 1 : 0, shift_x);
|
|
if (has_sub_structs)
|
|
for (f2_struct& i : st->sub_structs)
|
|
f2_struct_write_inner(s, &i, depth + 1, use_depth, shift_x);
|
|
if (has_enrs || has_pof || has_sub_structs)
|
|
f2_header_write_end_of_container(s, use_depth ? depth + 1 : 0);
|
|
if (!depth)
|
|
f2_header_write_end_of_container(s, 0);
|
|
}
|
|
|
|
static void f2_struct_write_pof(stream& s, pof* pof, uint32_t depth, bool shift_x) {
|
|
pof->shift_x = shift_x;
|
|
size_t len = pof->length();
|
|
f2_header h = {};
|
|
h.signature = shift_x ? reverse_endianness_uint32_t('POF1') : reverse_endianness_uint32_t('POF0');
|
|
h.length = 0x20;
|
|
h.depth = depth;
|
|
h.use_section_size = true;
|
|
h.data_size = h.section_size = (uint32_t)align_val(len, 0x10);
|
|
f2_header_write(s, &h, false);
|
|
pof->write(s);
|
|
}
|
|
|
|
static void f2_struct_write_enrs(stream& s, enrs* enrs, uint32_t depth) {
|
|
size_t len = enrs->length();
|
|
f2_header h = {};
|
|
h.signature = reverse_endianness_uint32_t('ENRS');
|
|
h.length = 0x20;
|
|
h.depth = depth;
|
|
h.use_section_size = true;
|
|
h.data_size = h.section_size = (uint32_t)align_val(len, 0x10);
|
|
f2_header_write(s, &h, false);
|
|
enrs->write(s);
|
|
}
|