Compare commits

...

1 Commits

Author SHA1 Message Date
607c3bfd38 refactor: various fixes
- Drop thread priority by 1
- Reduce signed/unsigned conversions
2024-12-22 00:24:47 +09:00

View File

@ -1,12 +1,16 @@
#pragma once #pragma once
#include <algorithm>
#include "infra/infra.h" #include "infra/infra.h"
#include "qmc2/qmc2.h" #include "qmc2/qmc2.h"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#else
#include <pthread.h>
#endif #endif
#include <endian_helper.h>
#include <str_helper.h> #include <str_helper.h>
#include <array> #include <array>
#include <condition_variable> #include <condition_variable>
@ -14,7 +18,6 @@
#include <fstream> #include <fstream>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include <string_view>
#include <vector> #include <vector>
class KggTask { class KggTask {
@ -34,16 +37,15 @@ class KggTask {
0xA8, 0xAF, 0xA6, 0x8E, 0x0F, 0xFF, 0x99, 0x14}; 0xA8, 0xAF, 0xA6, 0x8E, 0x0F, 0xFF, 0x99, 0x14};
std::ifstream kgg_stream_in(kgg_path_, std::ios::binary); std::ifstream kgg_stream_in(kgg_path_, std::ios::binary);
char header[0x100]{}; std::array<uint8_t, 0x400> header{};
kgg_stream_in.read(header, sizeof(header)); kgg_stream_in.read(reinterpret_cast<char*>(header.data()), header.size());
if (std::equal(kMagicHeader.cbegin(), kMagicHeader.cend(), header)) { if (std::equal(kMagicHeader.cbegin(), kMagicHeader.cend(), header.cbegin())) {
warning(LSR_STR("invalid kgg header")); warning(LSR_STR("invalid kgg header"));
return; return;
} }
const uint32_t offset_to_audio = *reinterpret_cast<uint32_t*>(&header[0x10]); const auto offset_to_audio = Endian::le_read<uint32_t>(&header[0x10]);
const uint32_t encrypt_mode = *reinterpret_cast<uint32_t*>(&header[0x14]); if (const auto mode = Endian::le_read<uint32_t>(&header[0x14]); mode != 5) {
if (encrypt_mode != 5) { lsr_eprintf("[WARN] unsupported enc_version (expect=0x05, got 0x%02x) (%s)\n", mode,
lsr_eprintf("[WARN] unsupported enc_version (expect=0x05, got 0x%02x) (%s)\n", encrypt_mode,
kgg_path_.filename().c_str()); kgg_path_.filename().c_str());
return; return;
} }
@ -69,20 +71,22 @@ class KggTask {
return; return;
} }
std::string magic(4, 0); std::array<uint8_t, 4> magic{};
kgg_stream_in.seekg(offset_to_audio, std::ios::beg); kgg_stream_in.seekg(offset_to_audio, std::ios::beg);
kgg_stream_in.read(magic.data(), 4); kgg_stream_in.read(reinterpret_cast<char*>(magic.data()), 4);
qmc2->Decrypt(std::span(reinterpret_cast<uint8_t*>(magic.data()), 4), 0); qmc2->Decrypt(magic, 0);
auto real_ext = DetectRealExt(magic); auto real_ext = DetectRealExt(magic);
lsr::string new_name = kgg_path_.stem().native() + lsr::string(suffix) + LSR_STR(".") + real_ext; lsr::string new_name = kgg_path_.stem().native() + lsr::string(suffix) + LSR_STR(".") + real_ext;
auto out_path = out_dir_ / new_name; auto out_path = out_dir_ / new_name;
if (exists(out_path)) { if (exists(out_path)) {
warning(lsr::string(LSR_STR("output file already exists: ")) + out_path.filename().native()); warning(lsr::string(LSR_STR("output file already exists: ")) + new_name);
return; return;
} }
kgg_stream_in.seekg(0, std::ios::end);
const auto file_size = static_cast<size_t>(kgg_stream_in.tellg());
kgg_stream_in.seekg(offset_to_audio, std::ios::beg); kgg_stream_in.seekg(offset_to_audio, std::ios::beg);
std::ofstream ofs_decrypted(out_path, std::ios::binary); std::ofstream ofs_decrypted(out_path, std::ios::binary);
if (!ofs_decrypted.is_open()) { if (!ofs_decrypted.is_open()) {
@ -92,29 +96,32 @@ class KggTask {
size_t offset{0}; size_t offset{0};
thread_local std::vector<uint8_t> temp_buffer(1024 * 1024, 0); thread_local std::vector<uint8_t> temp_buffer(1024 * 1024, 0);
auto buf_signed = std::span(reinterpret_cast<char*>(temp_buffer.data()), temp_buffer.size()); auto read_page_len = static_cast<std::streamsize>(temp_buffer.size());
auto buf_unsigned = std::span(temp_buffer);
while (!kgg_stream_in.eof()) { while (!kgg_stream_in.eof()) {
kgg_stream_in.read(buf_signed.data(), buf_signed.size()); kgg_stream_in.read(reinterpret_cast<char*>(temp_buffer.data()), read_page_len);
const auto n = static_cast<size_t>(kgg_stream_in.gcount()); const auto n = kgg_stream_in.gcount();
qmc2->Decrypt(buf_unsigned.subspan(0, n), offset); qmc2->Decrypt(std::span(temp_buffer.begin(), temp_buffer.begin() + n), offset);
ofs_decrypted.write(buf_signed.data(), n); ofs_decrypted.write(reinterpret_cast<char*>(temp_buffer.data()), n);
offset += n; offset += n;
} }
info(lsr::string(LSR_STR("** OK ** -> ")) + out_path.filename().native()); if (offset + offset_to_audio != file_size) {
warning(LSR_STR("OK (size mismatch)"));
} else {
info(lsr::string(LSR_STR("** OK ** -> ")) + out_path.filename().native());
}
} }
private: private:
std::filesystem::path kgg_path_; std::filesystem::path kgg_path_;
std::filesystem::path out_dir_; std::filesystem::path out_dir_;
static const lsr::character* DetectRealExt(const std::string_view magic) { static const lsr::character* DetectRealExt(const std::span<uint8_t> magic) {
if (magic == "fLaC") { if (std::equal(magic.begin(), magic.end(), "fLaC")) {
return LSR_STR("flac"); return LSR_STR("flac");
} }
if (magic == "OggS") { if (std::equal(magic.begin(), magic.end(), "OggS")) {
return LSR_STR("ogg"); return LSR_STR("ogg");
} }
return LSR_STR("mp3"); return LSR_STR("mp3");
@ -169,16 +176,32 @@ class KggTaskQueue {
Infra::kgm_ekey_db_t ekey_db_; Infra::kgm_ekey_db_t ekey_db_;
lsr::string suffix_; lsr::string suffix_;
void WorkerThreadBody() { void WorkerThreadBody() {
#ifdef _WIN32 ReduceThreadPriority();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
#endif
std::unique_ptr<KggTask> task{nullptr}; std::unique_ptr<KggTask> task{nullptr};
while ((task = Pop())) { while ((task = Pop())) {
task->Execute(ekey_db_, suffix_); task->Execute(ekey_db_, suffix_);
} }
} }
static void ReduceThreadPriority() {
#ifdef _WIN32
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
#else
pthread_t this_thread = pthread_self();
sched_param params;
int policy;
if (pthread_getschedparam(this_thread, &policy, &params) != 0) {
perror("pthread_getschedparam");
return;
}
params.sched_priority = std::max(params.sched_priority, sched_get_priority_min(policy));
if (pthread_setschedparam(this_thread, policy, &params) != 0) {
perror("pthread_setschedparam");
}
#endif
}
std::mutex mutex_{}; std::mutex mutex_{};
std::condition_variable signal_; std::condition_variable signal_;
std::queue<std::unique_ptr<KggTask>> tasks_{}; std::queue<std::unique_ptr<KggTask>> tasks_{};