Compare commits
2 Commits
d19ed2d57f
...
10e0c7446b
Author | SHA1 | Date | |
---|---|---|---|
10e0c7446b | |||
395d5628d8 |
@ -35,7 +35,10 @@ target_include_directories(kgg-dec
|
|||||||
src/tc_tea
|
src/tc_tea
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(kgg-dec PRIVATE shell32 ole32 libaes libmd5)
|
target_link_libraries(kgg-dec PRIVATE libaes libmd5)
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(kgg-dec PRIVATE shell32 ole32)
|
||||||
|
endif ()
|
||||||
if (WinSQLite3_Found)
|
if (WinSQLite3_Found)
|
||||||
target_link_libraries(kgg-dec PRIVATE WinSQLite3)
|
target_link_libraries(kgg-dec PRIVATE WinSQLite3)
|
||||||
target_include_directories(kgg-dec PRIVATE ${WindowsKitInclude})
|
target_include_directories(kgg-dec PRIVATE ${WindowsKitInclude})
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
{
|
{
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"generator": "Ninja",
|
"generator": "Ninja Multi-Config",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||||
}
|
}
|
||||||
@ -29,6 +29,12 @@
|
|||||||
"CMAKE_EXE_LINKER_FLAGS": "-static -static-libgcc -static-libstdc++ -lucrt"
|
"CMAKE_EXE_LINKER_FLAGS": "-static -static-libgcc -static-libstdc++ -lucrt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ninja",
|
||||||
|
"inherits": "default",
|
||||||
|
"description": "Default Ninja Configuration",
|
||||||
|
"binaryDir": "${sourceDir}/build/default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vs",
|
"name": "vs",
|
||||||
"inherits": "default",
|
"inherits": "default",
|
||||||
@ -54,6 +60,18 @@
|
|||||||
"description": "Build using MinGW (Release)",
|
"description": "Build using MinGW (Release)",
|
||||||
"configuration": "Release"
|
"configuration": "Release"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ninja-debug",
|
||||||
|
"configurePreset": "ninja",
|
||||||
|
"description": "Build using Ninja (Debug)",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ninja-release",
|
||||||
|
"configurePreset": "ninja",
|
||||||
|
"description": "Build using Ninja (Release)",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vs-debug",
|
"name": "vs-debug",
|
||||||
"configurePreset": "vs",
|
"configurePreset": "vs",
|
||||||
|
16
README.MD
16
README.MD
@ -50,7 +50,14 @@ cmake --build --preset vs-release --config Release
|
|||||||
copy /y README.MD .\\build\\vs2022\\
|
copy /y README.MD .\\build\\vs2022\\
|
||||||
```
|
```
|
||||||
|
|
||||||
## 第三方软件
|
### CMake 参数
|
||||||
|
|
||||||
|
CMake 支持以下参数:
|
||||||
|
|
||||||
|
- `USE_WIN_SQLITE3` - 使用 Windows 内置的 SQLite3 链接库(仅限 Windows + MSVC 编译环境)。
|
||||||
|
- `USE_WIN_CRYPTO` - 使用 Windows 内置的加密/哈希实现,而非软件实现(仅限 Windows 目标)。
|
||||||
|
|
||||||
|
### 第三方软件
|
||||||
|
|
||||||
该程序用到了以下第三方软件:
|
该程序用到了以下第三方软件:
|
||||||
|
|
||||||
@ -58,3 +65,10 @@ copy /y README.MD .\\build\\vs2022\\
|
|||||||
- [Tiny AES in C](https://github.com/kokke/tiny-AES-c) (Public Domain)
|
- [Tiny AES in C](https://github.com/kokke/tiny-AES-c) (Public Domain)
|
||||||
- [MD5.c](https://github.com/freebsd/freebsd-src/blob/release/14.2.0/sys/kern/md5c.c) (from FreeBSD)
|
- [MD5.c](https://github.com/freebsd/freebsd-src/blob/release/14.2.0/sys/kern/md5c.c) (from FreeBSD)
|
||||||
- Derived from the "RSA Data Security, Inc. MD5 Message-Digest Algorithm".
|
- Derived from the "RSA Data Security, Inc. MD5 Message-Digest Algorithm".
|
||||||
|
|
||||||
|
### Windows 7 用户注意
|
||||||
|
|
||||||
|
请从 SQLite 官网下载 [`sqlite-dll-win-x64-*.zip`](https://www.sqlite.org/download.html#win32)
|
||||||
|
并将压缩包内的 `sqlite3.dll` 放置到 `kgg-dec.exe` 同目录下,并更名为 `winsqlite3.dll`。
|
||||||
|
|
||||||
|
Windows 10 或更新版本不需要此操作,因为 Windows 10 或以上的版本内置该文件。
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
38
src/common/str_helper.h
Normal file
38
src/common/str_helper.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace lsr {
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
typedef wchar_t character;
|
||||||
|
typedef std::wstring string;
|
||||||
|
typedef std::wstring_view string_view;
|
||||||
|
#define LSR_STR(x) L##x
|
||||||
|
|
||||||
|
inline void write_stderr(const string& msg) {
|
||||||
|
fputws(msg.c_str(), stderr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
typedef char character;
|
||||||
|
typedef std::string string;
|
||||||
|
typedef std::string_view string_view;
|
||||||
|
#define LSR_STR(x) x
|
||||||
|
|
||||||
|
inline void write_stderr(const string& msg) {
|
||||||
|
fputs(msg.c_str(), stderr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace lsr
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#define lsr___fprintf fwprintf
|
||||||
|
#else
|
||||||
|
#define lsr___fprintf fprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define lsr_eprintf(fmt, ...) lsr___fprintf(stderr, LSR_STR(fmt), __VA_ARGS__)
|
||||||
|
#define lsr_printf(fmt, ...) lsr___fprintf(stdout, LSR_STR(fmt), __VA_ARGS__)
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Infra {
|
namespace Infra {
|
||||||
|
62
src/jobs.hpp
62
src/jobs.hpp
@ -1,18 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "infra/infra.h"
|
||||||
#include "qmc2/qmc2.h"
|
#include "qmc2/qmc2.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <str_helper.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <thread>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class KggTask {
|
class KggTask {
|
||||||
@ -20,18 +22,14 @@ class KggTask {
|
|||||||
explicit KggTask(std::filesystem::path kgg_path, std::filesystem::path out_dir)
|
explicit KggTask(std::filesystem::path kgg_path, std::filesystem::path out_dir)
|
||||||
: kgg_path_(std::move(kgg_path)), out_dir_(std::move(out_dir)) {}
|
: kgg_path_(std::move(kgg_path)), out_dir_(std::move(out_dir)) {}
|
||||||
|
|
||||||
static void log(const std::wstring& msg) { fputws(msg.c_str(), stderr); }
|
void log(const lsr::string& level, const lsr::string& msg) const {
|
||||||
void warning(const std::wstring& msg) const {
|
lsr_eprintf("[%s] %s (%s)\n", level.c_str(), msg.c_str(), kgg_path_.filename().c_str());
|
||||||
log(std::format(L"[WARN] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
|
||||||
}
|
|
||||||
void error(const std::wstring& msg) const {
|
|
||||||
log(std::format(L"[ERR ] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
|
||||||
}
|
|
||||||
void info(const std::wstring& msg) const {
|
|
||||||
log(std::format(L"[INFO] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
|
||||||
}
|
}
|
||||||
|
void warning(const lsr::string& msg) const { log(LSR_STR("WARN"), msg); }
|
||||||
|
void error(const lsr::string& msg) const { log(LSR_STR("ERR "), msg); }
|
||||||
|
void info(const lsr::string& msg) const { log(LSR_STR("INFO"), msg); }
|
||||||
|
|
||||||
void Execute(const Infra::kgm_ekey_db_t& ekey_db, const std::wstring_view suffix) const {
|
void Execute(const Infra::kgm_ekey_db_t& ekey_db, const lsr::string_view suffix) const {
|
||||||
constexpr static std::array<uint8_t, 16> kMagicHeader{0x7C, 0xD5, 0x32, 0xEB, 0x86, 0x02, 0x7F, 0x4B,
|
constexpr static std::array<uint8_t, 16> kMagicHeader{0x7C, 0xD5, 0x32, 0xEB, 0x86, 0x02, 0x7F, 0x4B,
|
||||||
0xA8, 0xAF, 0xA6, 0x8E, 0x0F, 0xFF, 0x99, 0x14};
|
0xA8, 0xAF, 0xA6, 0x8E, 0x0F, 0xFF, 0x99, 0x14};
|
||||||
|
|
||||||
@ -39,18 +37,20 @@ class KggTask {
|
|||||||
char header[0x100]{};
|
char header[0x100]{};
|
||||||
kgg_stream_in.read(header, sizeof(header));
|
kgg_stream_in.read(header, sizeof(header));
|
||||||
if (std::equal(kMagicHeader.cbegin(), kMagicHeader.cend(), header)) {
|
if (std::equal(kMagicHeader.cbegin(), kMagicHeader.cend(), header)) {
|
||||||
warning(L"invalid kgg header");
|
warning(LSR_STR("invalid kgg header"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const uint32_t offset_to_audio = *reinterpret_cast<uint32_t*>(&header[0x10]);
|
const uint32_t offset_to_audio = *reinterpret_cast<uint32_t*>(&header[0x10]);
|
||||||
const uint32_t encrypt_mode = *reinterpret_cast<uint32_t*>(&header[0x14]);
|
const uint32_t encrypt_mode = *reinterpret_cast<uint32_t*>(&header[0x14]);
|
||||||
if (encrypt_mode != 5) {
|
if (encrypt_mode != 5) {
|
||||||
warning(std::format(L"unsupported enc_version (expect=0x05, got 0x{:02x})", encrypt_mode));
|
lsr_eprintf("[WARN] unsupported enc_version (expect=0x05, got 0x%02x) (%s)\n", encrypt_mode,
|
||||||
|
kgg_path_.filename().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t audio_hash_len = *reinterpret_cast<uint32_t*>(&header[0x44]);
|
uint32_t audio_hash_len = *reinterpret_cast<uint32_t*>(&header[0x44]);
|
||||||
if (audio_hash_len != 0x20) {
|
if (audio_hash_len != 0x20) {
|
||||||
warning(std::format(L"audio hash length invalid (expect=0x20, got 0x{:02x})", audio_hash_len));
|
lsr_eprintf("audio hash length invalid (expect=0x20, got 0x%02x) (%s)\n", audio_hash_len,
|
||||||
|
kgg_path_.filename().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string audio_hash(&header[0x48], &header[0x48 + audio_hash_len]);
|
std::string audio_hash(&header[0x48], &header[0x48 + audio_hash_len]);
|
||||||
@ -58,13 +58,13 @@ class KggTask {
|
|||||||
if (auto it = ekey_db.find(audio_hash); it != ekey_db.end()) {
|
if (auto it = ekey_db.find(audio_hash); it != ekey_db.end()) {
|
||||||
ekey = it->second;
|
ekey = it->second;
|
||||||
} else {
|
} else {
|
||||||
warning(L"ekey not found");
|
warning(LSR_STR("ekey not found"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto qmc2 = QMC2::Create(ekey);
|
auto qmc2 = QMC2::Create(ekey);
|
||||||
if (!qmc2) {
|
if (!qmc2) {
|
||||||
error(L"create qmc2 instance failed (ekey decode error?)");
|
error(LSR_STR("create qmc2 instance failed (ekey decode error?)"));
|
||||||
fprintf(stderr, "%s\n", ekey.c_str());
|
fprintf(stderr, "%s\n", ekey.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,17 +74,19 @@ class KggTask {
|
|||||||
kgg_stream_in.read(magic.data(), 4);
|
kgg_stream_in.read(magic.data(), 4);
|
||||||
qmc2->Decrypt(std::span(reinterpret_cast<uint8_t*>(magic.data()), 4), 0);
|
qmc2->Decrypt(std::span(reinterpret_cast<uint8_t*>(magic.data()), 4), 0);
|
||||||
auto real_ext = DetectRealExt(magic);
|
auto real_ext = DetectRealExt(magic);
|
||||||
auto out_path = out_dir_ / std::format(L"{}{}.{}", kgg_path_.stem().wstring(), suffix, real_ext);
|
|
||||||
|
lsr::string new_name = kgg_path_.stem().native() + lsr::string(suffix) + LSR_STR(".") + real_ext;
|
||||||
|
auto out_path = out_dir_ / new_name;
|
||||||
|
|
||||||
if (exists(out_path)) {
|
if (exists(out_path)) {
|
||||||
warning(std::format(L"output file already exists: {}", out_path.filename().wstring()));
|
warning(lsr::string(LSR_STR("output file already exists: ")) + out_path.filename().native());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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()) {
|
||||||
error(L"failed to open output file");
|
error(LSR_STR("failed to open output file"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,27 +103,27 @@ class KggTask {
|
|||||||
offset += n;
|
offset += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
info(std::format(L"** OK ** -> {}", out_path.filename().wstring()));
|
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 wchar_t* DetectRealExt(const std::string_view magic) {
|
static const lsr::character* DetectRealExt(const std::string_view magic) {
|
||||||
if (magic == "fLaC") {
|
if (magic == "fLaC") {
|
||||||
return L"flac";
|
return LSR_STR("flac");
|
||||||
}
|
}
|
||||||
if (magic == "OggS") {
|
if (magic == "OggS") {
|
||||||
return L"ogg";
|
return LSR_STR("ogg");
|
||||||
}
|
}
|
||||||
return L"mp3";
|
return LSR_STR("mp3");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class KggTaskQueue {
|
class KggTaskQueue {
|
||||||
public:
|
public:
|
||||||
explicit KggTaskQueue(Infra::kgm_ekey_db_t ekey_db, const std::wstring_view suffix)
|
explicit KggTaskQueue(Infra::kgm_ekey_db_t ekey_db, const lsr::string_view suffix)
|
||||||
: ekey_db_(std::move(ekey_db)), suffix_(suffix) {}
|
: ekey_db_(std::move(ekey_db)), suffix_(suffix) {}
|
||||||
|
|
||||||
void Push(std::unique_ptr<KggTask> task) {
|
void Push(std::unique_ptr<KggTask> task) {
|
||||||
@ -165,9 +167,11 @@ class KggTaskQueue {
|
|||||||
private:
|
private:
|
||||||
bool thread_end_{false};
|
bool thread_end_{false};
|
||||||
Infra::kgm_ekey_db_t ekey_db_;
|
Infra::kgm_ekey_db_t ekey_db_;
|
||||||
std::wstring suffix_;
|
lsr::string suffix_;
|
||||||
void WorkerThreadBody() {
|
void WorkerThreadBody() {
|
||||||
|
#ifdef _WIN32
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
|
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())) {
|
||||||
|
12
src/main.cpp
12
src/main.cpp
@ -1,7 +1,11 @@
|
|||||||
#include <sqlite3_wrapper.h>
|
#include <sqlite3_wrapper.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "infra/infra.h"
|
#include "infra/infra.h"
|
||||||
#include "jobs.hpp"
|
#include "jobs.hpp"
|
||||||
|
#include "str_helper.h"
|
||||||
#include "utils/cli.h"
|
#include "utils/cli.h"
|
||||||
|
|
||||||
using Infra::kgm_ekey_db_t;
|
using Infra::kgm_ekey_db_t;
|
||||||
@ -30,7 +34,7 @@ void WalkFileOrDir(KggTaskQueue& queue, const std::filesystem::path& input_path,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fputws(std::format(L"[WARN] invalid path: {}\n", target_path.wstring()).c_str(), stderr);
|
lsr_eprintf("[WARN] invalid path: %s\n", target_path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +60,11 @@ void print_banner() {
|
|||||||
print_usage();
|
print_usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char** argv) {
|
||||||
CliParser cli_args;
|
CliParser cli_args;
|
||||||
print_banner();
|
print_banner();
|
||||||
|
|
||||||
cli_args.parse_from_cli();
|
cli_args.parse_from_cli(argc, argv);
|
||||||
|
|
||||||
bool scan_all_exts = cli_args.get_scan_all_file_ext();
|
bool scan_all_exts = cli_args.get_scan_all_file_ext();
|
||||||
|
|
||||||
@ -105,7 +109,7 @@ int main() {
|
|||||||
|
|
||||||
auto input_files = cli_args.get_input_files();
|
auto input_files = cli_args.get_input_files();
|
||||||
if (input_files.empty()) {
|
if (input_files.empty()) {
|
||||||
input_files.emplace_back(L".");
|
input_files.emplace_back(LSR_STR("."));
|
||||||
}
|
}
|
||||||
for (auto& positional_arg : input_files) {
|
for (auto& positional_arg : input_files) {
|
||||||
WalkFileOrDir(queue, positional_arg, scan_all_exts);
|
WalkFileOrDir(queue, positional_arg, scan_all_exts);
|
||||||
|
@ -1,47 +1,58 @@
|
|||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
|
#include <str_helper.h>
|
||||||
|
|
||||||
#include <Windows.h>
|
#ifdef _WIN32
|
||||||
#include <clocale>
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
#include <clocale>
|
||||||
|
#include <Windows.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <knownfolders.h>
|
#include <knownfolders.h>
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
#endif
|
||||||
|
|
||||||
CliParser::CliParser() {
|
CliParser::CliParser() {
|
||||||
|
#ifdef _WIN32
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
setlocale(LC_ALL, ".UTF8");
|
setlocale(LC_ALL, ".UTF8");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CliParser::parse_from_cli() {
|
void CliParser::parse_from_cli(int argc_, char** argv_) {
|
||||||
int argc;
|
int argc{argc_};
|
||||||
|
#ifdef _WIN32
|
||||||
wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
|
#else
|
||||||
|
char**& argv = argv_;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<std::wstring> positional_args{};
|
std::vector<lsr::string> positional_args{};
|
||||||
std::unordered_map<std::wstring, std::wstring> named_args{};
|
std::unordered_map<lsr::string, lsr::string> named_args{};
|
||||||
|
|
||||||
bool positional_only{false};
|
bool positional_only{false};
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
std::wstring arg{argv[i]};
|
lsr::string arg{argv[i]};
|
||||||
if (arg == L"--") {
|
if (arg == LSR_STR("--")) {
|
||||||
positional_only = true;
|
positional_only = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!positional_only && arg.starts_with(L"--")) {
|
if (!positional_only && arg.starts_with(LSR_STR("--"))) {
|
||||||
auto pos = arg.find(L'=');
|
auto pos = arg.find(L'=');
|
||||||
if (pos != std::wstring::npos) {
|
if (pos != lsr::string::npos) {
|
||||||
named_args[arg.substr(2, pos - 2)] = arg.substr(pos + 1);
|
named_args[arg.substr(2, pos - 2)] = arg.substr(pos + 1);
|
||||||
} else if (++i < argc) {
|
} else if (++i < argc) {
|
||||||
named_args[arg.substr(2)] = argv[i];
|
named_args[arg.substr(2)] = argv[i];
|
||||||
} else {
|
} else {
|
||||||
named_args[arg.substr(2)] = L"";
|
named_args[arg.substr(2)] = LSR_STR("");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
positional_args.push_back(arg);
|
positional_args.push_back(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
LocalFree(argv);
|
LocalFree(argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
positional_args_ = positional_args;
|
positional_args_ = positional_args;
|
||||||
named_args_ = named_args;
|
named_args_ = named_args;
|
||||||
@ -49,13 +60,18 @@ void CliParser::parse_from_cli() {
|
|||||||
|
|
||||||
std::filesystem::path CliParser::get_db_path() const {
|
std::filesystem::path CliParser::get_db_path() const {
|
||||||
std::filesystem::path kugou_db{};
|
std::filesystem::path kugou_db{};
|
||||||
if (const auto& it = named_args_.find(L"db"); it != named_args_.end()) {
|
|
||||||
|
if (const auto& it = named_args_.find(LSR_STR("db")); it != named_args_.end()) {
|
||||||
kugou_db = std::filesystem::path{it->second};
|
kugou_db = std::filesystem::path{it->second};
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
PWSTR pAppDirPath{};
|
PWSTR pAppDirPath{};
|
||||||
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &pAppDirPath);
|
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &pAppDirPath);
|
||||||
kugou_db = std::filesystem::path{pAppDirPath} / L"Kugou8" / L"KGMusicV3.db";
|
kugou_db = std::filesystem::path{pAppDirPath} / L"Kugou8" / L"KGMusicV3.db";
|
||||||
CoTaskMemFree(pAppDirPath);
|
CoTaskMemFree(pAppDirPath);
|
||||||
|
#else
|
||||||
|
kugou_db = std::filesystem::path{"KGMusicV3.db"};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return absolute(kugou_db);
|
return absolute(kugou_db);
|
||||||
|
@ -1,30 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <str_helper.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
typedef std::pair<std::vector<std::wstring>, std::unordered_map<std::wstring, std::wstring>> parsed_raw_args_t;
|
typedef std::pair<std::vector<lsr::string>, std::unordered_map<lsr::string, lsr::string>> parsed_raw_args_t;
|
||||||
|
|
||||||
class CliParser {
|
class CliParser {
|
||||||
public:
|
public:
|
||||||
CliParser();
|
CliParser();
|
||||||
void parse_from_cli();
|
void parse_from_cli(int argc, char** argv);
|
||||||
|
|
||||||
[[nodiscard]] std::filesystem::path get_infra_dll() const;
|
[[nodiscard]] std::filesystem::path get_infra_dll() const;
|
||||||
[[nodiscard]] std::filesystem::path get_db_path() const;
|
[[nodiscard]] std::filesystem::path get_db_path() const;
|
||||||
[[nodiscard]] std::wstring get_file_suffix() const { return get_with_default(L"suffix", L"_kgg-dec"); }
|
[[nodiscard]] lsr::string get_file_suffix() const {
|
||||||
[[nodiscard]] bool get_scan_all_file_ext() const { return get_with_default(L"scan-all-file-ext", L"0") == L"1"; };
|
return get_with_default(LSR_STR("suffix"), LSR_STR("_kgg-dec"));
|
||||||
[[nodiscard]] std::vector<std::wstring> get_input_files() const { return positional_args_; }
|
}
|
||||||
|
[[nodiscard]] bool get_scan_all_file_ext() const {
|
||||||
|
return get_with_default(LSR_STR("scan-all-file-ext"), LSR_STR("0")) == LSR_STR("1");
|
||||||
|
};
|
||||||
|
[[nodiscard]] std::vector<lsr::string> get_input_files() const { return positional_args_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::wstring> positional_args_{};
|
std::vector<lsr::string> positional_args_{};
|
||||||
std::unordered_map<std::wstring, std::wstring> named_args_{};
|
std::unordered_map<lsr::string, lsr::string> named_args_{};
|
||||||
|
|
||||||
static parsed_raw_args_t parse();
|
static parsed_raw_args_t parse();
|
||||||
[[nodiscard]] std::wstring get_with_default(const std::wstring& key, const std::wstring& default_value) const {
|
[[nodiscard]] lsr::string get_with_default(const lsr::string& key, const lsr::string& default_value) const {
|
||||||
if (const auto& it = named_args_.find(key); it != named_args_.end()) {
|
if (const auto& it = named_args_.find(key); it != named_args_.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
5
third-party/aes/aes.h
vendored
5
third-party/aes/aes.h
vendored
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#if USE_WIN_CRYPTO
|
#if USE_WIN_CRYPTO
|
||||||
@ -37,7 +38,9 @@ size_t AES_CBC_decrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length);
|
|||||||
#if USE_WIN_CRYPTO
|
#if USE_WIN_CRYPTO
|
||||||
bool AES_cleanup(AES_ctx* ctx);
|
bool AES_cleanup(AES_ctx* ctx);
|
||||||
#else
|
#else
|
||||||
inline bool AES_cleanup(AES_ctx* ctx) {return true;}
|
inline bool AES_cleanup(AES_ctx* ctx) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace AES
|
} // namespace AES
|
||||||
|
Loading…
Reference in New Issue
Block a user