From 3c7530ce93148e1c958f23e5e55df08eb7bf4ccc Mon Sep 17 00:00:00 2001 From: korenkonder Date: Sat, 19 Apr 2025 02:45:09 +0300 Subject: [PATCH] FT FARC reading fixes and writing support --- src/CRE/Glitter/file_writer.cpp | 2 + src/CRE/Glitter/glitter.hpp | 1 + src/KKdLib/farc.cpp | 329 ++++++++++++++++++++++---------- src/KKdLib/farc.hpp | 10 +- src/ReDIVA/x_pv_game.cpp | 81 ++++++-- src/ReDIVA/x_pv_game.hpp | 1 + 6 files changed, 313 insertions(+), 111 deletions(-) diff --git a/src/CRE/Glitter/file_writer.cpp b/src/CRE/Glitter/file_writer.cpp index 89362b10..7665a71c 100644 --- a/src/CRE/Glitter/file_writer.cpp +++ b/src/CRE/Glitter/file_writer.cpp @@ -2137,6 +2137,7 @@ namespace Glitter { bool encrypt = !!(writer_flags & FILE_WRITER_ENCRYPT); bool save_lst = !(writer_flags & FILE_WRITER_NO_LIST); bool big_endian = !!(writer_flags & FILE_WRITER_BIG_ENDIAN); + bool ft = !!(writer_flags & FILE_WRITER_FT); farc f; { size_t file_len = utf8_length(file); @@ -2198,6 +2199,7 @@ namespace Glitter { if (encrypt) { signature = FARC_FARC; flags = FARC_AES; + f.ft = ft; if (compress) enum_or(flags, FARC_GZIP); diff --git a/src/CRE/Glitter/glitter.hpp b/src/CRE/Glitter/glitter.hpp index 42b0b3ee..b036232c 100644 --- a/src/CRE/Glitter/glitter.hpp +++ b/src/CRE/Glitter/glitter.hpp @@ -275,6 +275,7 @@ namespace Glitter { FILE_WRITER_ENCRYPT = 0x02, FILE_WRITER_NO_LIST = 0x04, FILE_WRITER_BIG_ENDIAN = 0x08, + FILE_WRITER_FT = 0x10, }; enum FogType { diff --git a/src/KKdLib/farc.cpp b/src/KKdLib/farc.cpp index 24d2f774..852eb3fb 100644 --- a/src/KKdLib/farc.cpp +++ b/src/KKdLib/farc.cpp @@ -11,6 +11,7 @@ #include "deflate.hpp" #include "hash.hpp" #include "str_utils.hpp" +#include static const uint8_t key[] = { 0x70, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x5F, @@ -31,10 +32,14 @@ static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save = false, char* temp_path = 0, size_t dir_len = 0); static void farc_write_padding(farc* f, stream& s, size_t size, bool x = false); -farc::farc() : flags(), ft() { - signature = FARC_FArC; +farc::farc(farc_signature signature, farc_flags flags, bool ft) + : signature(signature), flags(flags), ft(ft), entry_padding(), header_padding() { compression_level = 12; alignment = 0x10; + if (ft) { + entry_size = 0x10; + header_size = 0x10; + } } farc::~farc() { @@ -426,53 +431,75 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f } if (plain) - signature = FARC_FArc; + if (signature == FARC_FARC) + flags = (farc_flags)0; + else + signature = FARC_FArc; + + f->ft &= signature == FARC_FARC; bool compressed = false; bool encrypted = false; switch (signature) { - case FARC_FARC: - f->flags = flags; - compressed = !!(flags & FARC_GZIP); - encrypted = !!(flags & FARC_AES); + case FARC_FArc: + default: + f->flags = (farc_flags)0; break; case FARC_FArC: f->flags = (farc_flags)0; compressed = true; break; - default: - f->flags = (farc_flags)0; - break; - } - - size_t header_length = 0; - switch (signature) { case FARC_FARC: - header_length += sizeof(int32_t) * 5; - break; - default: - header_length += sizeof(int32_t); + f->flags = flags; + compressed = !!(flags & FARC_GZIP); + encrypted = !!(flags & FARC_AES); break; } - if (signature == FARC_FArc) - for (farc_file& i : f->files) { - header_length += i.name.size() + 1; - header_length += sizeof(int32_t) * 2; - } - else - for (farc_file& i : f->files) { - header_length += i.name.size() + 1; - header_length += sizeof(int32_t) * 3; - } + size_t header_length = sizeof(int32_t); + for (farc_file& i : f->files) + header_length += i.name.size() + 1; - size_t align = header_length + 8; - s.set_position(align_val(align, f->alignment), SEEK_SET); + switch (signature) { + case FARC_FArc: + header_length += sizeof(int32_t) * 2 * f->files.size(); + break; + case FARC_FArC: + default: + header_length += sizeof(int32_t) * 3 * f->files.size(); + break; + case FARC_FARC: + if (f->ft) { + f->header_size = max_def(f->header_size, 0x10u); + f->entry_size = max_def(f->entry_size, 0x10u); + + header_length += sizeof(int32_t) + f->header_size; + header_length += f->entry_size * f->files.size(); + + if (encrypted) { + size_t head_data_len = header_length - sizeof(int32_t) * 2; + head_data_len = align_val(head_data_len, 0x10); + if (head_data_len == header_length - sizeof(int32_t) * 2) + head_data_len += 0x10; + header_length = head_data_len + sizeof(int32_t) * 2; + + header_length += 0x10; + } + } + else { + header_length += sizeof(int32_t) * 4 + f->header_padding; + header_length += (sizeof(int32_t) * 3 + f->entry_padding) * f->files.size(); + } + break; + } + + size_t align = align_val(header_length + 8, max_def(f->alignment, encrypted ? 0x10u : 0x01u)); + s.set_position(align, SEEK_SET); size_t dir_len = f->directory_path.size(); aes128_ctx ctx; if (signature == FARC_FARC) - aes128_init_ctx(&ctx, key); + aes128_init_ctx(&ctx, f->ft ? key_ft : key); f->compression_level = clamp_def(f->compression_level, 0, 12); @@ -511,9 +538,17 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f free_def(temp); } + std::vector size_compressed_enc; + if (f->ft) { + time_t t; + srand((uint32_t)_time64(&t)); + } + + if (encrypted) + size_compressed_enc.resize(f->files.size()); + for (farc_file& i : f->files) { i.offset = s.get_position(); - size_t file_len = i.size; if (i.encrypted && encrypted) { void* t1; @@ -521,7 +556,7 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f if (i.compressed && compressed) { if (!i.data_compressed || i.data_changed) { free_def(i.data_compressed); - deflate::compress_gzip(i.data, file_len, i.data_compressed, + deflate::compress_gzip(i.data, i.size, i.data_compressed, i.size_compressed, f->compression_level, i.name.c_str()); } t1 = i.data_compressed; @@ -534,21 +569,45 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f t1_len = i.size; } - size_t t2_len = align_val(t1_len, f->alignment); - uint8_t* t2 = (uint8_t*)force_malloc(t2_len); - memcpy(t2, t1, t1_len); - memset(t2 + t1_len, 0x78, t2_len - t1_len); + if (f->ft) { + size_t t2_len = align_val(t1_len, 0x10); + if (t2_len == t1_len) + t2_len += 0x10; + t2_len += 0x10; + size_compressed_enc.data()[&i - f->files.data()] = t2_len; - aes128_ecb_encrypt_buffer(&ctx, t2, t2_len); + uint8_t* t2 = (uint8_t*)force_malloc(t2_len); + for (int32_t j = 0; j < 0x10; j++) + t2[j] = (uint8_t)rand(); + memcpy(t2 + 0x10, t1, t1_len); + const int32_t pkcs7_pad_len = (int32_t)(t2_len - t1_len - 0x10); + memset(t2 + 0x10 + t1_len, pkcs7_pad_len, pkcs7_pad_len); // PKCS7 Padding - s.write(t2, t2_len); - free_def(t2); + aes128_ctx_set_iv(&ctx, t2); + aes128_cbc_encrypt_buffer(&ctx, t2 + 0x10, t2_len - 0x10); + + s.write(t2, t2_len); + free_def(t2); + } + else { + size_t t2_len = align_val(align_val(t1_len, 0x10), f->alignment); + size_compressed_enc.data()[&i - f->files.data()] = t2_len; + + uint8_t* t2 = (uint8_t*)force_malloc(t2_len); + memcpy(t2, t1, t1_len); + memset(t2 + t1_len, 0x78, t2_len - t1_len); + + aes128_ecb_encrypt_buffer(&ctx, t2, t2_len); + + s.write(t2, t2_len); + free_def(t2); + } } else if (i.compressed && compressed) { i.encrypted = false; if (!i.data_compressed || i.data_changed) { free_def(i.data_compressed); - deflate::compress_gzip(i.data, file_len, i.data_compressed, + deflate::compress_gzip(i.data, i.size, i.data_compressed, i.size_compressed, f->compression_level, i.name.c_str()); } s.write(i.data_compressed, i.size_compressed); @@ -558,12 +617,72 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f i.compressed = false; i.encrypted = false; free_def(i.data_compressed); - s.write(i.data, file_len); + s.write(i.data, i.size); farc_write_padding(f, s, i.size); } i.data_changed = false; } + if (f->ft) { + s.set_position(0, SEEK_SET); + s.write_uint32_t_reverse_endianness(FARC_FARC, true); + s.write_uint32_t_reverse_endianness((int32_t)header_length, true); + s.write_uint32_t_reverse_endianness(f->flags, true); + s.write_uint32_t_reverse_endianness(0x00, true); + + size_t head_data_len = header_length - sizeof(int32_t) * 2; + uint8_t* head_data = (uint8_t*)force_malloc(head_data_len); + if (encrypted) + for (int32_t i = 0; i < 0x10; i++) + head_data[i] = (uint8_t)rand(); + + uint8_t* dt = head_data; + if (encrypted) + dt += 0x10; + + store_reverse_endianness_uint32_t((void*)dt, f->header_size); + store_reverse_endianness_uint32_t((void*)(dt + 4), f->alignment); + store_reverse_endianness_uint32_t((void*)(dt + 8), (uint32_t)f->files.size()); + store_reverse_endianness_uint32_t((void*)(dt + 12), f->entry_size); + dt += f->header_size; + + for (farc_file& i : f->files) { + memcpy(dt, i.name.c_str(), i.name.size()); + dt[i.name.size()] = 0; + dt += i.name.size() + 1; + + farc_flags flags = (farc_flags)0; + if (i.compressed && compressed) + enum_or(flags, FARC_GZIP); + if (i.encrypted && encrypted) + enum_or(flags, FARC_AES); + + store_reverse_endianness_uint32_t((void*)dt, (uint32_t)i.offset); + if (i.encrypted && encrypted) + store_reverse_endianness_uint32_t((void*)(dt + 4), + (uint32_t)size_compressed_enc.data()[&i - f->files.data()]); + else if (i.compressed && compressed) + store_reverse_endianness_uint32_t((void*)(dt + 4), (uint32_t)i.size_compressed); + else + store_reverse_endianness_uint32_t((void*)(dt + 4), (uint32_t)i.size); + store_reverse_endianness_uint32_t((void*)(dt + 8), (uint32_t)i.size); + store_reverse_endianness_uint32_t((void*)(dt + 12), (uint32_t)flags); + dt += f->entry_size; + } + + if (encrypted) { + const int32_t pkcs7_pad_len = (int32_t)(head_data_len - (dt - head_data)); + memset(dt, pkcs7_pad_len, pkcs7_pad_len); // PKCS7 Padding + + aes128_ctx_set_iv(&ctx, head_data); + aes128_cbc_encrypt_buffer(&ctx, head_data + 0x10, head_data_len - 0x10); + } + + s.write(head_data, head_data_len); + free_def(head_data); + return; + } + s.set_position(0, SEEK_SET); switch (signature) { case FARC_FArc: @@ -583,8 +702,10 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f s.write_uint32_t_reverse_endianness(f->flags, true); s.write_uint32_t_reverse_endianness(0x00, true); s.write_uint32_t_reverse_endianness(f->alignment, true); - s.write_uint32_t_reverse_endianness(0x00, true); - s.write_uint32_t_reverse_endianness(0x00, true); + s.write_uint32_t_reverse_endianness(f->entry_padding, true); + s.write_uint32_t_reverse_endianness(f->header_padding, true); + if (f->header_padding) + s.write(f->header_padding); break; } @@ -614,14 +735,16 @@ static void farc_pack_files(farc* f, stream& s, farc_signature signature, farc_f for (farc_file& i : f->files) { s.write_string_null_terminated(i.name); s.write_int32_t_reverse_endianness((int32_t)i.offset, true); - if (i.compressed) { - s.write_int32_t_reverse_endianness((int32_t)i.size_compressed, true); + if (i.encrypted && encrypted) + s.write_int32_t_reverse_endianness( + (uint32_t)size_compressed_enc.data()[&i - f->files.data()], true); + else if (i.compressed && compressed) + s.write_int32_t_reverse_endianness((uint32_t)i.size_compressed, true); + else s.write_int32_t_reverse_endianness((int32_t)i.size, true); - } - else { - s.write_int32_t_reverse_endianness((int32_t)i.size, true); - s.write_int32_t_reverse_endianness(0x00, true); - } + s.write_int32_t_reverse_endianness((int32_t)i.size, true); + if (f->entry_padding) + s.write(f->entry_padding); } break; } @@ -679,10 +802,17 @@ static errno_t farc_read_header(farc* f, stream& s) { } if (f->ft) { - f->alignment = load_reverse_endianness_uint32_t((void*)dt); + f->header_size = load_reverse_endianness_uint32_t((void*)dt); + if (header_length < f->header_size || f->header_size < 0x10) + return -3; + + f->alignment = load_reverse_endianness_uint32_t((void*)(dt + 4)); uint32_t files_count = load_reverse_endianness_uint32_t((void*)(dt + 8)); - uint32_t entry_size = load_reverse_endianness_uint32_t((void*)(dt + 12)); - dt += sizeof(uint32_t) * 4; + f->entry_size = load_reverse_endianness_uint32_t((void*)(dt + 12)); + if (f->entry_size < 0x10) + return -4; + + dt += sizeof(uint32_t) * 4 + (f->header_size - 0x10); f->files.clear(); f->files.reserve(files_count); @@ -691,7 +821,8 @@ static errno_t farc_read_header(farc* f, stream& s) { while (dt[length]) length++; - farc_file ff; + f->files.push_back({}); + farc_file& ff = f->files.back(); ff.name.assign((const char*)dt, length); dt += length + 1; ff.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); @@ -699,17 +830,9 @@ static errno_t farc_read_header(farc* f, stream& s) { ff.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 8)); farc_flags flags = (farc_flags)load_reverse_endianness_uint32_t((void*)(dt + 12)); - if (ff.size) - ff.compressed = true; - else { - ff.size = ff.size_compressed; - ff.size_compressed = 0; - ff.compressed = false; - } - - ff.encrypted = ((f->flags | flags) & FARC_AES) != 0; - f->files.push_back(ff); - dt += entry_size; + ff.compressed = !!(flags & FARC_GZIP); + ff.encrypted = !!(flags & FARC_AES); + dt += f->entry_size; files_count--; } @@ -720,11 +843,17 @@ static errno_t farc_read_header(farc* f, stream& s) { size_t entry_size; if (f->signature == FARC_FARC) { f->alignment = load_reverse_endianness_uint32_t((void*)dt); - uint32_t entry_offset = load_reverse_endianness_uint32_t((void*)(dt + 4)); - uint32_t header_offset = load_reverse_endianness_uint32_t((void*)(dt + 8)); - dt += sizeof(uint32_t) * 3; + if ((f->flags & FARC_AES) && f->alignment < 0x10) + return -5; - entry_size = sizeof(uint32_t) * 3 + entry_offset; + f->entry_padding = load_reverse_endianness_uint32_t((void*)(dt + 4)); + f->header_padding = load_reverse_endianness_uint32_t((void*)(dt + 8)); + dt += sizeof(uint32_t) * 3 + f->header_padding; + + if (dt - d_t >= header_length) + return -6; + + entry_size = sizeof(uint32_t) * 3 + f->entry_padding; } else if (f->signature != FARC_FArc) { f->alignment = load_reverse_endianness_uint32_t((void*)dt); @@ -739,56 +868,64 @@ static errno_t farc_read_header(farc* f, stream& s) { entry_size = sizeof(uint32_t) * 2; } - size_t count = 0; + size_t files_count = 0; uint8_t* position = dt; while (dt - d_t < header_length) { while (*dt++); dt += entry_size; - count++; + files_count++; } dt = position; - bool encrypted = !!(f->flags & FARC_AES); + const bool encrypted = !!(f->flags & FARC_AES); f->files.clear(); - f->files.resize(count); + f->files.reserve(files_count); if (f->signature != FARC_FArc) - for (farc_file& i : f->files) { + while (dt - d_t < header_length && files_count) { size_t length = 0; while (dt[length]) length++; - i.name.assign((const char*)dt, length); - dt += length + 1; - i.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); - i.size_compressed = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); - i.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 8)); - if (i.size) - i.compressed = true; + f->files.push_back({}); + farc_file& ff = f->files.back(); + ff.name.assign((const char*)dt, length); + dt += length + 1; + ff.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); + ff.size_compressed = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); + ff.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 8)); + + if (ff.size) + ff.compressed = true; else { - i.size = i.size_compressed; - i.size_compressed = 0; - i.compressed = false; + ff.size = ff.size_compressed; + ff.size_compressed = 0; + ff.compressed = false; } - i.encrypted = encrypted; + ff.encrypted = encrypted; dt += entry_size; + files_count--; } else - for (farc_file& i : f->files) { + while (dt - d_t < header_length && files_count) { size_t length = 0; while (dt[length]) length++; - i.name.assign((const char*)dt, length); - dt += length + 1; - i.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); - i.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); - i.size_compressed = 0; - i.compressed = false; - i.encrypted = false; + f->files.push_back({}); + farc_file& ff = f->files.back(); + ff.name.assign((const char*)dt, length); + dt += length + 1; + ff.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); + ff.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); + + ff.size_compressed = 0; + ff.compressed = false; + ff.encrypted = false; dt += sizeof(int32_t) * 2; + files_count--; } free_def(d_t); @@ -865,8 +1002,8 @@ static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save, char* } } else if (ff->compressed || ff->encrypted) { - size_t temp_s = ff->compressed ? ff->size_compressed : ff->size; - temp_s = ff->encrypted ? align_val(temp_s, f->alignment) : temp_s; + size_t temp_s = ff->compressed || ff->encrypted ? ff->size_compressed : ff->size; + temp_s = ff->encrypted ? align_val(align_val(temp_s, 0x10), f->alignment) : temp_s; void* temp = force_malloc(temp_s); s.read(temp, temp_s); diff --git a/src/KKdLib/farc.hpp b/src/KKdLib/farc.hpp index c47d0e4b..15d21595 100644 --- a/src/KKdLib/farc.hpp +++ b/src/KKdLib/farc.hpp @@ -53,9 +53,17 @@ struct farc { farc_flags flags; int32_t compression_level; uint32_t alignment; + union { + uint32_t entry_padding; + uint32_t entry_size; + }; + union { + uint32_t header_padding; + uint32_t header_size; + }; bool ft; - farc(); + farc(farc_signature signature = FARC_FArC, farc_flags flags = (farc_flags)0, bool ft = false); ~farc(); farc_file* add_file(const char* name); diff --git a/src/ReDIVA/x_pv_game.cpp b/src/ReDIVA/x_pv_game.cpp index e2fd3d38..b269189e 100644 --- a/src/ReDIVA/x_pv_game.cpp +++ b/src/ReDIVA/x_pv_game.cpp @@ -6855,7 +6855,7 @@ bool x_pv_game::ctrl() { if (!src || !*src) return 0; - for (int32_t i = 0; i < size - 1; i++, b++) { + for (int32_t i = 0; *src && i < size - 1; i++, b++) { char c = *b = *src++; if (!c) { b++; @@ -7354,6 +7354,9 @@ bool x_pv_game::ctrl() { x_pv_game_write_dsc(pv_data.pv_data.dsc, pv_data.pv_id, x_pack_aft_out_dir); x_pv_game_write_dsc(pv_data.pv_data.dsc, pv_data.pv_id, x_pack_mmp_out_dir); + time_t t; + srand((uint32_t)_time64(&t)); + std::vector chara_effect_auth_3ds; std::vector song_effect_auth_3ds; std::vector stage_data_effect_auth_3ds; @@ -7604,7 +7607,10 @@ bool x_pv_game::ctrl() { x_pv_game_write_auth_3d_category(name, &auth_3d_db, avail_uids, x_pack_aft_out_dir); - farc* effpv_farc = new farc; + farc* effpv_farc = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, FARC_NONE); + effpv_farc->entry_padding = 0x01 + (rand() % 0x10); + effpv_farc->header_padding = 0x01 + (rand() % 0x20); + for (auth_3d*& i : song_effect_auth_3ds) x_pv_game_write_auth_3d(effpv_farc, i, &auth_3d_db, name, avail_uids, x_pack_aft_out_dir); @@ -7621,7 +7627,10 @@ bool x_pv_game::ctrl() { x_pv_game_write_auth_3d_category(name, &auth_3d_db, avail_uids, x_pack_aft_out_dir); - farc* effstgpv_farc = new farc; + farc* effstgpv_farc = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, FARC_NONE); + effstgpv_farc->entry_padding = 0x01 + (rand() % 0x10); + effstgpv_farc->header_padding = 0x01 + (rand() % 0x20); + for (stage_data_modern& i : stage_data.stage_data.stg_db.stage_modern) for (uint32_t& j : i.auth_3d_ids) { auth_3d* auth = auth_3d_data_get_auth_3d(j); @@ -7663,7 +7672,10 @@ bool x_pv_game::ctrl() { x_pv_game_write_auth_3d_category(name, &auth_3d_db, avail_uids, x_pack_mmp_out_dir); - farc* effpv_farc = new farc; + farc* effpv_farc = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, FARC_NONE, true); + effpv_farc->entry_size = 0x11 + (rand() % 0x10); + effpv_farc->header_size = 0x11 + (rand() % 0x20); + for (auth_3d*& i : song_effect_auth_3ds) x_pv_game_write_auth_3d(effpv_farc, i, &auth_3d_db, name, avail_uids, x_pack_mmp_out_dir); @@ -7680,7 +7692,10 @@ bool x_pv_game::ctrl() { x_pv_game_write_auth_3d_category(name, &auth_3d_db, avail_uids, x_pack_mmp_out_dir); - farc* effstgpv_farc = new farc; + farc* effstgpv_farc = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, FARC_NONE, true); + effstgpv_farc->entry_size = 0x11 + (rand() % 0x10); + effstgpv_farc->header_size = 0x11 + (rand() % 0x20); + for (stage_data_modern& i : stage_data.stage_data.stg_db.stage_modern) for (uint32_t& j : i.auth_3d_ids) { auth_3d* auth = auth_3d_data_get_auth_3d(j); @@ -9327,9 +9342,11 @@ void FarcCompress::FarcThreadMain(int32_t index) { waitable_timer timer; while (true) { if (thread.state == FARC_COMPRESS_STATE_WORKING) { - thread.f->write(thread.path.c_str(), FARC_FArC, FARC_NONE, true, false); - delete thread.f; - thread.f = 0; + if (thread.f) { + thread.f->write(thread.path.c_str(), thread.f->signature, thread.f->flags, true, false); + delete thread.f; + thread.f = 0; + } if (thread.state == FARC_COMPRESS_STATE_END) break; @@ -10009,9 +10026,10 @@ obj_set_reflect* x_pack_reflect::get_obj_set_reflect(uint32_t id) { XPVGameBaker::XPVGameBaker() : charas(), modules(), pv_tit_aet_set_ids(), pv_tit_spr_set_ids(), pv_tit_aet_ids(), obj_set_encode_flags(), pv_tit_init(), -wait(), start(), exit(), next(), only_firstread_x(), write_file() { +wait(), start(), exit(), next(), write_file(), only_firstread_x() { index = -1; chara_index = CHARA_MIKU; + farc = true; for (::chara_index& i : charas) i = CHARA_MIKU; @@ -10101,7 +10119,7 @@ void XPVGameBaker::window() { float_t w = 360.0f; float_t h = (float_t)height; - h = min_def(h, 228.0f); + h = min_def(h, 250.0f); ImGui::SetNextWindowPos({ (float_t)width - w, 0.0f }, ImGuiCond_Always); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); @@ -10121,6 +10139,7 @@ void XPVGameBaker::window() { return; } + ImGui::Checkbox("FARC", &farc); ImGui::Checkbox("Write only firstread_x.bin", &only_firstread_x); ImGui::SeparatorText("Object Set Encode Flags"); @@ -12500,7 +12519,16 @@ static bool x_pv_game_write_auth_3d(farc* f, auth_3d* auth, auth_3d_database_fil bool own_farc = !f; if (own_farc) - f = new farc; + if (out_dir == x_pack_mmp_out_dir) { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, FARC_NONE, true); + f->entry_size = 0x11 + (rand() % 0x10); + f->header_size = 0x11 + (rand() % 0x20); + } + else { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC); + f->entry_padding = 0x01 + (rand() % 0x10); + f->header_padding = 0x01 + (rand() % 0x20); + } farc_file* ff = f->add_file(name); ff->name.append(".a3da"); @@ -13197,7 +13225,8 @@ static void x_pv_game_write_glitter(Glitter::EffectGroup* eff_group, const auth_ Glitter::FileWriter::Write(Glitter::X, &temp_eff_group, sprintf_s_string("%s\\%s", out_dir, "particle_x\\").c_str(), name, (Glitter::FileWriterFlags)(Glitter::FILE_WRITER_COMPRESS - | Glitter::FILE_WRITER_ENCRYPT | Glitter::FILE_WRITER_NO_LIST)); + | Glitter::FILE_WRITER_ENCRYPT | Glitter::FILE_WRITER_NO_LIST + | (out_dir == x_pack_mmp_out_dir ? Glitter::FILE_WRITER_FT : 0))); } static void x_pv_game_write_object_set_material_msgpack_read(const char* path, @@ -13439,7 +13468,18 @@ static void x_pv_game_write_object_set(obj_set* obj_set, const std::string& name ::obj_set* set = alloc->allocate<::obj_set>(); set->move_data(obj_set, alloc); - farc* f = new farc; + farc* f; + if (out_dir == x_pack_mmp_out_dir) { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, (farc_flags)(FARC_AES | FARC_GZIP), true); + f->entry_size = 0x11 + (rand() % 0x10); + f->header_size = 0x11 + (rand() % 0x20); + } + else { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, (farc_flags)(FARC_AES | FARC_GZIP)); + f->entry_padding = 0x01 + (rand() % 0x10); + f->header_padding = 0x01 + (rand() % 0x20); + } + { data_struct* x_data = &data_list[DATA_X]; @@ -13460,6 +13500,7 @@ static void x_pv_game_write_object_set(obj_set* obj_set, const std::string& name farc_file* ff_tex = f->add_file((file_name + "_tex.bin").c_str()); txp.pack_file(&ff_tex->data, &ff_tex->size, false); ff_tex->compressed = true; + ff_tex->encrypted = true; } } @@ -13629,6 +13670,7 @@ static void x_pv_game_write_object_set(obj_set* obj_set, const std::string& name farc_file* ff_obj = f->add_file((file_name + "_obj.bin").c_str()); set->pack_file(&ff_obj->data, &ff_obj->size); ff_obj->compressed = true; + ff_obj->encrypted = true; } farc_compress_ptr->AddFarc(f, sprintf_s_string("%s\\objset\\%s", out_dir, file_name.c_str())); @@ -14560,11 +14602,22 @@ static void x_pv_game_write_spr(uint32_t spr_set_id, x_pv_game_fix_txp_set(set->txp, out_dir); - farc* f = new farc; + farc* f; + if (out_dir == x_pack_mmp_out_dir) { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, (farc_flags)(FARC_AES | FARC_GZIP), true); + f->entry_size = 0x11 + (rand() % 0x10); + f->header_size = 0x11 + (rand() % 0x20); + } + else { + f = new farc(x_pv_game_baker_ptr->farc ? FARC_FARC : FARC_FArC, (farc_flags)(FARC_AES | FARC_GZIP)); + f->entry_padding = 0x01 + (rand() % 0x10); + f->header_padding = 0x01 + (rand() % 0x20); + } farc_file* ff_bin = f->add_file(spr_db_spr_set->file_name.c_str()); set->pack_file(&ff_bin->data, &ff_bin->size); ff_bin->compressed = true; + ff_bin->encrypted = true; file_name.assign(spr_db_spr_set->file_name); pos = file_name.rfind(".bin"); diff --git a/src/ReDIVA/x_pv_game.hpp b/src/ReDIVA/x_pv_game.hpp index 4721e7e2..c0e5666e 100644 --- a/src/ReDIVA/x_pv_game.hpp +++ b/src/ReDIVA/x_pv_game.hpp @@ -958,6 +958,7 @@ public: bool next; bool write_file; bool only_firstread_x; + bool farc; aet_database pv_tit_aet_db; sprite_database pv_tit_spr_db;