diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4879c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build/ +src/sqlite3/* +!src/sqlite3/README.md +src/ACBExtractor/* +!src/ACBExtractor/README.md diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..7b2696e --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.17134.0", + "compilerPath": "${env:VS_ROOT}/2017/Community/VC/Tools/MSVC/14.15.26726/bin/Hostx64/x64/cl.exe", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8ced04a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "debug-x64", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/x64/Debug/${config:targetName}.exe", + "args": ["-v", "10044600", "-o", "bgm"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build/x64/Debug/", + "environment": [], + "externalConsole": true, + "preLaunchTask": "debug-x64" + }, + { + "name": "debug-x86", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/x86/Debug/${config:targetName}.exe", + "args": ["-v", "10044600", "-o", "bgm"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "preLaunchTask": "debug-x86" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f5f876c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,58 @@ +{ + "targetName": "CGSSAssetsDownloader", + "sources": [ + "src/*.cpp", + "src/ACBExtractor/*.cpp", + "src/sqlite3/sqlite3.c" + ], + "files.associations": { + "cmath": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "memory": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocinfo": "cpp", + "xlocnum": "cpp", + "xmemory": "cpp", + "xmemory0": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xutility": "cpp", + "algorithm": "cpp", + "ctime": "cpp", + "locale": "cpp", + "regex": "cpp", + "xlocbuf": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xloctime": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8de2790 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,62 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "debug-x64", + "type": "shell", + "command": "${workspaceFolder}/vcbuild", + "args": [ + "x64", + "Debug", + "${workspaceFolder}", + "${config:targetName}", + "${config:sources}" + ], + "group": "build" + }, + { + "label": "release-x64", + "type": "shell", + "command": "${workspaceFolder}/vcbuild", + "args": [ + "x64", + "Release", + "${workspaceFolder}", + "${config:targetName}", + "${config:sources}" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "debug-x86", + "type": "shell", + "command": "${workspaceFolder}/vcbuild", + "args": [ + "x86", + "Debug", + "${workspaceFolder}", + "${config:targetName}", + "${config:sources}" + ], + "group": "build" + }, + { + "label": "release-x86", + "type": "shell", + "command": "${workspaceFolder}/vcbuild", + "args": [ + "x86", + "Release", + "${workspaceFolder}", + "${config:targetName}", + "${config:sources}" + ], + "group": "build" + } + ] +} \ No newline at end of file diff --git a/CGSSAssetsDownloader.cpp b/CGSSAssetsDownloader.cpp deleted file mode 100644 index 35c9f7d..0000000 --- a/CGSSAssetsDownloader.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include "CGSSAssetsDownloader.h" - -Downloader::Downloader(string v, string t) { - res_ver = v; - type = t; -} - -void Downloader::set_type(string t) { - type = t; -} - -void Downloader::check_manifest() { - fstream _file; - string fileName = "data\\manifest_" + res_ver + ".db"; - _file.open(fileName.c_str(), ios::in); - - if (!_file) { - printf("Start download manifest.\n"); - download_manifest(); - } - else { - printf("Manifest file exists.\n"); - } -} - -void Downloader::download_manifest() { - exec_sync("if not exist \"data\" md data"); - //exec_sync("tool\\wget\\wget -c -O data\\manifest_" + res_ver + " http://storage.game.starlight-stage.jp/dl/" + res_ver + "/manifests/Android_AHigh_SHigh"); - download("http://storage.game.starlight-stage.jp/dl/" + res_ver + "/manifests/Android_AHigh_SHigh", "./data/manifest_" + res_ver + "."); - - string lz4file = "data\\manifest_" + res_ver; - long size = get_file_size(lz4file.c_str()); - if (size < 1) { - printf("Failed.\n"); - exec_sync("del data\\manifest_" + res_ver + " /f /s /q"); - exit(0); - } - lz4dec(lz4file, "db"); - exec_sync("del data\\manifest_" + res_ver); - printf("Successfully download manifest.\n"); -} - -void Downloader::download_asset() { - sqlite3 *db; - char *zErrMsg = 0; - int rc; - char *sql; - const char* data = type.c_str(); - - string sqlfile = "data\\manifest_" + res_ver + ".db"; - rc = sqlite3_open(sqlfile.c_str(), &db); - if (rc) { - fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); - exit(0); - } - else { - fprintf(stderr, "Successfully open database.\n"); - } - - exec_sync("if not exist \"" + type + "\" md " + type); - - if (type == "bgm") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/b/'||hash AS url, REPLACE(REPLACE(name,'b/',''),'.acb','') AS filename FROM manifests WHERE name LIKE 'b/%acb'"; - if (Downloader::mp3 != 0) { - exec_sync("if not exist bgm\\mp3 md bgm\\mp3"); - } - else { - exec_sync("if not exist bgm\\wav md bgm\\wav"); - } - } - else if (type == "live") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/l/'||hash AS url, REPLACE(REPLACE(name,'l/',''),'.acb','') AS filename FROM manifests WHERE name LIKE 'l/%acb'"; - if (Downloader::mp3 != 0) { - exec_sync("if not exist live\\mp3 md live\\mp3"); - } - else { - exec_sync("if not exist live\\wav md live\\wav"); - } - } - else if (type == "card") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name LIKE 'card_bg_______.unity3d'"; - } - else if (type == "icon") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name LIKE 'card________m.unity3d'"; - } - else if (type == "score") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.bdb','') AS filename FROM manifests WHERE name LIKE 'musicscores%bdb'"; - } - read_database(db, sql, data, zErrMsg, rc, type); - - sqlite3_close(db); -} - -void Downloader::download_single(string file) { - sqlite3 *db; - string sql; - char *zErrMsg = 0; - int rc; - const char* data = file.c_str(); - - string sqlfile = "data\\manifest_" + res_ver + ".db"; - rc = sqlite3_open(sqlfile.c_str(), &db); - if (rc) { - fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); - exit(0); - } - else { - fprintf(stderr, "Successfully open database.\n"); - } - - string suffixStr = file.substr(file.find_last_of(".") + 1); - exec_sync("if not exist dl md dl"); - if (suffixStr == "acb") { - string acb_type = file.substr(0,1); - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/" + acb_type + "/'||hash AS url, REPLACE(REPLACE(name,'" + acb_type + "/',''),'.acb','') AS filename FROM manifests WHERE name='" + file + "'"; - } - else if (suffixStr == "unity3d") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name='" + file + "'"; - } - else if (suffixStr == "bdb") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.bdb','') AS filename FROM manifests WHERE name='" + file + "'"; - } - else if (suffixStr == "mdb") { - sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.mdb','') AS filename FROM manifests WHERE name='" + file + "'"; - } - else { - exec_sync("cls"); - printf("File name error.\n\n"); - return; - } - - rc = sqlite3_exec(db, sql.c_str(), exist, (void*)data, &zErrMsg); - if (Downloader::exists != 0) { - rc = sqlite3_exec(db, sql.c_str(), get_single, (void*)suffixStr.c_str(), &zErrMsg); - } - else { - exec_sync("cls"); - printf("%s not found.\n\n", file.c_str()); - } - is_db_ok(rc, zErrMsg); -} - -void show_introduction() { - printf("CGSSAssetsDownloader VERSION 1.7\n\n"); - - printf("Usage: \n"); - printf("CGSSAssetsDownloader <-v resource_version> [-a] [-u] [-mp3]\n"); - printf("CGSSAssetsDownloader <-v resource_version> [-o option or filename] [-u] [-mp3]\n"); - printf("CGSSAssetsDownloader file1 file2 file3 ...\n\n"); - - printf("Example: \n"); - printf("CGSSAssetsDownloader -v 10027700 -o -bgm -u\n"); - printf("CGSSAssetsDownloader -v 10028005 -o gachaselect_30145.unity3d\n"); - printf("CGSSAssetsDownloader -v 10031250 -a -u -mp3\n"); - printf("CGSSAssetsDownloader path\\to\\NoSuffixFile path\\to\\ACBFile.acb path\\to\\HCAFile.hca ...\n\n"); - - printf("Arguments: \n"); - printf("<-v resource_version> [NECESSARY] Set the resource version of game and download database.\n"); - printf("[-a] [OPTIONAL] Auto update bgm, live, card, icon, score assets.\n"); - printf("[-o bgm|live|card|icon|score|(filename)] [OPTIONAL] Read the detail below.\n"); - printf("[-u] [OPTIONAL] Copy files to \"dl\\\" folder.\n"); - printf("[-mp3] [OPTIONAL] WAV to MP3.Default: WAV.\n\n"); - - printf("If you don't know the , try to visit\nhttps://starlight.kirara.ca/api/v1/info\n\n"); - - printf("-o detail: \n"); - printf(" bgm \t all background music will be downloaded.\n"); - printf(" live \t all live music will be downloaded.\n"); - printf(" card \t all unity3d files that contain card background will be downloaded.\n"); - printf(" icon \t all unity3d files that contain 124x124 card icon will be downloaded.\n"); - printf(" score \t all bdb files that contain music score will be downloaded.\n\n"); - - printf("You can use \"DB Browser for SQLite\" open the manifest database file in data\\ to browse file names\n\n"); - - printf("You can also drag no suffix file (to .unity3d), .acb file or .hca file (to .wav, or to .mp3 if you use -mp3 argument with command line) into the exe\n\n"); - - printf("Developed by github@toyobayashi, tieba@y_Nyanko, weibo@TTPTs\n\n"); - - printf("Powered by:\n"); - printf("hcadec\n"); - printf("OpenCGSS/Deretore\n"); - printf("ffmpeg\n"); - printf("SQLite\n"); - printf("UnityLz4\n\n"); - - printf("The copyright of CGSS and its related content is held by BANDAI NAMCO Entertainment Inc.\n\n"); - - system("pause>nul"); -} - -int main(int argc, char* argv[]) { - exec_sync("echo off"); - exec_sync("cls"); - - if (argc == 1) { - show_introduction(); - return 0; - } - - int v = string_index_of(argv, "-v", argc); - int o = string_index_of(argv, "-o", argc); - int u = string_index_of(argv, "-u", argc); - int mp3 = string_index_of(argv, "-mp3", argc); - int a = string_index_of(argv, "-a", argc); - - string version; - string option; - - if (v != -1 && v + 1 < argc) { - - if (atoi(argv[v + 1]) > 10012760) { - version = argv[v + 1]; - } - else { - printf("[ERROR] Please try resource version later than 10012760"); - system("pause>nul"); - return 0; - } - - if (u != -1) { - Downloader::copy = 1; - exec_sync("if not exist dl md dl"); - } - - if (mp3 != -1) { - Downloader::mp3 = 1; - } - - if (a != -1) { - Downloader::auto_update = 1; - Downloader downloader(version, ""); - downloader.check_manifest(); - downloader.set_type("bgm"); - downloader.download_asset(); - downloader.set_type("live"); - downloader.download_asset(); - downloader.set_type("card"); - downloader.download_asset(); - downloader.set_type("icon"); - downloader.download_asset(); - downloader.set_type("score"); - downloader.download_asset(); - return 0; - } - - if (o == -1) { - Downloader downloader(version, ""); - downloader.check_manifest(); - } - else if (o != -1 && o + 1 < argc) { - option = argv[o + 1]; - if (option == "bgm" || option == "live" || option == "card" || option == "icon" || option == "score") { - Downloader downloader(version, option); - downloader.check_manifest(); - downloader.download_asset(); - } - else { - Downloader downloader(version, ""); - downloader.check_manifest(); - downloader.download_single(option); - } - } - - } - else { - if (mp3 != -1) { - Downloader::mp3 = 1; - } - - for (int i = 1; i < argc; i++) { - string arg = argv[i]; - - if (arg != "-mp3") { - - string root; - string fileName; - if (arg.find_last_of("\\") == string::npos) { - root = ""; - fileName = arg; - } - else { - root = arg.substr(0, arg.find_last_of("\\")); - fileName = arg.substr(arg.find_last_of("\\") + 1); - } - - if (fileName.find_last_of(".") == string::npos && get_file_size(fileName.c_str()) != 0) { - lz4dec(arg, "unity3d"); - } - else { - if (fileName.substr(fileName.find_last_of(".") + 1) == "hca") { - hcadec(arg); - } - else if (fileName.substr(fileName.find_last_of(".") + 1) == "acb") { - exec_sync(dir_name() + "\\tool\\AcbUnzip\\AcbUnzip.exe " + arg); - exec_sync("dir /a-d /b " + root + "\\_acb_" + fileName + "\\*.hca>" + root + "\\_acb_" + fileName + "\\hcafiles.txt"); - - string hcaFile[300]; - int i = 0; - ifstream infile; - infile.open(root + "\\_acb_" + fileName + "\\hcafiles.txt", ios::in); - while (!infile.eof()){ - getline(infile, hcaFile[i], '\n'); - i++; - } - infile.close(); - - for (int x = 0; x < i - 1; x++) { - hcadec(root + "\\_acb_" + fileName + "\\" + hcaFile[x]); - string name = hcaFile[x].substr(0, hcaFile[x].find_last_of(".")); - if (Downloader::mp3 != 0) { - exec_sync(dir_name() + "\\tool\\ffmpeg\\ffmpeg.exe -i " + root + "\\_acb_" + fileName + "\\" + name + ".wav " + root + "\\" + name + ".mp3 -v quiet"); - } - else { - exec_sync("move " + root + "\\_acb_" + fileName + "\\" + name + ".wav " + root + "\\"); - } - } - exec_sync("rd " + root + "\\_acb_" + fileName + " /s /q"); - } - } - } - } - } - - - return 0; -} diff --git a/CGSSAssetsDownloader.h b/CGSSAssetsDownloader.h deleted file mode 100644 index 38b182f..0000000 --- a/CGSSAssetsDownloader.h +++ /dev/null @@ -1,394 +0,0 @@ -#pragma once - -#include "stdlib.h" -#include "download.h" -#include "sqlite3.h" -#include "lz4.h" -#include "clHCA.h" -#include -#include -#include - -// #define WIN32_LEAN_AND_MEAN -using namespace std; - -class Downloader { -private: - string res_ver; - string type; -public: - static int current; - static int max; - static int exists; - static int copy; - static int mp3; - static int auto_update; - static string update_list; - - Downloader(string, string); - void check_manifest(); - void download_manifest(); - void download_asset(); - void download_single(string); - void set_type(string); -}; - -int Downloader::current = 0; -int Downloader::max = 0; -int Downloader::exists = 0; -int Downloader::copy = 0; -int Downloader::mp3 = 0; -int Downloader::auto_update = 0; -string Downloader::update_list = ""; - -int string_index_of(char* arr[], char* str, int length) { - for (int i = 0; i < length; i++) { - if (strcmp(arr[i], str) == 0) { - return i; - } - } - return -1; -} - -void exec_sync(string cmd) { - system(cmd.c_str()); -} - -void is_db_ok(int &r, char *&errmsg) { - if (r != SQLITE_OK) { - fprintf(stderr, "SQL error: %s\n", errmsg); - sqlite3_free(errmsg); - exit(0); - } -} - -string dir_name(){ - char exeFullPath[MAX_PATH]; - string strPath = ""; - - GetModuleFileNameA(NULL, exeFullPath, MAX_PATH); - strPath = (string)exeFullPath; - int pos = strPath.find_last_of('\\', strPath.length()); - return strPath.substr(0, pos); -} - -void hcadec(string hcafile) { - unsigned int count = 0; - char *filenameOut = NULL; - float volume = 1; - unsigned int ciphKey1 = 0xF27E3B22; - unsigned int ciphKey2 = 0x00003657; - int mode = 16; - int loop = 0; - - char path[MAX_PATH]; - if (!(filenameOut&&filenameOut[0])) { - strcpy_s(path, sizeof(path), hcafile.c_str()); - char *d1 = strrchr(path, '\\'); - char *d2 = strrchr(path, '/'); - char *e = strrchr(path, '.'); - if (e&&d1dl\\_acb_" + name + ".acb\\hcafiles.txt"); - - string hcaFile[300]; - int i = 0; - ifstream infile; - infile.open("dl\\_acb_" + name + ".acb\\hcafiles.txt", ios::in); - while (!infile.eof()) { - getline(infile, hcaFile[i], '\n'); - i++; - } - infile.close(); - - for (int x = 0; x < i - 1; x++) { - hcadec("dl\\_acb_" + name + ".acb\\" + hcaFile[x]); - string fn = hcaFile[x].substr(0, hcaFile[x].find_last_of(".")); - if (Downloader::mp3 != 0) { - exec_sync("tool\\ffmpeg\\ffmpeg.exe -i dl\\_acb_" + name + ".acb\\" + fn + ".wav dl\\" + fn + ".mp3 -v quiet"); - } - else { - exec_sync("move dl\\_acb_" + name + ".acb\\" + fn + ".wav dl\\"); - } - } - exec_sync("rd dl\\_acb_" + name + ".acb /s /q"); - exec_sync("del dl\\" + name + ".acb"); - /* hcadec("dl\\_acb_" + name + ".acb\\" + name + ".hca"); - exec_sync("move dl\\_acb_" + name + ".acb\\" + name + ".wav dl\\"); - exec_sync("rd dl\\_acb_" + name + ".acb /s /q"); - exec_sync("del dl\\" + name + ".acb"); - if (Downloader::mp3 != 0) { - exec_sync("tool\\ffmpeg\\ffmpeg.exe -i dl\\" + name + ".wav dl\\" + name + ".mp3 -v quiet"); - exec_sync("del dl\\" + name + ".wav"); - }*/ - } - else if (strcmp((char*)data, "unity3d") == 0) { - lz4dec("dl\\" + name, "unity3d"); - exec_sync("del dl\\" + name); - } - else if (strcmp((char*)data, "bdb") == 0) { - lz4dec("dl\\" + name, "bdb"); - exec_sync("del dl\\" + name); - } - else if (strcmp((char*)data, "mdb") == 0) { - lz4dec("dl\\" + name, "mdb"); - exec_sync("del dl\\" + name); - } - exec_sync("cls"); - printf("%s Completed.\n\n", name.c_str()); - } - else { - exec_sync("cls"); - printf("File exists.\n\n"); - } - _file.close(); - return 0; -} - -void read_database(sqlite3 *db, char *sql, const char* data, char *zErrMsg, int rc, string type) { - printf("Reading database...\n"); - // Downloader::update_list = ""; - rc = sqlite3_exec(db, sql, sum_number, (void*)data, &zErrMsg); - rc = sqlite3_exec(db, sql, get_asset, (void*)data, &zErrMsg); - if (rc != SQLITE_OK) { - fprintf(stderr, "SQL error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - exit(0); - } - else { - ofstream log_txt; - exec_sync("if not exist \"log\" md log"); - exec_sync("cls"); - printf("%d/%d Completed.\n\n", Downloader::current, Downloader::max); - string head = ""; - if (Downloader::auto_update == 0) { - log_txt.open("log\\" + type + ".txt"); - log_txt << Downloader::update_list; - log_txt.close(); - head = "=========== Update " + type + " ===========\n\n"; - } - else { - log_txt.open("log\\log.txt"); - log_txt << Downloader::update_list; - log_txt.close(); - head = "============= Update =============\n\n"; - } - printf(head.c_str()); - printf(Downloader::update_list.c_str()); - printf("\n====================================\n"); - } -} \ No newline at end of file diff --git a/README.md b/README.md index 9c25f5d..59dc53d 100644 --- a/README.md +++ b/README.md @@ -43,12 +43,10 @@ If you don't know the , try to visit https://starlight.kirara. ## Powered by -* [hcadec](https://github.com/alama/hcadec) -* [OpenCGSS/DereTore](https://github.com/OpenCGSS/DereTore) +* [HCADecoder](https://github.com/Nyagamon/HCADecoder) * [ffmpeg](http://ffmpeg.org/) * [SQLite](https://sqlite.org/) * [UnityLz4](https://github.com/subdiox/UnityLz4) - ## Copyright diff --git a/clHCA.h b/clHCA.h deleted file mode 100644 index 26c6891..0000000 --- a/clHCA.h +++ /dev/null @@ -1,191 +0,0 @@ -#pragma once - -//-------------------------------------------------- -// HCA(High Compression Audio)クラス -//-------------------------------------------------- -class clHCA { -public: - clHCA(unsigned int ciphKey1 = 0x30DBE1AB, unsigned int ciphKey2 = 0xCC554639); - - // HCAチェック - static bool CheckFile(void *data, unsigned int size); - - // チェックサム - static unsigned short CheckSum(void *data, int size, unsigned short sum = 0); - - // ヘッダ情報をコンソール出力 - bool PrintInfo(const char *filenameHCA); - - // 復号化 - bool Decrypt(const char *filenameHCA); - - // デコードしてWAVEファイルに保存 - bool DecodeToWavefile(const char *filenameHCA, const char *filenameWAV, float volume = 1, int mode = 16, int loop = 0); - bool DecodeToWavefileStream(void *fpHCA, const char *filenameWAV, float volume = 1, int mode = 16, int loop = 0); - - // エンコードしてHCAファイルに保存 - //bool EncodeFromWavefile(const char *filenameWAV,const char *filenameHCA,float volume=1); - //bool EncodeFromWavefileStream(void *fpWAV,const char *filenameHCA,float volume=1); - -private: - struct stHeader {//ファイル情報 (必須) - unsigned int hca; // 'HCA' - unsigned short version; // バージョン。v1.3とv2.0の存在を確認 - unsigned short dataOffset; // データオフセット - }; - struct stFormat {//フォーマット情報 (必須) - unsigned int fmt; // 'fmt' - unsigned int channelCount : 8; // チャンネル数 1〜16 - unsigned int samplingRate : 24; // サンプリングレート 1〜0x7FFFFF - unsigned int blockCount; // ブロック数 0以上 - unsigned short r01; // 先頭の無音部分(ブロック数*0x400+0x80) - unsigned short r02; // 末尾の無音部分?計算方法不明(0x226) - }; - struct stCompress {//圧縮情報 (圧縮情報かデコード情報のどちらか一つが必須) - unsigned int comp; // 'comp' - unsigned short blockSize; // ブロックサイズ(CBRのときに有効?) 8〜0xFFFF、0のときはVBR - unsigned char r01; // 不明(1) 0〜r02 v2.0現在1のみ対応 - unsigned char r02; // 不明(15) r01〜0x1F v2.0現在15のみ対応 - unsigned char r03; // 不明(1)(1) - unsigned char r04; // 不明(1)(0) - unsigned char r05; // 不明(0x80)(0x80) - unsigned char r06; // 不明(0x80)(0x20) - unsigned char r07; // 不明(0)(0x20) - unsigned char r08; // 不明(0)(8) - unsigned char reserve1; // 予約 - unsigned char reserve2; // 予約 - }; - struct stDecode {//デコード情報 (圧縮情報かデコード情報のどちらか一つが必須) - unsigned int dec; // 'dec' - unsigned short blockSize; // ブロックサイズ(CBRのときに有効?) 8〜0xFFFF、0のときはVBR - unsigned char r01; // 不明(1) 0〜r02 v2.0現在1のみ対応 - unsigned char r02; // 不明(15) r01〜0x1F v2.0現在15のみ対応 - unsigned char count1; // type0とtype1の数-1 - unsigned char count2; // type2の数-1 - unsigned char r03 : 4; // 不明(0) - unsigned char r04 : 4; // 不明(0) 0は1に修正される - unsigned char enableCount2; // count2を使うフラグ - }; - struct stVBR {//可変ビットレート情報 (廃止?) - unsigned int vbr; // 'vbr' - unsigned short r01; // 不明 0〜0x1FF - unsigned short r02; // 不明 - }; - struct stATH {//ATHテーブル情報 (v2.0から廃止?) - unsigned int ath; // 'ath' - unsigned short type; // テーブルの種類(0:全て0 1:テーブル1) - }; - struct stLoop {//ループ情報 - unsigned int loop; // 'loop' - unsigned int loopStart; // ループ開始ブロックインデックス 0〜loopEnd - unsigned int loopEnd; // ループ終了ブロックインデックス loopStart〜(stFormat::blockCount-1) - unsigned short r01; // 不明(0x80)ループフラグ?ループ回数? - unsigned short r02; // 不明(0x226) - }; - struct stCipher {//暗号テーブル情報 - unsigned int ciph; // 'ciph' - unsigned short type; // 暗号化の種類(0:暗号化なし 1:鍵なし暗号化 0x38:鍵あり暗号化) - }; - struct stRVA {//相対ボリューム調節情報 - unsigned int rva; // 'rva' - float volume; // ボリューム - }; - struct stComment {//コメント情報 - unsigned int comm; // 'comm' - unsigned char len; // コメントの長さ? - //char comment[]; - }; - struct stPadding {//パディング - unsigned int pad; // 'pad' - }; - unsigned int _version; - unsigned int _dataOffset; - unsigned int _channelCount; - unsigned int _samplingRate; - unsigned int _blockCount; - unsigned int _fmt_r01; - unsigned int _fmt_r02; - unsigned int _blockSize; - unsigned int _comp_r01; - unsigned int _comp_r02; - unsigned int _comp_r03; - unsigned int _comp_r04; - unsigned int _comp_r05; - unsigned int _comp_r06; - unsigned int _comp_r07; - unsigned int _comp_r08; - unsigned int _comp_r09; - unsigned int _vbr_r01; - unsigned int _vbr_r02; - unsigned int _ath_type; - unsigned int _loopStart; - unsigned int _loopEnd; - unsigned int _loop_r01; - unsigned int _loop_r02; - bool _loopFlg; - unsigned int _ciph_type; - unsigned int _ciph_key1; - unsigned int _ciph_key2; - float _rva_volume; - unsigned int _comm_len; - char *_comm_comment; - class clATH { - public: - clATH(); - bool Init(int type, unsigned int key); - unsigned char *GetTable(void); - private: - unsigned char _table[0x80]; - void Init0(void); - void Init1(unsigned int key); - }_ath; - class clCipher { - public: - clCipher(); - bool Init(int type, unsigned int key1, unsigned int key2); - void Mask(void *data, int size); - private: - unsigned char _table[0x100]; - void Init0(void); - void Init1(void); - void Init56(unsigned int key1, unsigned int key2); - void Init56_CreateTable(unsigned char *table, unsigned char key); - }_cipher; - class clData { - public: - clData(void *data, int size); - int CheckBit(int bitSize); - int GetBit(int bitSize); - void AddBit(int bitSize); - private: - unsigned char *_data; - int _size; - int _bit; - }; - struct stChannel { - float block[0x80]; - float base[0x80]; - char value[0x80]; - char scale[0x80]; - char value2[8]; - int type; - char *value3; - unsigned int count; - float wav1[0x80]; - float wav2[0x80]; - float wav3[0x80]; - float wave[8][0x80]; - void Decode1(clData *data, unsigned int a, int b, unsigned char *ath); - void Decode2(clData *data); - void Decode3(unsigned int a, unsigned int b, unsigned int c, unsigned int d); - void Decode4(int index, unsigned int a, unsigned int b, unsigned int c); - void Decode5(int index); - }_channel[0x10]; - bool Decode(void *data, unsigned int size, unsigned int address); - bool DecodeToWavefile_Decode(void *fp1, void *fp2, unsigned int address, unsigned int count, void *data, void *modeFunction); - static void DecodeToWavefile_DecodeModeFloat(float f, void *fp); - static void DecodeToWavefile_DecodeMode8bit(float f, void *fp); - static void DecodeToWavefile_DecodeMode16bit(float f, void *fp); - static void DecodeToWavefile_DecodeMode24bit(float f, void *fp); - static void DecodeToWavefile_DecodeMode32bit(float f, void *fp); -}; diff --git a/download.h b/download.h deleted file mode 100644 index 464a6ee..0000000 --- a/download.h +++ /dev/null @@ -1,232 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -using namespace std; -#pragma comment(lib, "ws2_32.lib") - -long get_file_size(const char* strFileName) { - struct _stat info; - _stat(strFileName, &info); - long size = info.st_size; - return size; -} - -string Int_to_String(int n) { - ostringstream stream; - stream << n; - return stream.str(); -} - -void progress(double local, double current, double max, double speed) { - double p_local = round(local / max * 50); - double p_current = round(current / max * 50); - double percent = (local + current) / max * 100; - printf("\r"); - printf("%.2lf / %.2lf MB ", (local + current) / 1024 / 1024, max / 1024 / 1024); - printf("["); - for (int i = 0; i < (int)p_local; i++) { - printf("+"); - } - for (int i = 0; i < (int)p_current/* - 1*/; i++) { - printf("="); - } - printf(">"); - for (int i = 0; i < (int)(50 - p_local - p_current); i++) { - printf(" "); - } - printf("] "); - printf("%5.2f%% ", percent); - printf("%7.2lf KB/s", speed / 1024); - printf(" \b\b\b"); -} - -void progress(double current, double max) { - double p_current = floor(current / max * 50); - double percent = current / max * 100; - printf("Completed: %.0lf / %.0lf ", current, max); - printf("["); - for (int i = 0; i < (int)p_current - 1; i++) { - printf("="); - } - printf(">"); - for (int i = 0; i < (int)(50 - p_current); i++) { - printf(" "); - } - printf("] "); - printf("%5.2f%% ", percent); - printf(" \b\b\b"); -} - -const int BuffSize = 1024; //ûС - -void download(string url, string path) { - // ȡ - size_t protocol = url.find("//") + 2; - string hostname = url.substr(protocol, url.substr(protocol).find_first_of('/')); - // ȡ· - string route = url.substr(protocol).substr(url.substr(protocol).find_first_of('/')); - - // ȡĿļСжĿļǷѴ - long size = get_file_size(path.c_str()); - - WSADATA WsaData; - if (WSAStartup(MAKEWORD(2, 2), &WsaData)) { - printf("Init failed.\n"); - return; - } - - SOCKET sockeId; - SOCKADDR_IN addr; - hostent *remoteHost; - remoteHost = gethostbyname(hostname.c_str()); - - if (-1 == (sockeId = socket(AF_INET, SOCK_STREAM, 0))) { - printf("Create socket failed.\n"); - return; - } - - addr.sin_addr.S_un.S_addr = *((unsigned long *)*remoteHost->h_addr_list); //inet_addr("104.116.243.18") - addr.sin_family = AF_INET; - addr.sin_port = htons(80); - - if (SOCKET_ERROR == connect(sockeId, (SOCKADDR *)&addr, sizeof(addr))) { - printf("Connect server failed.\n"); - closesocket(sockeId); - WSACleanup(); - return; - } - - // ʼ - char* pReqHead = new char[BuffSize]; - pReqHead[0] = '\0'; - // - strcat(pReqHead, "GET "); - strcat(pReqHead, route.c_str()); - strcat(pReqHead, " HTTP/1.1\r\n"); - - // ͷ - string hosthead = "Host: " + hostname + "\r\n"; - - strcat(pReqHead, hosthead.c_str()); - strcat(pReqHead, "Accept: */*\r\n"); - strcat(pReqHead, "Connection: Keep-Alive\r\n"); - strcat(pReqHead, "User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; Nexus 42 Build/XYZZ1Y)\r\n"); - strcat(pReqHead, "X-Unity-Version: 5.1.2f1\r\n"); - strcat(pReqHead, "Accept-Encoding: gzip\r\n"); - if (size != 0) { - // ȡصֽϵ - string range = "Range: bytes=" + Int_to_String(size) + "-\r\n"; - strcat(pReqHead, range.c_str()); - } - strcat(pReqHead, "\r\n"); - //printf(pReqHead); - - if (SOCKET_ERROR == send(sockeId, pReqHead, strlen(pReqHead), 0)) { - printf("Send data failed.\n"); - closesocket(sockeId); - WSACleanup(); - delete pReqHead; - return; - } - - delete pReqHead; - - FILE *fp; - fp = fopen(path.c_str(), "ab+"); - - if (NULL == fp) { - printf("Create file failed.\n"); - closesocket(sockeId); - WSACleanup(); - return; - } - - char* buff = (char*)malloc(BuffSize * sizeof(char)); - memset(buff, '\0', BuffSize); - int iRec = 1; // ֽ - bool bStart = false; //Ƿ귵ͷ - int chars = 0; // жϷͷĩβ - - //շͷ - string str; - while (!bStart) { - iRec = recv(sockeId, buff, 1, 0); //һֽһֽڵĽHTTPͷ - str += *buff; - if (iRec < 0) { - bStart = true; - } - switch (*buff) - { - case '\r': - break; - case '\n'://жHTTPͷǷ - if (chars == 0) { - bStart = true; - } - chars = 0; - break; - default: - chars++; - break; - } - } - - //printf("%s\n", str.c_str()); - - // ȡͷеContent-Length - int length = -1; - if (str.find("Content-Length: ") != str.npos) { - string contentlength1 = str.substr(str.find("Content-Length: ")); - string contentlength2 = contentlength1.substr(0, contentlength1.find_first_of('\r')); - string contentlength3 = contentlength2.substr(16); - length = atoi(contentlength3.c_str()); - } - else { - printf("Download faild.\n"); - return; - } - - if (size == length && str.find("Content-Range") == str.npos) { - printf("File exists.\n"); - } - else { - // ʼ - int sum = 0; - int speed = 0; - double start_time = clock(); - double end_time = 0; - int last_time = 0; - do { - iRec = recv(sockeId, buff, BuffSize, 0); - if (iRec < 0) { - break; - } - sum += iRec; - speed += iRec; - //printf("\r%d", sum); - int now = clock(); - if (now - last_time > 500) { - progress(size, sum, length + size, speed * 2); - last_time = now; - speed = 0; - } - - fwrite(buff, iRec, 1, fp); - if (sum == length) { - end_time = clock(); - progress(size, sum, length + size, (double)sum / ((end_time - start_time) / 1000)); - closesocket(sockeId); - WSACleanup(); - break; - } - } while (iRec > 0); - } - - fclose(fp); - free(buff); - printf("\n\n"); -} diff --git a/lz4.h b/lz4.h deleted file mode 100644 index 9a652f1..0000000 --- a/lz4.h +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -using namespace std; - -std::vector readFile(string filename) -{ - // open the file: - std::ifstream file(filename, std::ios::binary); - - // Stop eating new lines in binary mode!!! - file.unsetf(std::ios::skipws); - - // get its size: - std::streampos fileSize; - - file.seekg(0, std::ios::end); - fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - - // reserve capacity - std::vector vec; - vec.reserve(fileSize); - - // read the data: - vec.insert(vec.begin(), - std::istream_iterator(file), - std::istream_iterator()); - - return vec; -} - -// Binary Reader for vector -class BinaryReader { -private: - vector ary; - int curPos; -public: - BinaryReader(vector &array); - int readByte(); - int readShortLE(); - int readIntLE(); - vector& copyBytes(vector &dst, int &offset, int &size); - void seekAbs(int pos); - void seekRel(int diff); - int getPos(); -}; - -BinaryReader::BinaryReader(vector &array) { - ary = array; - curPos = 0; -} -int BinaryReader::readByte() { - curPos++; - return ary[curPos - 1]; -} -int BinaryReader::readShortLE() { - curPos += 2; - return ary[curPos - 2] + (ary[curPos - 1] << 8); -} -int BinaryReader::readIntLE() { - curPos += 4; - return ary[curPos - 4] + (ary[curPos - 3] << 8) + (ary[curPos - 2] << 16) + (ary[curPos - 1] << 24); -} -vector& BinaryReader::copyBytes(vector &dst, int &offset, int &size) { - curPos += size; - copy(ary.begin() + curPos - size, ary.begin() + curPos, dst.begin() + offset); - return dst; -} -void BinaryReader::seekAbs(int pos) { - curPos = pos; -} -void BinaryReader::seekRel(int diff) { - curPos += diff; -} -int BinaryReader::getPos() { - return curPos; -} - -// Unity LZ4 Decompressor for vector -class LZ4Decompressor { -public: - vector decompress(vector &array); - int readAdditionalSize(BinaryReader &reader); -}; - -vector LZ4Decompressor::decompress(vector &array) { - BinaryReader r(array); - vector retArray; - int dataSize = 0; - int decompressedSize = 0; - - int token = 0; - int sqSize = 0; - int matchSize = 0; - int litPos = 0; - int offset = 0; - int retCurPos = 0; - int endPos = 0; - - r.seekAbs(4); - decompressedSize = r.readIntLE(); - dataSize = r.readIntLE(); - endPos = dataSize + 16; - retArray = vector(decompressedSize); - - r.seekAbs(16); - - // Start reading sequences - while (true) { - // Read the LiteralSize and MatchSize - token = r.readByte(); - sqSize = token >> 4; - matchSize = (token & 0x0f) + 4; - if (sqSize == 15) { - sqSize += readAdditionalSize(r); - } - - // Copy the literal - retArray = r.copyBytes(retArray, retCurPos, sqSize); - retCurPos += sqSize; - - if (r.getPos() >= endPos - 1) { - break; - } - - // Read the offset - offset = r.readShortLE(); - - // Read the additional MatchSize - if (matchSize == 19) { - matchSize += readAdditionalSize(r); - } - - // Copy the match properly - if (matchSize > offset) { - int matchPos = retCurPos - offset; - while (true) { - copy(retArray.begin() + matchPos, retArray.begin() + matchPos + offset, retArray.begin() + retCurPos); - retCurPos += offset; - matchSize -= offset; - if (matchSize < offset) { - break; - } - } - } - copy(retArray.begin() + retCurPos - offset, retArray.begin() + retCurPos - offset + matchSize, retArray.begin() + retCurPos); - retCurPos += matchSize; - } - return retArray; -} - -int LZ4Decompressor::readAdditionalSize(BinaryReader &reader) { - uint8_t size = reader.readByte(); - if (size == 255) { - return size + readAdditionalSize(reader); - } - else { - return size; - } -} - -void lz4dec(string filePath, string type) { - LZ4Decompressor lz4; - vector vec = readFile(filePath); - vector outBuffer = lz4.decompress(vec); - - ofstream output(filePath + "." + type, ios::binary); - output.write((char *)&outBuffer[0], outBuffer.size()); -} diff --git a/src/ACBExtractor/README.md b/src/ACBExtractor/README.md new file mode 100644 index 0000000..16b4831 --- /dev/null +++ b/src/ACBExtractor/README.md @@ -0,0 +1,14 @@ +# ACBExtractor + +## Repo + +https://github.com/toyobayashi/ACBExtractor + +## Usage + +``` bash +ACBExtractor [...acbfile] +``` + +## License +* MIT diff --git a/src/CGSSAssetsDownloader.cpp b/src/CGSSAssetsDownloader.cpp new file mode 100644 index 0000000..83ef1ec --- /dev/null +++ b/src/CGSSAssetsDownloader.cpp @@ -0,0 +1,699 @@ + +#include +#include +#include +#include "./download.h" +#include "./lz4.h" +#include "./clHCA.h" +#include "./CGSSAssetsDownloader.h" +#include "./ACBExtractor/include/ACBExtractor.h" + +using namespace std; + +Downloader::Downloader(string v, string t) { + res_ver = v; + type = t; +} + +void Downloader::set_type(string t) { + type = t; +} + +void Downloader::check_manifest() { + fstream _file; + string fileName = "data\\manifest_" + res_ver + ".db"; + _file.open(fileName.c_str(), ios::in); + + if (!_file) { + printf("Start download manifest.\n"); + download_manifest(); + } + else { + printf("Manifest file exists.\n"); + } +} + +void Downloader::download_manifest() { + exec_sync("if not exist \"data\" md data"); + //exec_sync("tool\\wget\\wget -c -O data\\manifest_" + res_ver + " http://storage.game.starlight-stage.jp/dl/" + res_ver + "/manifests/Android_AHigh_SHigh"); + download("http://storage.game.starlight-stage.jp/dl/" + res_ver + "/manifests/Android_AHigh_SHigh", "./data/manifest_" + res_ver + "."); + + string lz4file = "data\\manifest_" + res_ver; + long size = get_file_size(lz4file.c_str()); + if (size < 1) { + printf("Failed.\n"); + exec_sync("del data\\manifest_" + res_ver + " /f /s /q"); + exit(0); + } + lz4dec(lz4file, "db"); + exec_sync("del data\\manifest_" + res_ver); + printf("Successfully download manifest.\n"); +} + +void Downloader::download_asset() { + sqlite3 *db; + char *zErrMsg = 0; + int rc; + const char* sql = ""; + const char* data = type.c_str(); + + string sqlfile = "data\\manifest_" + res_ver + ".db"; + rc = sqlite3_open(sqlfile.c_str(), &db); + if (rc) { + fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); + exit(0); + } + else { + fprintf(stderr, "Successfully open database.\n"); + } + + exec_sync("if not exist \"" + type + "\" md " + type); + + if (type == "bgm") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/b/'||hash AS url, REPLACE(REPLACE(name,'b/',''),'.acb','') AS filename FROM manifests WHERE name LIKE 'b/%acb'"; + if (Downloader::mp3 != 0) { + exec_sync("if not exist bgm\\mp3 md bgm\\mp3"); + } + else { + exec_sync("if not exist bgm\\wav md bgm\\wav"); + } + } + else if (type == "live") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/l/'||hash AS url, REPLACE(REPLACE(name,'l/',''),'.acb','') AS filename FROM manifests WHERE name LIKE 'l/%acb'"; + if (Downloader::mp3 != 0) { + exec_sync("if not exist live\\mp3 md live\\mp3"); + } + else { + exec_sync("if not exist live\\wav md live\\wav"); + } + } + else if (type == "card") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name LIKE 'card_bg_______.unity3d'"; + } + else if (type == "icon") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name LIKE 'card________m.unity3d'"; + } + else if (type == "score") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.bdb','') AS filename FROM manifests WHERE name LIKE 'musicscores%bdb'"; + } + read_database(db, sql, data, zErrMsg, rc, type); + + sqlite3_close(db); +} + +void Downloader::download_single(string file) { + sqlite3 *db; + string sql; + char *zErrMsg = 0; + int rc; + const char* data = file.c_str(); + + string sqlfile = "data\\manifest_" + res_ver + ".db"; + rc = sqlite3_open(sqlfile.c_str(), &db); + if (rc) { + fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); + exit(0); + } + else { + fprintf(stderr, "Successfully open database.\n"); + } + + string suffixStr = file.substr(file.find_last_of(".") + 1); + exec_sync("if not exist dl md dl"); + if (suffixStr == "acb") { + string acb_type = file.substr(0,1); + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/Sound/Common/" + acb_type + "/'||hash AS url, REPLACE(REPLACE(name,'" + acb_type + "/',''),'.acb','') AS filename FROM manifests WHERE name='" + file + "'"; + } + else if (suffixStr == "unity3d") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/High/AssetBundles/Android/'||hash AS url, REPLACE(name,'.unity3d','') AS filename FROM manifests WHERE name='" + file + "'"; + } + else if (suffixStr == "bdb") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.bdb','') AS filename FROM manifests WHERE name='" + file + "'"; + } + else if (suffixStr == "mdb") { + sql = "SELECT 'http://storage.game.starlight-stage.jp/dl/resources/Generic/'||hash AS url, REPLACE(name,'.mdb','') AS filename FROM manifests WHERE name='" + file + "'"; + } + else { + exec_sync("cls"); + printf("File name error.\n\n"); + return; + } + + rc = sqlite3_exec(db, sql.c_str(), exist, (void*)data, &zErrMsg); + if (Downloader::exists != 0) { + rc = sqlite3_exec(db, sql.c_str(), get_single, (void*)suffixStr.c_str(), &zErrMsg); + } + else { + exec_sync("cls"); + printf("%s not found.\n\n", file.c_str()); + } + is_db_ok(rc, zErrMsg); +} + +void show_introduction() { + printf("CGSSAssetsDownloader VERSION 1.8\n\n"); + + printf("Usage: \n"); + printf("CGSSAssetsDownloader <-v resource_version> [-a] [-u] [-mp3]\n"); + printf("CGSSAssetsDownloader <-v resource_version> [-o option or filename] [-u] [-mp3]\n"); + printf("CGSSAssetsDownloader file1 file2 file3 ...\n\n"); + + printf("Example: \n"); + printf("CGSSAssetsDownloader -v 10027700 -o -bgm -u\n"); + printf("CGSSAssetsDownloader -v 10028005 -o gachaselect_30145.unity3d\n"); + printf("CGSSAssetsDownloader -v 10031250 -a -u -mp3\n"); + printf("CGSSAssetsDownloader path\\to\\NoSuffixFile path\\to\\ACBFile.acb path\\to\\HCAFile.hca ...\n\n"); + + printf("Arguments: \n"); + printf("<-v resource_version> [NECESSARY] Set the resource version of game and download database.\n"); + printf("[-a] [OPTIONAL] Auto update bgm, live, card, icon, score assets.\n"); + printf("[-o bgm|live|card|icon|score|(filename)] [OPTIONAL] Read the detail below.\n"); + printf("[-u] [OPTIONAL] Copy files to \"dl\\\" folder.\n"); + printf("[-mp3] [OPTIONAL] WAV to MP3.Default: WAV.\n\n"); + + printf("If you don't know the , try to visit\nhttps://starlight.kirara.ca/api/v1/info\n\n"); + + printf("-o detail: \n"); + printf(" bgm \t all background music will be downloaded.\n"); + printf(" live \t all live music will be downloaded.\n"); + printf(" card \t all unity3d files that contain card background will be downloaded.\n"); + printf(" icon \t all unity3d files that contain 124x124 card icon will be downloaded.\n"); + printf(" score \t all bdb files that contain music score will be downloaded.\n\n"); + + printf("You can use \"DB Browser for SQLite\" open the manifest database file in data\\ to browse file names\n\n"); + + printf("You can also drag no suffix file (to .unity3d), .acb file or .hca file (to .wav, or to .mp3 if you use -mp3 argument with command line) into the exe\n\n"); + + printf("Developed by github@toyobayashi\n\n"); + + printf("Powered by:\n"); + printf("HCADecoder\n"); + printf("ffmpeg\n"); + printf("SQLite\n"); + printf("UnityLz4\n\n"); + + printf("The copyright of CGSS and its related content is held by BANDAI NAMCO Entertainment Inc.\n\n"); + + system("pause>nul"); +} + +bool extract_acb (string acbFile) { + try { + ACBExtractor extractor(acbFile); + bool result = extractor.extract(nullptr); + return result; + } catch (const char* err) { + printf("ACBExtractor Error: %s\n", err); + return false; + } +} + +int string_index_of (char* arr[], const char* str, int length) { + for (int i = 0; i < length; i++) { + if (strcmp(arr[i], str) == 0) { + return i; + } + } + return -1; +} + +void exec_sync (string cmd) { + system(cmd.c_str()); +} + +void is_db_ok (int &r, char *&errmsg) { + if (r != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", errmsg); + sqlite3_free(errmsg); + exit(0); + } +} + +string dir_name () { + char exeFullPath[MAX_PATH]; + string strPath = ""; + + GetModuleFileNameA(NULL, exeFullPath, MAX_PATH); + strPath = (string)exeFullPath; + size_t pos = strPath.find_last_of('\\', strPath.length()); + return strPath.substr(0, pos); +} + +void hcadec (string hcafile) { + unsigned int count = 0; + char *filenameOut = NULL; + float volume = 1; + unsigned int ciphKey1 = 0xF27E3B22; + unsigned int ciphKey2 = 0x00003657; + int mode = 16; + int loop = 0; + + char path[MAX_PATH]; + if (!(filenameOut&&filenameOut[0])) { + strcpy_s(path, sizeof(path), hcafile.c_str()); + char *d1 = strrchr(path, '\\'); + char *d2 = strrchr(path, '/'); + char *e = strrchr(path, '.'); + if (e&&d1dl\\_acb_" + name + ".acb\\hcafiles.txt"); + + string hcaFile[300]; + int i = 0; + ifstream infile; + infile.open("dl\\_acb_" + name + ".acb\\hcafiles.txt", ios::in); + while (!infile.eof()) { + getline(infile, hcaFile[i], '\n'); + i++; + } + infile.close(); + + for (int x = 0; x < i - 1; x++) { + hcadec("dl\\_acb_" + name + ".acb\\" + hcaFile[x]); + string fn = hcaFile[x].substr(0, hcaFile[x].find_last_of(".")); + if (Downloader::mp3 != 0) { + exec_sync("tool\\ffmpeg\\ffmpeg.exe -i dl\\_acb_" + name + ".acb\\" + fn + ".wav dl\\" + fn + ".mp3 -v quiet"); + } + else { + exec_sync("move dl\\_acb_" + name + ".acb\\" + fn + ".wav dl\\"); + } + } + exec_sync("rd dl\\_acb_" + name + ".acb /s /q"); + exec_sync("del dl\\" + name + ".acb"); + /* hcadec("dl\\_acb_" + name + ".acb\\" + name + ".hca"); + exec_sync("move dl\\_acb_" + name + ".acb\\" + name + ".wav dl\\"); + exec_sync("rd dl\\_acb_" + name + ".acb /s /q"); + exec_sync("del dl\\" + name + ".acb"); + if (Downloader::mp3 != 0) { + exec_sync("tool\\ffmpeg\\ffmpeg.exe -i dl\\" + name + ".wav dl\\" + name + ".mp3 -v quiet"); + exec_sync("del dl\\" + name + ".wav"); + }*/ + } + else if (strcmp((char*)data, "unity3d") == 0) { + lz4dec("dl\\" + name, "unity3d"); + exec_sync("del dl\\" + name); + } + else if (strcmp((char*)data, "bdb") == 0) { + lz4dec("dl\\" + name, "bdb"); + exec_sync("del dl\\" + name); + } + else if (strcmp((char*)data, "mdb") == 0) { + lz4dec("dl\\" + name, "mdb"); + exec_sync("del dl\\" + name); + } + exec_sync("cls"); + printf("%s Completed.\n\n", name.c_str()); + } + else { + exec_sync("cls"); + printf("File exists.\n\n"); + } + _file.close(); + return 0; +} + +void read_database(sqlite3 *db, const char *sql, const char* data, char *zErrMsg, int rc, string type) { + printf("Reading database...\n"); + // Downloader::update_list = ""; + rc = sqlite3_exec(db, sql, sum_number, (void*)data, &zErrMsg); + rc = sqlite3_exec(db, sql, get_asset, (void*)data, &zErrMsg); + if (rc != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + exit(0); + } + else { + ofstream log_txt; + exec_sync("if not exist \"log\" md log"); + exec_sync("cls"); + printf("%d/%d Completed.\n\n", Downloader::current, Downloader::max); + string head = ""; + if (Downloader::auto_update == 0) { + log_txt.open("log\\" + type + ".txt"); + log_txt << Downloader::update_list; + log_txt.close(); + head = "=========== Update " + type + " ===========\n\n"; + } + else { + log_txt.open("log\\log.txt"); + log_txt << Downloader::update_list; + log_txt.close(); + head = "============= Update =============\n\n"; + } + printf(head.c_str()); + printf(Downloader::update_list.c_str()); + printf("\n====================================\n"); + } +} + +int main(int argc, char* argv[]) { + exec_sync("echo off"); + exec_sync("cls"); + + if (argc == 1) { + show_introduction(); + return 0; + } + + int v = string_index_of(argv, "-v", argc); + int o = string_index_of(argv, "-o", argc); + int u = string_index_of(argv, "-u", argc); + int mp3 = string_index_of(argv, "-mp3", argc); + int a = string_index_of(argv, "-a", argc); + + string version; + string option; + + if (v != -1 && v + 1 < argc) { + + if (atoi(argv[v + 1]) > 10012760) { + version = argv[v + 1]; + } + else { + printf("[ERROR] Please try resource version later than 10012760"); + system("pause>nul"); + return 0; + } + + if (u != -1) { + Downloader::copy = 1; + exec_sync("if not exist dl md dl"); + } + + if (mp3 != -1) { + Downloader::mp3 = 1; + } + + if (a != -1) { + Downloader::auto_update = 1; + Downloader downloader(version, ""); + downloader.check_manifest(); + downloader.set_type("bgm"); + downloader.download_asset(); + downloader.set_type("live"); + downloader.download_asset(); + downloader.set_type("card"); + downloader.download_asset(); + downloader.set_type("icon"); + downloader.download_asset(); + downloader.set_type("score"); + downloader.download_asset(); + return 0; + } + + if (o == -1) { + Downloader downloader(version, ""); + downloader.check_manifest(); + } + else if (o != -1 && o + 1 < argc) { + option = argv[o + 1]; + if (option == "bgm" || option == "live" || option == "card" || option == "icon" || option == "score") { + Downloader downloader(version, option); + downloader.check_manifest(); + downloader.download_asset(); + } + else { + Downloader downloader(version, ""); + downloader.check_manifest(); + downloader.download_single(option); + } + } + + } + else { + if (mp3 != -1) { + Downloader::mp3 = 1; + } + + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + + if (arg != "-mp3") { + + string root; + string fileName; + if (arg.find_last_of("\\") == string::npos) { + root = ""; + fileName = arg; + } + else { + root = arg.substr(0, arg.find_last_of("\\")); + fileName = arg.substr(arg.find_last_of("\\") + 1); + } + + if (fileName.find_last_of(".") == string::npos && get_file_size(fileName.c_str()) != 0) { + lz4dec(arg, "unity3d"); + } + else { + if (fileName.substr(fileName.find_last_of(".") + 1) == "hca") { + hcadec(arg); + } + else if (fileName.substr(fileName.find_last_of(".") + 1) == "acb") { + extract_acb(arg); + exec_sync("dir /a-d /b " + root + "\\_acb_" + fileName + "\\*.hca>" + root + "\\_acb_" + fileName + "\\hcafiles.txt"); + + string hcaFile[300]; + int i = 0; + ifstream infile; + infile.open(root + "\\_acb_" + fileName + "\\hcafiles.txt", ios::in); + while (!infile.eof()){ + getline(infile, hcaFile[i], '\n'); + i++; + } + infile.close(); + + for (int x = 0; x < i - 1; x++) { + hcadec(root + "\\_acb_" + fileName + "\\" + hcaFile[x]); + string name = hcaFile[x].substr(0, hcaFile[x].find_last_of(".")); + if (Downloader::mp3 != 0) { + exec_sync(dir_name() + "\\tool\\ffmpeg\\ffmpeg.exe -i " + root + "\\_acb_" + fileName + "\\" + name + ".wav " + root + "\\" + name + ".mp3 -v quiet"); + } + else { + exec_sync("move " + root + "\\_acb_" + fileName + "\\" + name + ".wav " + root + "\\"); + } + } + exec_sync("rd " + root + "\\_acb_" + fileName + " /s /q"); + } + } + } + } + } + + return 0; +} diff --git a/src/CGSSAssetsDownloader.h b/src/CGSSAssetsDownloader.h new file mode 100644 index 0000000..df478c7 --- /dev/null +++ b/src/CGSSAssetsDownloader.h @@ -0,0 +1,57 @@ +#ifndef __CGSSASSETSDOWNLOADER_H__ +#define __CGSSASSETSDOWNLOADER_H__ + +#include "./sqlite3/sqlite3.h" + +class Downloader { +private: + std::string res_ver; + std::string type; +public: + static int current; + static int max; + static int exists; + static int copy; + static int mp3; + static int auto_update; + static std::string update_list; + + Downloader(std::string, std::string); + void check_manifest(); + void download_manifest(); + void download_asset(); + void download_single(std::string); + void set_type(std::string); +}; + +int Downloader::current = 0; +int Downloader::max = 0; +int Downloader::exists = 0; +int Downloader::copy = 0; +int Downloader::mp3 = 0; +int Downloader::auto_update = 0; +std::string Downloader::update_list = ""; + +bool extract_acb (std::string acbFile); + +int string_index_of (char* arr[], const char* str, int length); + +void exec_sync (std::string); + +void is_db_ok (int &r, char *&errmsg); + +std::string dir_name (); + +void hcadec (std::string hcafile); + +int exist(void *data, int argc, char **argv, char **azColName); + +int sum_number(void *data, int argc, char **argv, char **azColName); + +int get_asset(void *data, int argc, char **argv, char **azColName); + +int get_single(void *data, int argc, char **argv, char **azColName); + +void read_database(sqlite3 *db, const char *sql, const char* data, char *zErrMsg, int rc, std::string type); + +#endif // !__CGSSASSETSDOWNLOADER_H__ diff --git a/clHCA.cpp b/src/clHCA.cpp similarity index 81% rename from clHCA.cpp rename to src/clHCA.cpp index 5f650c6..031b395 100644 --- a/clHCA.cpp +++ b/src/clHCA.cpp @@ -1,1476 +1,1398 @@ - -//-------------------------------------------------- -// インクルード -//-------------------------------------------------- -#include "clHCA.h" -#include -#include - -//-------------------------------------------------- -// インライン関数 -//-------------------------------------------------- -inline short bswap(short v) { short r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline unsigned short bswap(unsigned short v) { unsigned short r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline int bswap(int v) { int r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline unsigned int bswap(unsigned int v) { unsigned int r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline long long bswap(long long v) { long long r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline unsigned long long bswap(unsigned long long v) { unsigned long long r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } -inline float bswap(float v) { unsigned int i = bswap(*(unsigned int *)&v); return *(float *)&i; } -inline unsigned int ceil2(unsigned int a, unsigned int b) { return (b>0) ? (a / b + ((a%b) ? 1 : 0)) : 0; } - -//-------------------------------------------------- -// コンストラクタ -//-------------------------------------------------- -clHCA::clHCA(unsigned int ciphKey1, unsigned int ciphKey2) : - _ciph_key1(ciphKey1), _ciph_key2(ciphKey2), _ath(), _cipher() {} - -//-------------------------------------------------- -// HCAチェック -//-------------------------------------------------- -bool clHCA::CheckFile(void *data, unsigned int size) { - return (data&&size >= 4 && (*(unsigned int *)data & 0x7F7F7F7F) == 0x00414348); -} - -//-------------------------------------------------- -// チェックサム -//-------------------------------------------------- -unsigned short clHCA::CheckSum(void *data, int size, unsigned short sum) { - static unsigned short v[] = { - 0x0000,0x8005,0x800F,0x000A,0x801B,0x001E,0x0014,0x8011,0x8033,0x0036,0x003C,0x8039,0x0028,0x802D,0x8027,0x0022, - 0x8063,0x0066,0x006C,0x8069,0x0078,0x807D,0x8077,0x0072,0x0050,0x8055,0x805F,0x005A,0x804B,0x004E,0x0044,0x8041, - 0x80C3,0x00C6,0x00CC,0x80C9,0x00D8,0x80DD,0x80D7,0x00D2,0x00F0,0x80F5,0x80FF,0x00FA,0x80EB,0x00EE,0x00E4,0x80E1, - 0x00A0,0x80A5,0x80AF,0x00AA,0x80BB,0x00BE,0x00B4,0x80B1,0x8093,0x0096,0x009C,0x8099,0x0088,0x808D,0x8087,0x0082, - 0x8183,0x0186,0x018C,0x8189,0x0198,0x819D,0x8197,0x0192,0x01B0,0x81B5,0x81BF,0x01BA,0x81AB,0x01AE,0x01A4,0x81A1, - 0x01E0,0x81E5,0x81EF,0x01EA,0x81FB,0x01FE,0x01F4,0x81F1,0x81D3,0x01D6,0x01DC,0x81D9,0x01C8,0x81CD,0x81C7,0x01C2, - 0x0140,0x8145,0x814F,0x014A,0x815B,0x015E,0x0154,0x8151,0x8173,0x0176,0x017C,0x8179,0x0168,0x816D,0x8167,0x0162, - 0x8123,0x0126,0x012C,0x8129,0x0138,0x813D,0x8137,0x0132,0x0110,0x8115,0x811F,0x011A,0x810B,0x010E,0x0104,0x8101, - 0x8303,0x0306,0x030C,0x8309,0x0318,0x831D,0x8317,0x0312,0x0330,0x8335,0x833F,0x033A,0x832B,0x032E,0x0324,0x8321, - 0x0360,0x8365,0x836F,0x036A,0x837B,0x037E,0x0374,0x8371,0x8353,0x0356,0x035C,0x8359,0x0348,0x834D,0x8347,0x0342, - 0x03C0,0x83C5,0x83CF,0x03CA,0x83DB,0x03DE,0x03D4,0x83D1,0x83F3,0x03F6,0x03FC,0x83F9,0x03E8,0x83ED,0x83E7,0x03E2, - 0x83A3,0x03A6,0x03AC,0x83A9,0x03B8,0x83BD,0x83B7,0x03B2,0x0390,0x8395,0x839F,0x039A,0x838B,0x038E,0x0384,0x8381, - 0x0280,0x8285,0x828F,0x028A,0x829B,0x029E,0x0294,0x8291,0x82B3,0x02B6,0x02BC,0x82B9,0x02A8,0x82AD,0x82A7,0x02A2, - 0x82E3,0x02E6,0x02EC,0x82E9,0x02F8,0x82FD,0x82F7,0x02F2,0x02D0,0x82D5,0x82DF,0x02DA,0x82CB,0x02CE,0x02C4,0x82C1, - 0x8243,0x0246,0x024C,0x8249,0x0258,0x825D,0x8257,0x0252,0x0270,0x8275,0x827F,0x027A,0x826B,0x026E,0x0264,0x8261, - 0x0220,0x8225,0x822F,0x022A,0x823B,0x023E,0x0234,0x8231,0x8213,0x0216,0x021C,0x8219,0x0208,0x820D,0x8207,0x0202, - }; - for (unsigned char *s = (unsigned char *)data, *e = s + size; s> 8) ^ *s]; - return sum; -} - -//-------------------------------------------------- -// ヘッダ情報をコンソール出力 -//-------------------------------------------------- -bool clHCA::PrintInfo(const char *filenameHCA) { - - // チェック - if (!(filenameHCA))return false; - - // HCAファイルを開く - FILE *fp; - if (fopen_s(&fp, filenameHCA, "rb")) { - printf("Error: ファイルが開けませんでした。\n"); - return false; - } - - // ヘッダチェック - stHeader header; - memset(&header, 0, sizeof(header)); - fread(&header, sizeof(header), 1, fp); - if (!CheckFile(&header, sizeof(header))) { - printf("Error: HCAファイルではありません。\n"); - fclose(fp); return false; - } - - // ヘッダ解析 - header.dataOffset = bswap(header.dataOffset); - unsigned char *data = new unsigned char[header.dataOffset]; - if (!data) { - printf("Error: メモリ不足です。\n"); - fclose(fp); return false; - } - fseek(fp, 0, SEEK_SET); - fread(data, header.dataOffset, 1, fp); - - unsigned char *s = (unsigned char *)data; - unsigned int size = header.dataOffset; - - // サイズチェック - if (sizeversion); - _dataOffset = bswap(hca->dataOffset); - printf("コーデック: HCA\n"); - printf("バージョン: %d.%d\n", _version >> 8, _version & 0xFF); - //if(size<_dataOffset)return false; - if (CheckSum(hca, _dataOffset))printf("※ ヘッダが破損しています。改変してる場合もこの警告が出ます。\n"); - } - else { - printf("※ HCAチャンクがありません。再生に必要な情報です。\n"); - } - - // fmt - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { - stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); - _channelCount = fmt->channelCount; - _samplingRate = bswap(fmt->samplingRate << 8); - _blockCount = bswap(fmt->blockCount); - _fmt_r01 = bswap(fmt->r01); - _fmt_r02 = bswap(fmt->r02); - switch (_channelCount) { - case 1:printf("チャンネル数: モノラル (1チャンネル)\n"); break; - case 2:printf("チャンネル数: ステレオ (2チャンネル)\n"); break; - default:printf("チャンネル数: %dチャンネル\n", _channelCount); break; - } - if (!(_channelCount >= 1 && _channelCount <= 16)) { - printf("※ チャンネル数の範囲は1〜16です。\n"); - } - printf("サンプリングレート: %dHz\n", _samplingRate); - if (!(_samplingRate >= 1 && _samplingRate <= 0x7FFFFF)) { - printf("※ サンプリングレートの範囲は1〜8388607(0x7FFFFF)です。\n"); - } - printf("ブロック数: %d\n", _blockCount); - printf("先頭無音ブロック数: %d\n", (_fmt_r01 - 0x80) / 0x400); - printf("末尾無音サンプル数?: %d\n", _fmt_r02); - } - else { - printf("※ fmtチャンクがありません。再生に必要な情報です。\n"); - } - - // comp - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { - stCompress *comp = (stCompress *)s; s += sizeof(stCompress); - _blockSize = bswap(comp->blockSize); - _comp_r01 = comp->r01; - _comp_r02 = comp->r02; - _comp_r03 = comp->r03; - _comp_r04 = comp->r04; - _comp_r05 = comp->r05; - _comp_r06 = comp->r06; - _comp_r07 = comp->r07; - _comp_r08 = comp->r08; - printf("ビットレート: CBR (固定ビットレート)\n"); - printf("ブロックサイズ: 0x%04X\n", _blockSize); - if (!(_blockSize >= 8 && _blockSize <= 0xFFFF)) { - printf("※ ブロックサイズの範囲は8〜65535(0xFFFF)です。v1.3では0でVBRになるようになってましたが、v2.0から廃止されたようです。\n"); - } - printf("comp1: %d\n", _comp_r01); - printf("comp2: %d\n", _comp_r02); - if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F)) { - printf("※ comp1とcomp2の範囲は0<=comp1<=comp2<=31です。v2.0現在、comp1は1、comp2は15で固定されています。\n"); - } - printf("comp3: %d\n", _comp_r03); - if (!_comp_r03) { - printf("※ comp3は1以上の値です。\n"); - } - printf("comp4: %d\n", _comp_r04); - printf("comp5: %d\n", _comp_r05); - printf("comp6: %d\n", _comp_r06); - printf("comp7: %d\n", _comp_r07); - printf("comp8: %d\n", _comp_r08); - } - - // dec - else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { - stDecode *dec = (stDecode *)s; s += sizeof(stDecode); - _blockSize = bswap(dec->blockSize); - _comp_r01 = dec->r01; - _comp_r02 = dec->r02; - _comp_r03 = dec->r04; - _comp_r04 = dec->r03; - _comp_r05 = dec->count1 + 1; - _comp_r06 = ((dec->enableCount2) ? dec->count2 : dec->count1) + 1; - _comp_r07 = _comp_r05 - _comp_r06; - _comp_r08 = 0; - printf("ビットレート: CBR (固定ビットレート)\n"); - printf("ブロックサイズ: 0x%04X\n", _blockSize); - if (!(_blockSize >= 8 && _blockSize <= 0xFFFF)) { - printf("※ ブロックサイズの範囲は8〜65535(0xFFFF)です。v1.3では0でVBRになるようになってましたが、v2.0から廃止されたようです。\n"); - } - printf("dec1: %d\n", _comp_r01); - printf("dec2: %d\n", _comp_r02); - if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F)) { - printf("※ dec1とdec2の範囲は0<=dec1<=dec2<=31です。v2.0現在、dec1は1、dec2は15で固定されています。\n"); - } - printf("dec3: %d\n", _comp_r03); - if (!_comp_r03) { - printf("※ dec3は再生時に1以上の値に修正されます。\n"); - } - printf("dec4: %d\n", _comp_r04); - printf("dec5: %d\n", _comp_r05); - printf("dec6: %d\n", _comp_r06); - printf("dec7: %d\n", _comp_r07); - } - else { - printf("※ compチャンクまたはdecチャンクがありません。再生に必要な情報です。\n"); - } - - // vbr - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { - stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); - _vbr_r01 = bswap(vbr->r01); - _vbr_r02 = bswap(vbr->r02); - printf("ビットレート: VBR (可変ビットレート) ※v2.0で廃止されています。\n"); - if (!(_blockSize == 0)) { - printf("※ compまたはdecチャンクですでにCBRが指定されています。\n"); - } - printf("vbr1: %d\n", _vbr_r01); - if (!(_vbr_r01 >= 0 && _vbr_r01 <= 0x1FF)) { - printf("※ vbr1の範囲は0〜511(0x1FF)です。\n"); - } - printf("vbr2: %d\n", _vbr_r02); - } - else { - _vbr_r01 = 0; - _vbr_r02 = 0; - } - - // ath - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { - stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); - _ath_type = ath->type; - printf("ATHタイプ:%d ※v2.0から廃止されています。\n", _ath_type); - } - else { - if (_version<0x200) { - printf("ATHタイプ:1 ※v2.0から廃止されています。\n"); - } - } - - // loop - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { - stLoop *loop = (stLoop *)s; s += sizeof(stLoop); - _loopStart = bswap(loop->loopStart); - _loopEnd = bswap(loop->loopEnd); - _loop_r01 = bswap(loop->r01); - _loop_r02 = bswap(loop->r02); - printf("ループ開始ブロック: %d\n", _loopStart); - printf("ループ終了ブロック: %d\n", _loopEnd); - if (!(_loopStart >= 0 && _loopStart <= _loopEnd&&_loopEnd<_blockCount)) { - printf("※ ループ開始ブロックとループ終了ブロックの範囲は、0<=ループ開始ブロック<=ループ終了ブロック<ブロック数 です。\n"); - } - printf("ループ情報1: %d\n", _loop_r01); - printf("ループ情報2: %d\n", _loop_r02); - } - - // ciph - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { - stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); - _ciph_type = bswap(ciph->type); - switch (_ciph_type) { - case 0:printf("暗号化タイプ: なし\n"); break; - case 1:printf("暗号化タイプ: 鍵無し暗号化\n"); break; - case 0x38:printf("暗号化タイプ: 鍵有り暗号化 ※正しい鍵を使わないと出力波形がおかしくなります。\n"); break; - default:printf("暗号化タイプ: %d\n", _ciph_type); break; - } - if (!(_ciph_type == 0 || _ciph_type == 1 || _ciph_type == 0x38)) { - printf("※ この暗号化タイプは、v2.0現在再生できません。\n"); - } - } - - // rva - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { - stRVA *rva = (stRVA *)s; s += sizeof(stRVA); - _rva_volume = bswap(rva->volume); - printf("相対ボリューム調節: %g倍\n", _rva_volume); - } - - // comm - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { - stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); - _comm_len = comm->len; - _comm_comment = (char *)s; - printf("コメント: %s\n", _comm_comment); - } - - delete[] data; - - // 閉じる - fclose(fp); - - return true; -} - -//-------------------------------------------------- -// 復号化 -//-------------------------------------------------- -bool clHCA::Decrypt(const char *filenameHCA) { - - // チェック - if (!(filenameHCA))return false; - - // HCAファイルを開く - FILE *fp; - if (fopen_s(&fp, filenameHCA, "r+b"))return false; - - // ヘッダチェック - stHeader header; - memset(&header, 0, sizeof(header)); - fread(&header, sizeof(header), 1, fp); - if (!CheckFile(&header, sizeof(header))) { fclose(fp); return false; } - - // ヘッダ解析 - header.dataOffset = bswap(header.dataOffset); - unsigned char *data = new unsigned char[header.dataOffset]; - if (!data) { fclose(fp); return false; } - fseek(fp, 0, SEEK_SET); - fread(data, header.dataOffset, 1, fp); - - unsigned char *s = (unsigned char *)data; - unsigned int size = header.dataOffset; - - // サイズチェック - if (sizehca &= 0x7F7F7F7F; - _version = bswap(hca->version); - _dataOffset = bswap(hca->dataOffset); - } - else { - delete[] data; fclose(fp); return false; - } - - // fmt - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { - stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); - fmt->fmt &= 0x7F7F7F7F; - _samplingRate = bswap(fmt->samplingRate << 8); - _blockCount = bswap(fmt->blockCount); - } - else { - delete[] data; fclose(fp); return false; - } - - // comp - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { - stCompress *comp = (stCompress *)s; s += sizeof(stCompress); - comp->comp &= 0x7F7F7F7F; - _blockSize = bswap(comp->blockSize); - } - - // dec - else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { - stDecode *dec = (stDecode *)s; s += sizeof(stDecode); - dec->dec &= 0x7F7F7F7F; - _blockSize = bswap(dec->blockSize); - } - else { - delete[] data; fclose(fp); return false; - } - - // vbr - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { - stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); - vbr->vbr &= 0x7F7F7F7F; - } - - // ath - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { - stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); - ath->ath &= 0x7F7F7F7F; - _ath_type = bswap(ath->type); - //ath->type=0; - } - else { - if (_version<0x200)_ath_type = 1; - } - - // loop - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { - stLoop *loop = (stLoop *)s; s += sizeof(stLoop); - loop->loop &= 0x7F7F7F7F; - } - - // ciph - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { - stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); - ciph->ciph &= 0x7F7F7F7F; - _ciph_type = bswap(ciph->type); - ciph->type = 0; - } - - // rva - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { - stRVA *rva = (stRVA *)s; s += sizeof(stRVA); - rva->rva &= 0x7F7F7F7F; - } - - // comm - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { - stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); - comm->comm &= 0x7F7F7F7F; - s += comm->len; - } - - // pad - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00646170) { - stPadding *pad = (stPadding *)s; s += sizeof(stPadding); - pad->pad &= 0x7F7F7F7F; - } - - // 初期化 - if (!_ath.Init(_ath_type, _samplingRate)) { delete[] data; fclose(fp); return false; } - if (!_cipher.Init(_ciph_type, _ciph_key1, _ciph_key2)) { delete[] data; fclose(fp); return false; } - unsigned char *data2 = new unsigned char[_blockSize]; - if (!data2) { delete[] data; fclose(fp); return false; } - - // ヘッダを書き込み - *(unsigned short *)&data[size - 2] = bswap(CheckSum(data, size - 2)); - fseek(fp, 0, SEEK_SET); - fwrite(data, size, 1, fp); - delete[] data; - - // ブロックデータを復号化 - if (_ciph_type != 0) { - for (unsigned int i = 0, a = size; i<_blockCount; i++, a += _blockSize) { - fseek(fp, a, SEEK_SET); - fread(data2, _blockSize, 1, fp); - _cipher.Mask(data2, _blockSize); - *(unsigned short *)&data2[_blockSize - 2] = bswap(CheckSum(data2, _blockSize - 2)); - fseek(fp, a, SEEK_SET); - fwrite(data2, _blockSize, 1, fp); - } - } - delete[] data2; - - // 閉じる - fclose(fp); - - return true; -} - -//-------------------------------------------------- -// デコードしてWAVEファイルに保存 -//-------------------------------------------------- -bool clHCA::DecodeToWavefile(const char *filenameHCA, const char *filenameWAV, float volume, int mode, int loop) { - - // チェック - if (!(filenameHCA))return false; - - // HCAファイルを開く - FILE *fp; - if (fopen_s(&fp, filenameHCA, "rb"))return false; - - // 保存 - if (!DecodeToWavefileStream(fp, filenameWAV, volume, mode, loop)) { fclose(fp); return false; } - - // 閉じる - fclose(fp); - - return true; -} -bool clHCA::DecodeToWavefileStream(void *fpHCA, const char *filenameWAV, float volume, int mode, int loop) { - - // チェック - if (!(fpHCA&&filenameWAV && (mode == 0 || mode == 8 || mode == 16 || mode == 24 || mode == 32) && loop >= 0))return false; - - // - FILE *fp1 = (FILE *)fpHCA; - unsigned int address = ftell(fp1); - - // ヘッダチェック - stHeader header; - memset(&header, 0, sizeof(header)); - fread(&header, sizeof(header), 1, fp1); - if (!CheckFile(&header, sizeof(header)))return false; - - // ヘッダ解析 - header.dataOffset = bswap(header.dataOffset); - unsigned char *data1 = new unsigned char[header.dataOffset]; - if (!data1) { fclose(fp1); return false; } - fseek(fp1, address, SEEK_SET); - fread(data1, header.dataOffset, 1, fp1); - if (!Decode(data1, header.dataOffset, 0)) { delete[] data1; return false; } - - // WAVEファイルを開く - FILE *fp2; - if (fopen_s(&fp2, filenameWAV, "wb")) { delete[] data1; return false; } - - // WAVEヘッダを書き込み - struct stWAVEHeader { - char riff[4]; - unsigned int riffSize; - char wave[4]; - char fmt[4]; - unsigned int fmtSize; - unsigned short fmtType; - unsigned short fmtChannelCount; - unsigned int fmtSamplingRate; - unsigned int fmtSamplesPerSec; - unsigned short fmtSamplingSize; - unsigned short fmtBitCount; - }wavRiff = { 'R','I','F','F',0,'W','A','V','E','f','m','t',' ',0x10,0,0,0,0,0,0 }; - struct stWAVEsmpl { - char smpl[4]; - unsigned int smplSize; - unsigned int manufacturer; - unsigned int product; - unsigned int samplePeriod; - unsigned int MIDIUnityNote; - unsigned int MIDIPitchFraction; - unsigned int SMPTEFormat; - unsigned int SMPTEOffset; - unsigned int sampleLoops; - unsigned int samplerData; - unsigned int loop_Identifier; - unsigned int loop_Type; - unsigned int loop_Start; - unsigned int loop_End; - unsigned int loop_Fraction; - unsigned int loop_PlayCount; - }wavSmpl = { 's','m','p','l',0x3C,0,0,0,0x3C,0,0,0,1,0x18,0,0,0,0,0,0 }; - struct stWAVEnote { - char note[4]; - unsigned int noteSize; - unsigned int dwName; - }wavNote = { 'n','o','t','e',0,0 }; - struct stWAVEdata { - char data[4]; - unsigned int dataSize; - }wavData = { 'd','a','t','a',0 }; - wavRiff.fmtType = (mode>0) ? 1 : 3; - wavRiff.fmtChannelCount = _channelCount; - wavRiff.fmtBitCount = (mode>0) ? mode : 32; - wavRiff.fmtSamplingRate = _samplingRate; - wavRiff.fmtSamplingSize = wavRiff.fmtBitCount / 8 * wavRiff.fmtChannelCount; - wavRiff.fmtSamplesPerSec = wavRiff.fmtSamplingRate*wavRiff.fmtSamplingSize; - if (_loopFlg) { - wavSmpl.samplePeriod = (unsigned int)(1 / (double)wavRiff.fmtSamplingRate * 1000000000); - wavSmpl.loop_Start = _loopStart * 0x80 * 8 * wavRiff.fmtSamplingSize; - wavSmpl.loop_End = _loopEnd * 0x80 * 8 * wavRiff.fmtSamplingSize; - wavSmpl.loop_PlayCount = (_loop_r01 == 0x80) ? 0 : _loop_r01; - } - else if (loop) { - wavSmpl.loop_Start = 0; - wavSmpl.loop_End = _blockCount * 0x80 * 8 * wavRiff.fmtSamplingSize; - _loopStart = 0; - _loopEnd = _blockCount; - } - if (_comm_comment) { - wavNote.noteSize = 4 + _comm_len + 1; - if (wavNote.noteSize & 3)wavNote.noteSize += 4 - (wavNote.noteSize & 3); - } - wavData.dataSize = _blockCount * 0x80 * 8 * wavRiff.fmtSamplingSize + (wavSmpl.loop_End - wavSmpl.loop_Start)*loop; - wavRiff.riffSize = 0x1C + ((_loopFlg && !loop) ? sizeof(wavSmpl) : 0) + (_comm_comment ? 8 + wavNote.noteSize : 0) + sizeof(wavData) + wavData.dataSize; - fwrite(&wavRiff, sizeof(wavRiff), 1, fp2); - if (_loopFlg && !loop)fwrite(&wavSmpl, sizeof(wavSmpl), 1, fp2); - if (_comm_comment) { - int address = ftell(fp2); - fwrite(&wavNote, sizeof(wavNote), 1, fp2); - fputs(_comm_comment, fp2); - fseek(fp2, address + 8 + wavNote.noteSize, SEEK_SET); - } - fwrite(&wavData, sizeof(wavData), 1, fp2); - - // 相対ボリュームを調節 - _rva_volume *= volume; - - // デコード - void *modeFunction = DecodeToWavefile_DecodeMode16bit; - switch (mode) { - case 0:modeFunction = DecodeToWavefile_DecodeModeFloat; break; - case 8:modeFunction = DecodeToWavefile_DecodeMode8bit; break; - case 16:modeFunction = DecodeToWavefile_DecodeMode16bit; break; - case 24:modeFunction = DecodeToWavefile_DecodeMode24bit; break; - case 32:modeFunction = DecodeToWavefile_DecodeMode32bit; break; - } - unsigned char *data2 = new unsigned char[_blockSize]; - if (!data2) { delete[] data1; fclose(fp2); return false; } - if (!loop) { - if (!DecodeToWavefile_Decode(fp1, fp2, address + _dataOffset, _blockCount, data2, modeFunction)) { delete[] data2; delete[] data1; fclose(fp2); return false; } - } - else { - unsigned int loopBlockOffset = _dataOffset + _loopStart*_blockSize; - unsigned int loopBlockCount = _loopEnd - _loopStart; - if (!DecodeToWavefile_Decode(fp1, fp2, address + _dataOffset, _loopEnd, data2, modeFunction)) { delete[] data2; delete[] data1; fclose(fp2); return false; } - for (int i = 1; i1) { f = 1; } - else if (f<-1) { f = -1; } - ((void(*)(float, void *))modeFunction)(f, fp2); - } - } - } - } - return true; -} -void clHCA::DecodeToWavefile_DecodeModeFloat(float f, void *fp) { fwrite(&f, sizeof(f), 1, (FILE *)fp); } -void clHCA::DecodeToWavefile_DecodeMode8bit(float f, void *fp) { int v = (int)(f * 0x7F) + 0x80; fwrite(&v, 1, 1, (FILE *)fp); } -void clHCA::DecodeToWavefile_DecodeMode16bit(float f, void *fp) { int v = (int)(f * 0x7FFF); fwrite(&v, 2, 1, (FILE *)fp); } -void clHCA::DecodeToWavefile_DecodeMode24bit(float f, void *fp) { int v = (int)(f * 0x7FFFFF); fwrite(&v, 3, 1, (FILE *)fp); } -void clHCA::DecodeToWavefile_DecodeMode32bit(float f, void *fp) { int v = (int)(f * 0x7FFFFFFF); fwrite(&v, 4, 1, (FILE *)fp); } - -//-------------------------------------------------- -// エンコードしてHCAファイルに保存 -//-------------------------------------------------- -/*bool clHCA::EncodeFromWavefile(const char *filenameWAV,const char *filenameHCA,float volume){ - -// チェック -if(!(filenameWAV))return false; - -// WAVファイルを開く -FILE *fp; -if(fopen_s(&fp,filenameWAV,"rb"))return false; - -// 保存 -if(!EncodeFromWavefileStream(fp,filenameHCA,volume)){fclose(fp);return false;} - -// 閉じる -fclose(fp); - -return true; -} -bool clHCA::EncodeFromWavefileStream(void *fpWAV,const char *filenameHCA,float volume){ - -// チェック -if(!(fpWAV&&filenameHCA))return false; - -// -FILE *fp1=(FILE *)fpWAV; -unsigned int address=ftell(fp1); - -// ヘッダチェック -struct stWAVEHeader{ -unsigned int riff; -unsigned int riffSize; -unsigned int wave; -unsigned int fmt; -unsigned int fmtSize; -unsigned short fmtType; -unsigned short fmtChannelCount; -unsigned int fmtSamplingRate; -unsigned int fmtSamplesPerSec; -unsigned short fmtSamplingSize; -unsigned short fmtBitCount; -}header; -memset(&header,0,sizeof(header)); -fread(&header,sizeof(header),1,fp1); -if(!(header.riff==0x46464952&&header.wave==0x45564157&&header.fmt==0x20746D66&&(header.fmtType==1||header.fmtType==3)))return false; - -//@@@@@@@@@@@@@@@@@@@@@@@ - -return true; -}*/ - -//-------------------------------------------------- -// ATH -//-------------------------------------------------- -clHCA::clATH::clATH() { Init0(); } -bool clHCA::clATH::Init(int type, unsigned int key) { - switch (type) { - case 0:Init0(); break; - case 1:Init1(key); break; - default:return false; - } - return true; -} -unsigned char *clHCA::clATH::GetTable(void) { - return _table; -} -void clHCA::clATH::Init0(void) { - memset(_table, 0, sizeof(_table)); -} -void clHCA::clATH::Init1(unsigned int key) { - static unsigned char list[] = { - 0x78,0x5F,0x56,0x51,0x4E,0x4C,0x4B,0x49,0x48,0x48,0x47,0x46,0x46,0x45,0x45,0x45, - 0x44,0x44,0x44,0x44,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x42,0x42,0x42,0x42,0x42, - 0x42,0x42,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x40,0x40,0x40,0x40, - 0x40,0x40,0x40,0x40,0x40,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, - 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, - 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, - 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C, - 0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3F, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x3F,0x3F,0x3F,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x41,0x41,0x41,0x41, - 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, - 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x43,0x43,0x43, - 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x44,0x44, - 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x45,0x45,0x45,0x45, - 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, - 0x46,0x46,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x48,0x48,0x48,0x48, - 0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4A,0x4A,0x4A,0x4A, - 0x4A,0x4A,0x4A,0x4A,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4C,0x4C,0x4C,0x4C,0x4C, - 0x4C,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4E,0x4E,0x4E,0x4E,0x4E,0x4E,0x4F,0x4F,0x4F, - 0x4F,0x4F,0x4F,0x50,0x50,0x50,0x50,0x50,0x51,0x51,0x51,0x51,0x51,0x52,0x52,0x52, - 0x52,0x52,0x53,0x53,0x53,0x53,0x54,0x54,0x54,0x54,0x54,0x55,0x55,0x55,0x55,0x56, - 0x56,0x56,0x56,0x57,0x57,0x57,0x57,0x57,0x58,0x58,0x58,0x59,0x59,0x59,0x59,0x5A, - 0x5A,0x5A,0x5A,0x5B,0x5B,0x5B,0x5B,0x5C,0x5C,0x5C,0x5D,0x5D,0x5D,0x5D,0x5E,0x5E, - 0x5E,0x5F,0x5F,0x5F,0x60,0x60,0x60,0x61,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, - 0x63,0x64,0x64,0x64,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69, - 0x69,0x6A,0x6A,0x6A,0x6B,0x6B,0x6B,0x6C,0x6C,0x6D,0x6D,0x6D,0x6E,0x6E,0x6F,0x6F, - 0x70,0x70,0x70,0x71,0x71,0x72,0x72,0x73,0x73,0x73,0x74,0x74,0x75,0x75,0x76,0x76, - 0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7D,0x7D,0x7E, - 0x7E,0x7F,0x7F,0x80,0x80,0x81,0x81,0x82,0x83,0x83,0x84,0x84,0x85,0x85,0x86,0x86, - 0x87,0x88,0x88,0x89,0x89,0x8A,0x8A,0x8B,0x8C,0x8C,0x8D,0x8D,0x8E,0x8F,0x8F,0x90, - 0x90,0x91,0x92,0x92,0x93,0x94,0x94,0x95,0x95,0x96,0x97,0x97,0x98,0x99,0x99,0x9A, - 0x9B,0x9B,0x9C,0x9D,0x9D,0x9E,0x9F,0xA0,0xA0,0xA1,0xA2,0xA2,0xA3,0xA4,0xA5,0xA5, - 0xA6,0xA7,0xA7,0xA8,0xA9,0xAA,0xAA,0xAB,0xAC,0xAD,0xAE,0xAE,0xAF,0xB0,0xB1,0xB1, - 0xB2,0xB3,0xB4,0xB5,0xB6,0xB6,0xB7,0xB8,0xB9,0xBA,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, - 0xC0,0xC1,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCD, - 0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD, - 0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xED,0xEE, - 0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFF,0xFF, - }; - for (unsigned int i = 0, v = 0; i<0x80; i++, v += key) { - unsigned int index = v >> 13; - if (index >= 0x28E) { - memset(&_table[i], 0xFF, 0x80 - i); - break; - } - _table[i] = list[index]; - } -} - -//-------------------------------------------------- -// 暗号化テーブル -//-------------------------------------------------- -clHCA::clCipher::clCipher() { Init0(); } -bool clHCA::clCipher::Init(int type, unsigned int key1, unsigned int key2) { - if (!(key1 | key2))type = 0; - switch (type) { - case 0:Init0(); break; - case 1:Init1(); break; - case 56:Init56(key1, key2); break; - default:return false; - } - return true; -} -void clHCA::clCipher::Mask(void *data, int size) { - for (unsigned char *d = (unsigned char *)data; size>0; d++, size--)*d = _table[*d]; -} -void clHCA::clCipher::Init0(void) { - for (int i = 0; i<0x100; i++)_table[i] = i; -} -void clHCA::clCipher::Init1(void) { - for (int i = 1, v = 0; i<0xFF; i++) { - v = (v * 13 + 11) & 0xFF; - if (v == 0 || v == 0xFF)v = (v * 13 + 11) & 0xFF; - _table[i] = v; - } - _table[0] = 0; - _table[0xFF] = 0xFF; -} -void clHCA::clCipher::Init56(unsigned int key1, unsigned int key2) { - - // テーブル1を生成 - unsigned char t1[8]; - if (!key1)key2--; - key1--; - for (int i = 0; i<7; i++) { - t1[i] = key1; - key1 = (key1 >> 8) | (key2 << 24); - key2 >>= 8; - } - - // テーブル2 - unsigned char t2[0x10] = { - t1[1],t1[1] ^ t1[6], - t1[2] ^ t1[3],t1[2], - t1[2] ^ t1[1],t1[3] ^ t1[4], - t1[3],t1[3] ^ t1[2], - t1[4] ^ t1[5],t1[4], - t1[4] ^ t1[3],t1[5] ^ t1[6], - t1[5],t1[5] ^ t1[4], - t1[6] ^ t1[1],t1[6], - }; - - // テーブル3 - unsigned char t3[0x100], t31[0x10], t32[0x10], *t = t3; - Init56_CreateTable(t31, t1[0]); - for (int i = 0; i<0x10; i++) { - Init56_CreateTable(t32, t2[i]); - unsigned char v = t31[i] << 4; - for (int j = 0; j<0x10; j++) { - *(t++) = v | t32[j]; - } - } - - // CIPHテーブル - t = &_table[1]; - for (int i = 0, v = 0; i<0x100; i++) { - v = (v + 0x11) & 0xFF; - unsigned char a = t3[v]; - if (a != 0 && a != 0xFF)*(t++) = a; - } - _table[0] = 0; - _table[0xFF] = 0xFF; - -} -void clHCA::clCipher::Init56_CreateTable(unsigned char *r, unsigned char key) { - int mul = ((key & 1) << 3) | 5; - int add = (key & 0xE) | 1; - key >>= 4; - for (int i = 0; i<0x10; i++) { - key = (key*mul + add) & 0xF; - *(r++) = key; - } -} - -//-------------------------------------------------- -// データ -//-------------------------------------------------- -clHCA::clData::clData(void *data, int size) :_data((unsigned char *)data), _size(size * 8 - 16), _bit(0) {} -int clHCA::clData::CheckBit(int bitSize) { - int v = 0; - if (_bit + bitSize <= _size) { - static int mask[] = { 0xFFFFFF,0x7FFFFF,0x3FFFFF,0x1FFFFF,0x0FFFFF,0x07FFFF,0x03FFFF,0x01FFFF }; - unsigned char *data = &_data[_bit >> 3]; - v = data[0]; v = (v << 8) | data[1]; v = (v << 8) | data[2]; - v &= mask[_bit & 7]; - v >>= 24 - (_bit & 7) - bitSize; - } - return v; -} -int clHCA::clData::GetBit(int bitSize) { - int v = CheckBit(bitSize); - _bit += bitSize; - return v; -} -void clHCA::clData::AddBit(int bitSize) { - _bit += bitSize; -} - -//-------------------------------------------------- -// デコード -//-------------------------------------------------- -bool clHCA::Decode(void *data, unsigned int size, unsigned int address) { - - // チェック - if (!(data))return false; - - // ヘッダ - if (address == 0) { - unsigned char *s = (unsigned char *)data; - - // サイズチェック - if (sizeversion); - _dataOffset = bswap(hca->dataOffset); - //if(!(_version<=0x200&&_version>0x101))return false; // バージョンチェック(無効) - if (size<_dataOffset)return false; - //if(CheckSum(hca,_dataOffset))return false; // ヘッダの破損チェック(ヘッダ改変を有効にするため破損チェック無効) - } - else { - return false; - } - - // fmt - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { - stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); - _channelCount = fmt->channelCount; - _samplingRate = bswap(fmt->samplingRate << 8); - _blockCount = bswap(fmt->blockCount); - _fmt_r01 = bswap(fmt->r01); - _fmt_r02 = bswap(fmt->r02); - if (!(_channelCount >= 1 && _channelCount <= 16))return false; - if (!(_samplingRate >= 1 && _samplingRate <= 0x7FFFFF))return false; - } - else { - return false; - } - - // comp - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { - stCompress *comp = (stCompress *)s; s += sizeof(stCompress); - _blockSize = bswap(comp->blockSize); - _comp_r01 = comp->r01; - _comp_r02 = comp->r02; - _comp_r03 = comp->r03; - _comp_r04 = comp->r04; - _comp_r05 = comp->r05; - _comp_r06 = comp->r06; - _comp_r07 = comp->r07; - _comp_r08 = comp->r08; - if (!((_blockSize >= 8 && _blockSize <= 0xFFFF) || (_blockSize == 0)))return false; - if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F))return false; - } - - // dec - else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { - stDecode *dec = (stDecode *)s; s += sizeof(stDecode); - _blockSize = bswap(dec->blockSize); - _comp_r01 = dec->r01; - _comp_r02 = dec->r02; - _comp_r03 = dec->r04; - _comp_r04 = dec->r03; - _comp_r05 = dec->count1 + 1; - _comp_r06 = ((dec->enableCount2) ? dec->count2 : dec->count1) + 1; - _comp_r07 = _comp_r05 - _comp_r06; - _comp_r08 = 0; - if (!((_blockSize >= 8 && _blockSize <= 0xFFFF) || (_blockSize == 0)))return false; - if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F))return false; - if (!_comp_r03)_comp_r03 = 1; - } - else { - return false; - } - - // vbr - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { - stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); - _vbr_r01 = bswap(vbr->r01); - _vbr_r02 = bswap(vbr->r02); - if (!(_blockSize == 0 && _vbr_r01 >= 0 && _vbr_r01 <= 0x1FF))return false; - } - else { - _vbr_r01 = 0; - _vbr_r02 = 0; - } - - // ath - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { - stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); - _ath_type = ath->type; - } - else { - _ath_type = (_version<0x200) ? 1 : 0;//v1.3ではデフォルト値が1になってたが、v2.0からATHテーブルが廃止されてるみたいなので0に - } - - // loop - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { - stLoop *loop = (stLoop *)s; s += sizeof(stLoop); - _loopStart = bswap(loop->loopStart); - _loopEnd = bswap(loop->loopEnd); - _loop_r01 = bswap(loop->r01); - _loop_r02 = bswap(loop->r02); - _loopFlg = true; - if (!(_loopStart >= 0 && _loopStart <= _loopEnd&&_loopEnd<_blockCount))return false; - } - else { - _loopStart = 0; - _loopEnd = 0; - _loop_r01 = 0; - _loop_r02 = 0x400; - _loopFlg = false; - } - - // ciph - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { - stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); - _ciph_type = bswap(ciph->type); - if (!(_ciph_type == 0 || _ciph_type == 1 || _ciph_type == 0x38))return false; - } - else { - _ciph_type = 0; - } - - // rva - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { - stRVA *rva = (stRVA *)s; s += sizeof(stRVA); - _rva_volume = bswap(rva->volume); - } - else { - _rva_volume = 1; - } - - // comm - if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { - stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); - _comm_len = comm->len; - _comm_comment = (char *)s; - } - else { - _comm_len = 0; - _comm_comment = NULL; - } - - // 初期化 - if (!_ath.Init(_ath_type, _samplingRate))return false; - if (!_cipher.Init(_ciph_type, _ciph_key1, _ciph_key2))return false; - - // 値チェック(ヘッダの改変ミスによるエラーを回避するため) - if (!_comp_r03)_comp_r03 = 1;//0での除算を防ぐため - - // デコード準備 - memset(_channel, 0, sizeof(_channel)); - if (!(_comp_r01 == 1 && _comp_r02 == 15))return false; - _comp_r09 = ceil2(_comp_r05 - (_comp_r06 + _comp_r07), _comp_r08); - char r[0x10]; memset(r, 0, sizeof(r)); - unsigned int b = _channelCount / _comp_r03; - if (_comp_r07&&b>1) { - char *c = r; - for (unsigned int i = 0; i<_comp_r03; i++, c += b) { - switch (b) { - case 2:c[0] = 1; c[1] = 2; break; - case 3:c[0] = 1; c[1] = 2; break; - case 4:c[0] = 1; c[1] = 2; if (_comp_r04 == 0) { c[2] = 1; c[3] = 2; }break; - case 5:c[0] = 1; c[1] = 2; if (_comp_r04 <= 2) { c[3] = 1; c[4] = 2; }break; - case 6:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; break; - case 7:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; break; - case 8:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; c[6] = 1; c[7] = 2; break; - } - } - } - for (unsigned int i = 0; i<_channelCount; i++) { - _channel[i].type = r[i]; - _channel[i].value3 = &_channel[i].value[_comp_r06 + _comp_r07]; - _channel[i].count = _comp_r06 + ((r[i] != 2) ? _comp_r07 : 0); - } - - } - - // ブロックデータ - else if (address >= _dataOffset) { - if (size<_blockSize)return false; - if (CheckSum(data, _blockSize))return false; - _cipher.Mask(data, _blockSize); - clData d(data, _blockSize); - int magic = d.GetBit(16);//0xFFFF固定 - if (magic == 0xFFFF) { - int a = (d.GetBit(9) << 8) - d.GetBit(7); - for (unsigned int i = 0; i<_channelCount; i++)_channel[i].Decode1(&d, _comp_r09, a, _ath.GetTable()); - for (int i = 0; i<8; i++) { - for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode2(&d); - for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode3(_comp_r09, _comp_r08, _comp_r07 + _comp_r06, _comp_r05); - for (unsigned int j = 0; j<_channelCount - 1; j++)_channel[j].Decode4(i, _comp_r05 - _comp_r06, _comp_r06, _comp_r07); - for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode5(i); - } - } - } - - return true; -} - -//-------------------------------------------------- -// デコード第一段階 -// ベースデータの読み込み -//-------------------------------------------------- -void clHCA::stChannel::Decode1(clData *data, unsigned int a, int b, unsigned char *ath) { - static unsigned char scalelist[] = { - // v2.0 - 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, - 0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, - 0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, - 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, - 0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, - 0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, - 0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // v1.3 - //0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, - //0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, - //0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, - //0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, - //0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, - //0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, - //0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, - //0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - }; - static unsigned int valueInt[] = { - 0x342A8D26,0x34633F89,0x3497657D,0x34C9B9BE,0x35066491,0x353311C4,0x356E9910,0x359EF532, - 0x35D3CCF1,0x360D1ADF,0x363C034A,0x367A83B3,0x36A6E595,0x36DE60F5,0x371426FF,0x3745672A, - 0x37838359,0x37AF3B79,0x37E97C38,0x381B8D3A,0x384F4319,0x388A14D5,0x38B7FBF0,0x38F5257D, - 0x3923520F,0x39599D16,0x3990FA4D,0x39C12C4D,0x3A00B1ED,0x3A2B7A3A,0x3A647B6D,0x3A9837F0, - 0x3ACAD226,0x3B071F62,0x3B340AAF,0x3B6FE4BA,0x3B9FD228,0x3BD4F35B,0x3C0DDF04,0x3C3D08A4, - 0x3C7BDFED,0x3CA7CD94,0x3CDF9613,0x3D14F4F0,0x3D467991,0x3D843A29,0x3DB02F0E,0x3DEAC0C7, - 0x3E1C6573,0x3E506334,0x3E8AD4C6,0x3EB8FBAF,0x3EF67A41,0x3F243516,0x3F5ACB94,0x3F91C3D3, - 0x3FC238D2,0x400164D2,0x402C6897,0x4065B907,0x40990B88,0x40CBEC15,0x4107DB35,0x413504F3, - }; - static unsigned int scaleInt[] = { - 0x00000000,0x3F2AAAAB,0x3ECCCCCD,0x3E924925,0x3E638E39,0x3E3A2E8C,0x3E1D89D9,0x3E088889, - 0x3D842108,0x3D020821,0x3C810204,0x3C008081,0x3B804020,0x3B002008,0x3A801002,0x3A000801, - }; - static float *valueFloat = (float *)valueInt; - static float *scaleFloat = (float *)scaleInt; - int v = data->GetBit(3); - if (v >= 6) { - for (unsigned int i = 0; iGetBit(6); - } - else if (v) { - int v1 = data->GetBit(6), v2 = (1 << v) - 1, v3 = v2 >> 1, v4; - value[0] = v1; - for (unsigned int i = 1; iGetBit(v); - if (v4 != v2) { v1 += v4 - v3; } - else { v1 = data->GetBit(6); } - value[i] = v1; - } - } - else { - memset(value, 0, 0x80); - } - if (type == 2) { - v = data->CheckBit(4); value2[0] = v; - if (v<15)for (int i = 0; i<8; i++)value2[i] = data->GetBit(4); - } - else { - for (unsigned int i = 0; iGetBit(6); - } - for (unsigned int i = 0; i> 8) - ((v * 5) >> 1) + 1; - if (v<0)v = 15; - else if (v >= 0x39)v = 1; - else v = scalelist[v]; - } - scale[i] = v; - } - memset(&scale[count], 0, 0x80 - count); - for (unsigned int i = 0; iGetBit(bitSize); - if (s<8) { - v += s << 4; - data->AddBit(list2[v] - bitSize); - f = list3[v]; - } - else { - v = (1 - ((v & 1) << 1))*(v >> 1); - if (!v)data->AddBit(-1); - f = (float)v; - } - block[i] = base[i] * f; - } - memset(&block[count], 0, sizeof(float)*(0x80 - count)); -} - -//-------------------------------------------------- -// デコード第三段階 -// ブロックデータ修正その1 ※v2.0から追加 -//-------------------------------------------------- -void clHCA::stChannel::Decode3(unsigned int a, unsigned int b, unsigned int c, unsigned int d) { - if (type != 2 && b) { - static unsigned int listInt[2][0x40] = { - { - 0x00000000,0x00000000,0x32A0B051,0x32D61B5E,0x330EA43A,0x333E0F68,0x337D3E0C,0x33A8B6D5, - 0x33E0CCDF,0x3415C3FF,0x34478D75,0x3484F1F6,0x34B123F6,0x34EC0719,0x351D3EDA,0x355184DF, - 0x358B95C2,0x35B9FCD2,0x35F7D0DF,0x36251958,0x365BFBB8,0x36928E72,0x36C346CD,0x370218AF, - 0x372D583F,0x3766F85B,0x3799E046,0x37CD078C,0x3808980F,0x38360094,0x38728177,0x38A18FAF, - 0x38D744FD,0x390F6A81,0x393F179A,0x397E9E11,0x39A9A15B,0x39E2055B,0x3A16942D,0x3A48A2D8, - 0x3A85AAC3,0x3AB21A32,0x3AED4F30,0x3B1E196E,0x3B52A81E,0x3B8C57CA,0x3BBAFF5B,0x3BF9295A, - 0x3C25FED7,0x3C5D2D82,0x3C935A2B,0x3CC4563F,0x3D02CD87,0x3D2E4934,0x3D68396A,0x3D9AB62B, - 0x3DCE248C,0x3E0955EE,0x3E36FD92,0x3E73D290,0x3EA27043,0x3ED87039,0x3F1031DC,0x3F40213B, - },{ - 0x3F800000,0x3FAA8D26,0x3FE33F89,0x4017657D,0x4049B9BE,0x40866491,0x40B311C4,0x40EE9910, - 0x411EF532,0x4153CCF1,0x418D1ADF,0x41BC034A,0x41FA83B3,0x4226E595,0x425E60F5,0x429426FF, - 0x42C5672A,0x43038359,0x432F3B79,0x43697C38,0x439B8D3A,0x43CF4319,0x440A14D5,0x4437FBF0, - 0x4475257D,0x44A3520F,0x44D99D16,0x4510FA4D,0x45412C4D,0x4580B1ED,0x45AB7A3A,0x45E47B6D, - 0x461837F0,0x464AD226,0x46871F62,0x46B40AAF,0x46EFE4BA,0x471FD228,0x4754F35B,0x478DDF04, - 0x47BD08A4,0x47FBDFED,0x4827CD94,0x485F9613,0x4894F4F0,0x48C67991,0x49043A29,0x49302F0E, - 0x496AC0C7,0x499C6573,0x49D06334,0x4A0AD4C6,0x4A38FBAF,0x4A767A41,0x4AA43516,0x4ADACB94, - 0x4B11C3D3,0x4B4238D2,0x4B8164D2,0x4BAC6897,0x4BE5B907,0x4C190B88,0x4C4BEC15,0x00000000, - } - }; - static float *listFloat = (float *)listInt[1]; - for (unsigned int i = 0, k = c, l = c - 1; i>= 1) { - float *d1 = d; - float *d2 = &d[count2]; - for (int j = 0; j>= 1, count2 <<= 1) { - float *list1Float = (float *)list1Int[i]; - float *list2Float = (float *)list2Int[i]; - float *s1 = s; - float *s2 = &s1[count2]; - float *d1 = d; - float *d2 = &d1[count2 * 2 - 1]; - for (int j = 0; j +#include + +#ifdef _WIN32 +#include +#endif + +inline short bswap(short v) { short r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline unsigned short bswap(unsigned short v) { unsigned short r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline int bswap(int v) { int r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline unsigned int bswap(unsigned int v) { unsigned int r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline long long bswap(long long v) { long long r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline unsigned long long bswap(unsigned long long v) { unsigned long long r = v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; r <<= 8; v >>= 8; r |= v & 0xFF; return r; } +inline float bswap(float v) { unsigned int i = bswap(*(unsigned int *)&v); return *(float *)&i; } +inline unsigned int ceil2(unsigned int a, unsigned int b) { return (b>0) ? (a / b + ((a%b) ? 1 : 0)) : 0; } + +clHCA::clHCA(unsigned int ciphKey1, unsigned int ciphKey2) : + _ciph_key1(ciphKey1), _ciph_key2(ciphKey2), _ath(), _cipher() {} + +bool clHCA::CheckFile(void *data, unsigned int size) { + return (data&&size >= 4 && (*(unsigned int *)data & 0x7F7F7F7F) == 0x00414348); +} + +unsigned short clHCA::CheckSum(void *data, int size, unsigned short sum) { + static unsigned short v[] = { + 0x0000,0x8005,0x800F,0x000A,0x801B,0x001E,0x0014,0x8011,0x8033,0x0036,0x003C,0x8039,0x0028,0x802D,0x8027,0x0022, + 0x8063,0x0066,0x006C,0x8069,0x0078,0x807D,0x8077,0x0072,0x0050,0x8055,0x805F,0x005A,0x804B,0x004E,0x0044,0x8041, + 0x80C3,0x00C6,0x00CC,0x80C9,0x00D8,0x80DD,0x80D7,0x00D2,0x00F0,0x80F5,0x80FF,0x00FA,0x80EB,0x00EE,0x00E4,0x80E1, + 0x00A0,0x80A5,0x80AF,0x00AA,0x80BB,0x00BE,0x00B4,0x80B1,0x8093,0x0096,0x009C,0x8099,0x0088,0x808D,0x8087,0x0082, + 0x8183,0x0186,0x018C,0x8189,0x0198,0x819D,0x8197,0x0192,0x01B0,0x81B5,0x81BF,0x01BA,0x81AB,0x01AE,0x01A4,0x81A1, + 0x01E0,0x81E5,0x81EF,0x01EA,0x81FB,0x01FE,0x01F4,0x81F1,0x81D3,0x01D6,0x01DC,0x81D9,0x01C8,0x81CD,0x81C7,0x01C2, + 0x0140,0x8145,0x814F,0x014A,0x815B,0x015E,0x0154,0x8151,0x8173,0x0176,0x017C,0x8179,0x0168,0x816D,0x8167,0x0162, + 0x8123,0x0126,0x012C,0x8129,0x0138,0x813D,0x8137,0x0132,0x0110,0x8115,0x811F,0x011A,0x810B,0x010E,0x0104,0x8101, + 0x8303,0x0306,0x030C,0x8309,0x0318,0x831D,0x8317,0x0312,0x0330,0x8335,0x833F,0x033A,0x832B,0x032E,0x0324,0x8321, + 0x0360,0x8365,0x836F,0x036A,0x837B,0x037E,0x0374,0x8371,0x8353,0x0356,0x035C,0x8359,0x0348,0x834D,0x8347,0x0342, + 0x03C0,0x83C5,0x83CF,0x03CA,0x83DB,0x03DE,0x03D4,0x83D1,0x83F3,0x03F6,0x03FC,0x83F9,0x03E8,0x83ED,0x83E7,0x03E2, + 0x83A3,0x03A6,0x03AC,0x83A9,0x03B8,0x83BD,0x83B7,0x03B2,0x0390,0x8395,0x839F,0x039A,0x838B,0x038E,0x0384,0x8381, + 0x0280,0x8285,0x828F,0x028A,0x829B,0x029E,0x0294,0x8291,0x82B3,0x02B6,0x02BC,0x82B9,0x02A8,0x82AD,0x82A7,0x02A2, + 0x82E3,0x02E6,0x02EC,0x82E9,0x02F8,0x82FD,0x82F7,0x02F2,0x02D0,0x82D5,0x82DF,0x02DA,0x82CB,0x02CE,0x02C4,0x82C1, + 0x8243,0x0246,0x024C,0x8249,0x0258,0x825D,0x8257,0x0252,0x0270,0x8275,0x827F,0x027A,0x826B,0x026E,0x0264,0x8261, + 0x0220,0x8225,0x822F,0x022A,0x823B,0x023E,0x0234,0x8231,0x8213,0x0216,0x021C,0x8219,0x0208,0x820D,0x8207,0x0202, + }; + for (unsigned char *s = (unsigned char *)data, *e = s + size; s> 8) ^ *s]; + return sum; +} + +bool clHCA::PrintInfo(const char *filenameHCA) { + + if (!(filenameHCA))return false; + + FILE *fp; +#ifdef _WIN32 + wchar_t strUnicode[260]; + MultiByteToWideChar(CP_UTF8, 0, filenameHCA, -1, strUnicode, 260); + if (!(fp = _wfopen(strUnicode, L"rb"))) { + printf("Error: Can not open file.\n"); + return false; + } +#else + if (!(fp = fopen(filenameHCA, "rb"))) { + printf("Error: Can not open file.\n"); + return false; + } +#endif + + stHeader header; + memset(&header, 0, sizeof(header)); + fread(&header, sizeof(header), 1, fp); + if (!CheckFile(&header, sizeof(header))) { + printf("Error: Not HCA File\n"); + fclose(fp); return false; + } + + header.dataOffset = bswap(header.dataOffset); + unsigned char *data = new unsigned char[header.dataOffset]; + if (!data) { + printf("Error: Memory not enough.\n"); + fclose(fp); return false; + } + fseek(fp, 0, SEEK_SET); + fread(data, header.dataOffset, 1, fp); + + unsigned char *s = (unsigned char *)data; + unsigned int size = header.dataOffset; + + if (sizeversion); + _dataOffset = bswap(hca->dataOffset); + printf("Codec: HCA\n"); + printf("Version: %d.%d\n", _version >> 8, _version & 0xFF); + //if(size<_dataOffset)return false; + if (CheckSum(hca, _dataOffset))printf("[!] Bad header.\n"); + } + else { + printf("[!] HCA chunk missing.\n"); + } + + // fmt + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { + stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); + _channelCount = fmt->channelCount; + _samplingRate = bswap(fmt->samplingRate << 8); + _blockCount = bswap(fmt->blockCount); + _muteHeader = bswap(fmt->muteHeader); + _muteFooter = bswap(fmt->muteFooter); + switch (_channelCount) { + case 1:printf("Chanel: Monoural (1 chanel)\n"); break; + case 2:printf("Chanel: Stereo (2 chanel)\n"); break; + default:printf("Chanel: %d chanel\n", _channelCount); break; + } + if (!(_channelCount >= 1 && _channelCount <= 16)) { + printf("[!] Chanel is from 1 to 16.\n"); + } + printf("Sampling Rate: %d Hz\n", _samplingRate); + if (!(_samplingRate >= 1 && _samplingRate <= 0x7FFFFF)) { + printf("[!] Sampling Rate is from 1 to 8388607(0x7FFFFF).\n"); + } + printf("Block Count: %d\n", _blockCount); + printf("Header No Sound Part: %d\n", (_muteHeader - 0x80) / 0x400); + printf("Footer No Sound Sample: %d\n", _muteFooter); + } + else { + printf("[!] fmt chunk missing.\n"); + } + + // comp + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { + stCompress *comp = (stCompress *)s; s += sizeof(stCompress); + _blockSize = bswap(comp->blockSize); + _comp_r01 = comp->r01; + _comp_r02 = comp->r02; + _comp_r03 = comp->r03; + _comp_r04 = comp->r04; + _comp_r05 = comp->r05; + _comp_r06 = comp->r06; + _comp_r07 = comp->r07; + _comp_r08 = comp->r08; + unsigned int bps = _samplingRate*_blockSize / 128; + if (bps<1000000)printf("Bit Rate: %gkbps CBR (constant Bit Rate)\n", bps / 1000.0f); + else printf("Bit Rate: %gMbps CBR (constant Bit Rate)\n", bps / 1000000.0f); + printf("Block Size: 0x%X\n", _blockSize); + if (!(_blockSize >= 8 && _blockSize <= 0xFFFF)) { + printf("[!] Block size is from 8 to 65535(0xFFFF). 0 is VBR in v1.3, unused from v2.0.\n"); + } + printf("comp1: %d\n", _comp_r01); + printf("comp2: %d\n", _comp_r02); + if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F)) { + printf("[!] comp1 and comp2 are 0 <= comp1 <= comp2 <= 31. v2.0: comp1 = 1, comp2 = 15.\n"); + } + printf("comp3: %d\n", _comp_r03); + if (!_comp_r03) { + printf("[!] comp3 is >1.\n"); + } + printf("comp4: %d\n", _comp_r04); + printf("comp5: %d\n", _comp_r05); + printf("comp6: %d\n", _comp_r06); + printf("comp7: %d\n", _comp_r07); + printf("comp8: %d\n", _comp_r08); + } + + // dec + else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { + stDecode *dec = (stDecode *)s; s += sizeof(stDecode); + _blockSize = bswap(dec->blockSize); + _comp_r01 = dec->r01; + _comp_r02 = dec->r02; + _comp_r03 = dec->r04; + _comp_r04 = dec->r03; + _comp_r05 = dec->count1 + 1; + _comp_r06 = ((dec->enableCount2) ? dec->count2 : dec->count1) + 1; + _comp_r07 = _comp_r05 - _comp_r06; + _comp_r08 = 0; + unsigned int bps = _samplingRate*_blockSize / 128; + if (bps<1000000)printf("Bit Rate: %gkbps CBR (constant bit Rate)\n", bps / 1000.0f); + else printf("Bit Rate: %gMbps CBR (constant bit Rate)\n", bps / 1000000.0f); + printf("Block Size: 0x%X\n", _blockSize); + if (!(_blockSize >= 8 && _blockSize <= 0xFFFF)) { + printf("[!] Block size is from 8 to 65535(0xFFFF). 0 is VBR in v1.3, unused from v2.0.\n"); + } + printf("dec1: %d\n", _comp_r01); + printf("dec2: %d\n", _comp_r02); + if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F)) { + printf("[!] dec1 and dec2 are 0 <= dec1 <= dec2 <= 31. v2.0: dec1 = 1, dec2 = 15.\n\n"); + } + printf("dec3: %d\n", _comp_r03); + if (!_comp_r03) { + printf("[!] dec3 will be corrected to >1 when playing.\n"); + } + printf("dec4: %d\n", _comp_r04); + printf("dec5: %d\n", _comp_r05); + printf("dec6: %d\n", _comp_r06); + printf("dec7: %d\n", _comp_r07); + } + else { + printf("[!] comp or dec missing.\n"); + } + + // vbr + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { + stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); + _vbr_r01 = bswap(vbr->r01); + _vbr_r02 = bswap(vbr->r02); + printf("Bit Rate: VBR (Variable Bit Rate) [!]Unused from v2.0.\n"); + if (!(_blockSize == 0)) { + printf("[!] CBR has been specified in comp or dec chunk.\n"); + } + printf("vbr1: %d\n", _vbr_r01); + if (!(_vbr_r01 >= 0 && _vbr_r01 <= 0x1FF)) { + printf("[!] vbr1 is from 0 to 511(0x1FF).\n"); + } + printf("vbr2: %d\n", _vbr_r02); + } + else { + _vbr_r01 = 0; + _vbr_r02 = 0; + } + + // ath + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { + stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); + _ath_type = ath->type; + printf("ATH Type:%d [!] Unused from v2.0.\n", _ath_type); + } + else { + if (_version<0x200) { + printf("ATH Type:1 [!] Unused from v2.0.\n"); + } + } + + // loop + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { + stLoop *loop = (stLoop *)s; s += sizeof(stLoop); + _loopStart = bswap(loop->start); + _loopEnd = bswap(loop->end); + _loopCount = bswap(loop->count); + _loop_r01 = bswap(loop->r01); + printf("Loop Start: %d\n", _loopStart); + printf("Loop End: %d\n", _loopEnd); + if (!(_loopStart >= 0 && _loopStart <= _loopEnd&&_loopEnd<_blockCount)) { + printf("[!] Loop start and loop end is 0 <= loopStart <= loopEnd < blockCount.\n"); + } + if (_loopCount == 0x80) { + printf("Loop: Infinite\n"); + } + else { + printf("Loop: %d times\n", _loopCount); + } + printf("Loop Information 1: %d\n", _loop_r01); + } + + // ciph + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { + stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); + _ciph_type = bswap(ciph->type); + switch (_ciph_type) { + case 0:printf("Cipher Type: none\n"); break; + case 1:printf("Cipher Type: no-key\n"); break; + case 0x38:printf("Cipher Type: key [!] Require correct key.\n"); break; + default:printf("Cipher Type: %d\n", _ciph_type); break; + } + if (!(_ciph_type == 0 || _ciph_type == 1 || _ciph_type == 0x38)) { + printf("[!] v2.0 now can not play this cipher type.\n"); + } + } + + // rva + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { + stRVA *rva = (stRVA *)s; s += sizeof(stRVA); + _rva_volume = bswap(rva->volume); + printf("Relative Volume: %g times\n", _rva_volume); + } + + // comm + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { + stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); + _comm_len = comm->len; + _comm_comment = (char *)s; + printf("Comment: %s\n", _comm_comment); + } + + delete[] data; + + fclose(fp); + + return true; +} + +bool clHCA::Decrypt(const char *filenameHCA) { + + if (!(filenameHCA))return false; + + FILE *fp; +#ifdef _WIN32 + wchar_t strUnicode[260]; + MultiByteToWideChar(CP_UTF8, 0, filenameHCA, -1, strUnicode, 260); + if (!(fp = _wfopen(strUnicode, L"r+b"))) return false; +#else + if (!(fp = fopen(filenameHCA, "r+b")))return false; +#endif + + stHeader header; + memset(&header, 0, sizeof(header)); + fread(&header, sizeof(header), 1, fp); + if (!CheckFile(&header, sizeof(header))) { fclose(fp); return false; } + + header.dataOffset = bswap(header.dataOffset); + unsigned char *data = new unsigned char[header.dataOffset]; + if (!data) { fclose(fp); return false; } + fseek(fp, 0, SEEK_SET); + fread(data, header.dataOffset, 1, fp); + + unsigned char *s = (unsigned char *)data; + unsigned int size = header.dataOffset; + + if (sizehca &= 0x7F7F7F7F; + _version = bswap(hca->version); + _dataOffset = bswap(hca->dataOffset); + } + else { + delete[] data; fclose(fp); return false; + } + + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { + stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); + fmt->fmt &= 0x7F7F7F7F; + _samplingRate = bswap(fmt->samplingRate << 8); + _blockCount = bswap(fmt->blockCount); + } + else { + delete[] data; fclose(fp); return false; + } + + // comp + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { + stCompress *comp = (stCompress *)s; s += sizeof(stCompress); + comp->comp &= 0x7F7F7F7F; + _blockSize = bswap(comp->blockSize); + } + + // dec + else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { + stDecode *dec = (stDecode *)s; s += sizeof(stDecode); + dec->dec &= 0x7F7F7F7F; + _blockSize = bswap(dec->blockSize); + } + else { + delete[] data; fclose(fp); return false; + } + + // vbr + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { + stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); + vbr->vbr &= 0x7F7F7F7F; + } + + // ath + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { + stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); + ath->ath &= 0x7F7F7F7F; + _ath_type = bswap(ath->type); + //ath->type=0; + } + else { + if (_version<0x200)_ath_type = 1; + } + + // loop + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { + stLoop *loop = (stLoop *)s; s += sizeof(stLoop); + loop->loop &= 0x7F7F7F7F; + } + + // ciph + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { + stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); + ciph->ciph &= 0x7F7F7F7F; + _ciph_type = bswap(ciph->type); + ciph->type = 0; + } + + // rva + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { + stRVA *rva = (stRVA *)s; s += sizeof(stRVA); + rva->rva &= 0x7F7F7F7F; + } + + // comm + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { + stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); + comm->comm &= 0x7F7F7F7F; + s += comm->len; + } + + // pad + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00646170) { + stPadding *pad = (stPadding *)s; s += sizeof(stPadding); + pad->pad &= 0x7F7F7F7F; + } + + if (!_ath.Init(_ath_type, _samplingRate)) { delete[] data; fclose(fp); return false; } + if (!_cipher.Init(_ciph_type, _ciph_key1, _ciph_key2)) { delete[] data; fclose(fp); return false; } + unsigned char *data2 = new unsigned char[_blockSize]; + if (!data2) { delete[] data; fclose(fp); return false; } + + *(unsigned short *)&data[size - 2] = bswap(CheckSum(data, size - 2)); + fseek(fp, 0, SEEK_SET); + fwrite(data, size, 1, fp); + delete[] data; + + if (_ciph_type != 0) { + for (unsigned int i = 0, a = size; i<_blockCount; i++, a += _blockSize) { + fseek(fp, a, SEEK_SET); + fread(data2, _blockSize, 1, fp); + _cipher.Mask(data2, _blockSize); + *(unsigned short *)&data2[_blockSize - 2] = bswap(CheckSum(data2, _blockSize - 2)); + fseek(fp, a, SEEK_SET); + fwrite(data2, _blockSize, 1, fp); + } + } + delete[] data2; + + fclose(fp); + + return true; +} + +bool clHCA::DecodeToWavefile(const char *filenameHCA, const char *filenameWAV, float volume, int mode, int loop) { + if (!(filenameHCA))return false; + + FILE *fp; +#ifdef _WIN32 + wchar_t strUnicode[260]; + MultiByteToWideChar(CP_UTF8, 0, filenameHCA, -1, strUnicode, 260); + if (!(fp = _wfopen(strUnicode, L"rb"))) return false; +#else + if (!(fp = fopen(filenameHCA, "rb")))return false; +#endif + + if (!DecodeToWavefileStream(fp, filenameWAV, volume, mode, loop)) { fclose(fp); return false; } + + fclose(fp); + + return true; +} +bool clHCA::DecodeToWavefileStream(void *fpHCA, const char *filenameWAV, float volume, int mode, int loop) { + + if (!(fpHCA&&filenameWAV && (mode == 0 || mode == 8 || mode == 16 || mode == 24 || mode == 32) && loop >= 0))return false; + + FILE *fp1 = (FILE *)fpHCA; + unsigned int address = ftell(fp1); + + stHeader header; + memset(&header, 0, sizeof(header)); + fread(&header, sizeof(header), 1, fp1); + if (!CheckFile(&header, sizeof(header)))return false; + + header.dataOffset = bswap(header.dataOffset); + unsigned char *data1 = new unsigned char[header.dataOffset]; + if (!data1) { fclose(fp1); return false; } + fseek(fp1, address, SEEK_SET); + fread(data1, header.dataOffset, 1, fp1); + if (!Decode(data1, header.dataOffset, 0)) { delete[] data1; return false; } + + FILE *fp2; +#ifdef _WIN32 + wchar_t strUnicode[260]; + MultiByteToWideChar(CP_UTF8, 0, filenameWAV, -1, strUnicode, 260); + if (!(fp2 = _wfopen(strUnicode, L"wb"))) { delete[] data1; return false; } +#else + if (!(fp2 = fopen(filenameWAV, "wb"))) { delete[] data1; return false; } +#endif + + struct stWAVEHeader { + char riff[4]; + unsigned int riffSize; + char wave[4]; + char fmt[4]; + unsigned int fmtSize; + unsigned short fmtType; + unsigned short fmtChannelCount; + unsigned int fmtSamplingRate; + unsigned int fmtSamplesPerSec; + unsigned short fmtSamplingSize; + unsigned short fmtBitCount; + }wavRiff = { 'R','I','F','F',0,'W','A','V','E','f','m','t',' ',0x10,0,0,0,0,0,0 }; + struct stWAVEsmpl { + char smpl[4]; + unsigned int smplSize; + unsigned int manufacturer; + unsigned int product; + unsigned int samplePeriod; + unsigned int MIDIUnityNote; + unsigned int MIDIPitchFraction; + unsigned int SMPTEFormat; + unsigned int SMPTEOffset; + unsigned int sampleLoops; + unsigned int samplerData; + unsigned int loop_Identifier; + unsigned int loop_Type; + unsigned int loop_Start; + unsigned int loop_End; + unsigned int loop_Fraction; + unsigned int loop_PlayCount; + }wavSmpl = { 's','m','p','l',0x3C,0,0,0,0x3C,0,0,0,1,0x18,0,0,0,0,0,0 }; + struct stWAVEnote { + char note[4]; + unsigned int noteSize; + unsigned int dwName; + }wavNote = { 'n','o','t','e',0,0 }; + struct stWAVEdata { + char data[4]; + unsigned int dataSize; + }wavData = { 'd','a','t','a',0 }; + wavRiff.fmtType = (mode>0) ? 1 : 3; + wavRiff.fmtChannelCount = _channelCount; + wavRiff.fmtBitCount = (mode>0) ? mode : 32; + wavRiff.fmtSamplingRate = _samplingRate; + wavRiff.fmtSamplingSize = wavRiff.fmtBitCount / 8 * wavRiff.fmtChannelCount; + wavRiff.fmtSamplesPerSec = wavRiff.fmtSamplingRate*wavRiff.fmtSamplingSize; + if (_loopFlg) { + wavSmpl.samplePeriod = (unsigned int)(1 / (double)wavRiff.fmtSamplingRate * 1000000000); + wavSmpl.loop_Start = _loopStart * 0x80 * 8 + _muteFooter; //[!] Unknown + wavSmpl.loop_End = (_loopEnd + 1) * 0x80 * 8 - 1; //[!] Unknown + wavSmpl.loop_PlayCount = (_loopCount == 0x80) ? 0 : _loopCount; + } + else if (loop) { + wavSmpl.loop_Start = 0; + wavSmpl.loop_End = (_blockCount + 1) * 0x80 * 8 - 1; //[!] Unknown + _loopStart = 0; + _loopEnd = _blockCount; + } + if (_comm_comment) { + wavNote.noteSize = 4 + _comm_len + 1; + if (wavNote.noteSize & 3)wavNote.noteSize += 4 - (wavNote.noteSize & 3); + } + wavData.dataSize = _blockCount * 0x80 * 8 * wavRiff.fmtSamplingSize + (wavSmpl.loop_End - wavSmpl.loop_Start)*loop; + wavRiff.riffSize = 0x1C + ((_loopFlg && !loop) ? sizeof(wavSmpl) : 0) + (_comm_comment ? 8 + wavNote.noteSize : 0) + sizeof(wavData) + wavData.dataSize; + fwrite(&wavRiff, sizeof(wavRiff), 1, fp2); + if (_loopFlg && !loop)fwrite(&wavSmpl, sizeof(wavSmpl), 1, fp2); + if (_comm_comment) { + int address = ftell(fp2); + fwrite(&wavNote, sizeof(wavNote), 1, fp2); + fputs(_comm_comment, fp2); + fseek(fp2, address + 8 + wavNote.noteSize, SEEK_SET); + } + fwrite(&wavData, sizeof(wavData), 1, fp2); + + _rva_volume *= volume; + + void (*modeFunction)(float, void *) = NULL; + modeFunction = DecodeToWavefile_DecodeMode16bit; + switch (mode) { + case 0:modeFunction = DecodeToWavefile_DecodeModeFloat; break; + case 8:modeFunction = DecodeToWavefile_DecodeMode8bit; break; + case 16:modeFunction = DecodeToWavefile_DecodeMode16bit; break; + case 24:modeFunction = DecodeToWavefile_DecodeMode24bit; break; + case 32:modeFunction = DecodeToWavefile_DecodeMode32bit; break; + } + unsigned char *data2 = new unsigned char[_blockSize]; + if (!data2) { delete[] data1; fclose(fp2); return false; } + if (!loop) { + if (!DecodeToWavefile_Decode(fp1, fp2, address + _dataOffset, _blockCount, data2, modeFunction)) { delete[] data2; delete[] data1; fclose(fp2); return false; } + } + else { + unsigned int loopBlockOffset = _dataOffset + _loopStart*_blockSize; + unsigned int loopBlockCount = _loopEnd - _loopStart; + if (!DecodeToWavefile_Decode(fp1, fp2, address + _dataOffset, _loopEnd, data2, modeFunction)) { delete[] data2; delete[] data1; fclose(fp2); return false; } + for (int i = 1; i1) { f = 1; } + else if (f<-1) { f = -1; } + ((void(*)(float, void *))modeFunction)(f, fp2); + } + } + } + } + return true; +} +void clHCA::DecodeToWavefile_DecodeModeFloat(float f, void *fp) { fwrite(&f, sizeof(f), 1, (FILE *)fp); } +void clHCA::DecodeToWavefile_DecodeMode8bit(float f, void *fp) { int v = (int)(f * 0x7F) + 0x80; fwrite(&v, 1, 1, (FILE *)fp); } +void clHCA::DecodeToWavefile_DecodeMode16bit(float f, void *fp) { int v = (int)(f * 0x7FFF); fwrite(&v, 2, 1, (FILE *)fp); } +void clHCA::DecodeToWavefile_DecodeMode24bit(float f, void *fp) { int v = (int)(f * 0x7FFFFF); fwrite(&v, 3, 1, (FILE *)fp); } +void clHCA::DecodeToWavefile_DecodeMode32bit(float f, void *fp) { int v = (int)(f * 0x7FFFFFFF); fwrite(&v, 4, 1, (FILE *)fp); } + +/*bool clHCA::EncodeFromWavefile(const char *filenameWAV,const char *filenameHCA,float volume){ + +if(!(filenameWAV))return false; + +FILE *fp; +if(!(fp = fopen(filenameWAV,"rb")))return false; + +if(!EncodeFromWavefileStream(fp,filenameHCA,volume)){fclose(fp);return false;} + +fclose(fp); + +return true; +} +bool clHCA::EncodeFromWavefileStream(void *fpWAV,const char *filenameHCA,float volume){ + +if(!(fpWAV&&filenameHCA))return false; + +FILE *fp1=(FILE *)fpWAV; +unsigned int address=ftell(fp1); + +struct stWAVEHeader{ +unsigned int riff; +unsigned int riffSize; +unsigned int wave; +unsigned int fmt; +unsigned int fmtSize; +unsigned short fmtType; +unsigned short fmtChannelCount; +unsigned int fmtSamplingRate; +unsigned int fmtSamplesPerSec; +unsigned short fmtSamplingSize; +unsigned short fmtBitCount; +}header; +memset(&header,0,sizeof(header)); +fread(&header,sizeof(header),1,fp1); +if(!(header.riff==0x46464952&&header.wave==0x45564157&&header.fmt==0x20746D66&&(header.fmtType==1||header.fmtType==3)))return false; + +//@@@@@@@@@@@@@@@@@@@@@@@ + +return true; +}*/ + +//-------------------------------------------------- +// ATH +//-------------------------------------------------- +clHCA::clATH::clATH() { Init0(); } +bool clHCA::clATH::Init(int type, unsigned int key) { + switch (type) { + case 0:Init0(); break; + case 1:Init1(key); break; + default:return false; + } + return true; +} +unsigned char *clHCA::clATH::GetTable(void) { + return _table; +} +void clHCA::clATH::Init0(void) { + memset(_table, 0, sizeof(_table)); +} +void clHCA::clATH::Init1(unsigned int key) { + static unsigned char list[] = { + 0x78,0x5F,0x56,0x51,0x4E,0x4C,0x4B,0x49,0x48,0x48,0x47,0x46,0x46,0x45,0x45,0x45, + 0x44,0x44,0x44,0x44,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x42,0x42,0x42,0x42,0x42, + 0x42,0x42,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, + 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, + 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, + 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C, + 0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3F, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x3F,0x3F,0x3F,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x41,0x41,0x41,0x41, + 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, + 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, + 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x43,0x43,0x43, + 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x45,0x45,0x45,0x45, + 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, + 0x46,0x46,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x48,0x48,0x48,0x48, + 0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4A,0x4A,0x4A,0x4A, + 0x4A,0x4A,0x4A,0x4A,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4C,0x4C,0x4C,0x4C,0x4C, + 0x4C,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4E,0x4E,0x4E,0x4E,0x4E,0x4E,0x4F,0x4F,0x4F, + 0x4F,0x4F,0x4F,0x50,0x50,0x50,0x50,0x50,0x51,0x51,0x51,0x51,0x51,0x52,0x52,0x52, + 0x52,0x52,0x53,0x53,0x53,0x53,0x54,0x54,0x54,0x54,0x54,0x55,0x55,0x55,0x55,0x56, + 0x56,0x56,0x56,0x57,0x57,0x57,0x57,0x57,0x58,0x58,0x58,0x59,0x59,0x59,0x59,0x5A, + 0x5A,0x5A,0x5A,0x5B,0x5B,0x5B,0x5B,0x5C,0x5C,0x5C,0x5D,0x5D,0x5D,0x5D,0x5E,0x5E, + 0x5E,0x5F,0x5F,0x5F,0x60,0x60,0x60,0x61,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, + 0x63,0x64,0x64,0x64,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69, + 0x69,0x6A,0x6A,0x6A,0x6B,0x6B,0x6B,0x6C,0x6C,0x6D,0x6D,0x6D,0x6E,0x6E,0x6F,0x6F, + 0x70,0x70,0x70,0x71,0x71,0x72,0x72,0x73,0x73,0x73,0x74,0x74,0x75,0x75,0x76,0x76, + 0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7D,0x7D,0x7E, + 0x7E,0x7F,0x7F,0x80,0x80,0x81,0x81,0x82,0x83,0x83,0x84,0x84,0x85,0x85,0x86,0x86, + 0x87,0x88,0x88,0x89,0x89,0x8A,0x8A,0x8B,0x8C,0x8C,0x8D,0x8D,0x8E,0x8F,0x8F,0x90, + 0x90,0x91,0x92,0x92,0x93,0x94,0x94,0x95,0x95,0x96,0x97,0x97,0x98,0x99,0x99,0x9A, + 0x9B,0x9B,0x9C,0x9D,0x9D,0x9E,0x9F,0xA0,0xA0,0xA1,0xA2,0xA2,0xA3,0xA4,0xA5,0xA5, + 0xA6,0xA7,0xA7,0xA8,0xA9,0xAA,0xAA,0xAB,0xAC,0xAD,0xAE,0xAE,0xAF,0xB0,0xB1,0xB1, + 0xB2,0xB3,0xB4,0xB5,0xB6,0xB6,0xB7,0xB8,0xB9,0xBA,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCD, + 0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD, + 0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xED,0xEE, + 0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFF,0xFF, + }; + for (unsigned int i = 0, v = 0; i<0x80; i++, v += key) { + unsigned int index = v >> 13; + if (index >= 0x28E) { + memset(&_table[i], 0xFF, 0x80 - i); + break; + } + _table[i] = list[index]; + } +} + +clHCA::clCipher::clCipher() { Init0(); } +bool clHCA::clCipher::Init(int type, unsigned int key1, unsigned int key2) { + if (!(key1 | key2))type = 0; + switch (type) { + case 0:Init0(); break; + case 1:Init1(); break; + case 56:Init56(key1, key2); break; + default:return false; + } + return true; +} +void clHCA::clCipher::Mask(void *data, int size) { + for (unsigned char *d = (unsigned char *)data; size>0; d++, size--)*d = _table[*d]; +} +void clHCA::clCipher::Init0(void) { + for (int i = 0; i<0x100; i++)_table[i] = i; +} +void clHCA::clCipher::Init1(void) { + for (int i = 1, v = 0; i<0xFF; i++) { + v = (v * 13 + 11) & 0xFF; + if (v == 0 || v == 0xFF)v = (v * 13 + 11) & 0xFF; + _table[i] = v; + } + _table[0] = 0; + _table[0xFF] = 0xFF; +} +void clHCA::clCipher::Init56(unsigned int key1, unsigned int key2) { + + unsigned char t1[8]; + if (!key1)key2--; + key1--; + for (int i = 0; i<7; i++) { + t1[i] = key1; + key1 = (key1 >> 8) | (key2 << 24); + key2 >>= 8; + } + + unsigned char t2[0x10] = { + t1[1],static_cast(t1[1] ^ t1[6]), + static_cast(t1[2] ^ t1[3]),t1[2], + static_cast(t1[2] ^ t1[1]),static_cast(t1[3] ^ t1[4]), + t1[3],static_cast(t1[3] ^ t1[2]), + static_cast(t1[4] ^ t1[5]),t1[4], + static_cast(t1[4] ^ t1[3]),static_cast(t1[5] ^ t1[6]), + t1[5],static_cast(t1[5] ^ t1[4]), + static_cast(t1[6] ^ t1[1]),t1[6], + }; + + unsigned char t3[0x100], t31[0x10], t32[0x10], *t = t3; + Init56_CreateTable(t31, t1[0]); + for (int i = 0; i<0x10; i++) { + Init56_CreateTable(t32, t2[i]); + unsigned char v = t31[i] << 4; + for (int j = 0; j<0x10; j++) { + *(t++) = v | t32[j]; + } + } + + t = &_table[1]; + for (int i = 0, v = 0; i<0x100; i++) { + v = (v + 0x11) & 0xFF; + unsigned char a = t3[v]; + if (a != 0 && a != 0xFF)*(t++) = a; + } + _table[0] = 0; + _table[0xFF] = 0xFF; + +} +void clHCA::clCipher::Init56_CreateTable(unsigned char *r, unsigned char key) { + int mul = ((key & 1) << 3) | 5; + int add = (key & 0xE) | 1; + key >>= 4; + for (int i = 0; i<0x10; i++) { + key = (key*mul + add) & 0xF; + *(r++) = key; + } +} + +clHCA::clData::clData(void *data, int size) :_data((unsigned char *)data), _size(size * 8 - 16), _bit(0) {} +int clHCA::clData::CheckBit(int bitSize) { + int v = 0; + if (_bit + bitSize <= _size) { + static int mask[] = { 0xFFFFFF,0x7FFFFF,0x3FFFFF,0x1FFFFF,0x0FFFFF,0x07FFFF,0x03FFFF,0x01FFFF }; + unsigned char *data = &_data[_bit >> 3]; + v = data[0]; v = (v << 8) | data[1]; v = (v << 8) | data[2]; + v &= mask[_bit & 7]; + v >>= 24 - (_bit & 7) - bitSize; + } + return v; +} +int clHCA::clData::GetBit(int bitSize) { + int v = CheckBit(bitSize); + _bit += bitSize; + return v; +} +void clHCA::clData::AddBit(int bitSize) { + _bit += bitSize; +} + +bool clHCA::Decode(void *data, unsigned int size, unsigned int address) { + + if (!(data))return false; + + if (address == 0) { + unsigned char *s = (unsigned char *)data; + + if (sizeversion); + _dataOffset = bswap(hca->dataOffset); + //if(!(_version<=0x200&&_version>0x101))return false; + if (size<_dataOffset)return false; + //if(CheckSum(hca,_dataOffset))return false; + } + else { + return false; + } + + // fmt + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00746D66) { + stFormat *fmt = (stFormat *)s; s += sizeof(stFormat); + _channelCount = fmt->channelCount; + _samplingRate = bswap(fmt->samplingRate << 8); + _blockCount = bswap(fmt->blockCount); + _muteHeader = bswap(fmt->muteHeader); + _muteFooter = bswap(fmt->muteFooter); + if (!(_channelCount >= 1 && _channelCount <= 16))return false; + if (!(_samplingRate >= 1 && _samplingRate <= 0x7FFFFF))return false; + } + else { + return false; + } + + // comp + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706D6F63) { + stCompress *comp = (stCompress *)s; s += sizeof(stCompress); + _blockSize = bswap(comp->blockSize); + _comp_r01 = comp->r01; + _comp_r02 = comp->r02; + _comp_r03 = comp->r03; + _comp_r04 = comp->r04; + _comp_r05 = comp->r05; + _comp_r06 = comp->r06; + _comp_r07 = comp->r07; + _comp_r08 = comp->r08; + if (!((_blockSize >= 8 && _blockSize <= 0xFFFF) || (_blockSize == 0)))return false; + if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F))return false; + } + + // dec + else if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00636564) { + stDecode *dec = (stDecode *)s; s += sizeof(stDecode); + _blockSize = bswap(dec->blockSize); + _comp_r01 = dec->r01; + _comp_r02 = dec->r02; + _comp_r03 = dec->r04; + _comp_r04 = dec->r03; + _comp_r05 = dec->count1 + 1; + _comp_r06 = ((dec->enableCount2) ? dec->count2 : dec->count1) + 1; + _comp_r07 = _comp_r05 - _comp_r06; + _comp_r08 = 0; + if (!((_blockSize >= 8 && _blockSize <= 0xFFFF) || (_blockSize == 0)))return false; + if (!(_comp_r01 >= 0 && _comp_r01 <= _comp_r02&&_comp_r02 <= 0x1F))return false; + if (!_comp_r03)_comp_r03 = 1; + } + else { + return false; + } + + // vbr + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00726276) { + stVBR *vbr = (stVBR *)s; s += sizeof(stVBR); + _vbr_r01 = bswap(vbr->r01); + _vbr_r02 = bswap(vbr->r02); + if (!(_blockSize == 0 && _vbr_r01 >= 0 && _vbr_r01 <= 0x1FF))return false; + } + else { + _vbr_r01 = 0; + _vbr_r02 = 0; + } + + // ath + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00687461) { + stATH *ath = (stATH *)s; s += 6;//s+=sizeof(stATH); + _ath_type = ath->type; + } + else { + _ath_type = (_version<0x200) ? 1 : 0; + } + + // loop + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x706F6F6C) { + stLoop *loop = (stLoop *)s; s += sizeof(stLoop); + _loopStart = bswap(loop->start); + _loopEnd = bswap(loop->end); + _loopCount = bswap(loop->count); + _loop_r01 = bswap(loop->r01); + _loopFlg = true; + if (!(_loopStart >= 0 && _loopStart <= _loopEnd&&_loopEnd<_blockCount))return false; + } + else { + _loopStart = 0; + _loopEnd = 0; + _loopCount = 0; + _loop_r01 = 0x400; + _loopFlg = false; + } + + // ciph + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x68706963) { + stCipher *ciph = (stCipher *)s; s += 6;//s+=sizeof(stCipher); + _ciph_type = bswap(ciph->type); + if (!(_ciph_type == 0 || _ciph_type == 1 || _ciph_type == 0x38))return false; + } + else { + _ciph_type = 0; + } + + // rva + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x00617672) { + stRVA *rva = (stRVA *)s; s += sizeof(stRVA); + _rva_volume = bswap(rva->volume); + } + else { + _rva_volume = 1; + } + + // comm + if ((*(unsigned int *)s & 0x7F7F7F7F) == 0x6D6D6F63) { + stComment *comm = (stComment *)s; s += 5;//s+=sizeof(stComment); + _comm_len = comm->len; + _comm_comment = (char *)s; + } + else { + _comm_len = 0; + _comm_comment = NULL; + } + + if (!_ath.Init(_ath_type, _samplingRate))return false; + if (!_cipher.Init(_ciph_type, _ciph_key1, _ciph_key2))return false; + + if (!_comp_r03)_comp_r03 = 1; + + memset(_channel, 0, sizeof(_channel)); + if (!(_comp_r01 == 1 && _comp_r02 == 15))return false; + _comp_r09 = ceil2(_comp_r05 - (_comp_r06 + _comp_r07), _comp_r08); + char r[0x10]; memset(r, 0, sizeof(r)); + unsigned int b = _channelCount / _comp_r03; + if (_comp_r07&&b>1) { + char *c = r; + for (unsigned int i = 0; i<_comp_r03; i++, c += b) { + switch (b) { + case 2:c[0] = 1; c[1] = 2; break; + case 3:c[0] = 1; c[1] = 2; break; + case 4:c[0] = 1; c[1] = 2; if (_comp_r04 == 0) { c[2] = 1; c[3] = 2; }break; + case 5:c[0] = 1; c[1] = 2; if (_comp_r04 <= 2) { c[3] = 1; c[4] = 2; }break; + case 6:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; break; + case 7:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; break; + case 8:c[0] = 1; c[1] = 2; c[4] = 1; c[5] = 2; c[6] = 1; c[7] = 2; break; + } + } + } + for (unsigned int i = 0; i<_channelCount; i++) { + _channel[i].type = r[i]; + _channel[i].value3 = &_channel[i].value[_comp_r06 + _comp_r07]; + _channel[i].count = _comp_r06 + ((r[i] != 2) ? _comp_r07 : 0); + } + + } + + else if (address >= _dataOffset) { + if (size<_blockSize)return false; + if (CheckSum(data, _blockSize))return false; +// if(((unsigned char *)data)[_blockSize-2]==0x5E)_asm int 3 + _cipher.Mask(data, _blockSize); + clData d(data, _blockSize); + int magic = d.GetBit(16);//0xFFFF + if (magic == 0xFFFF) { + int a = (d.GetBit(9) << 8) - d.GetBit(7); + for (unsigned int i = 0; i<_channelCount; i++)_channel[i].Decode1(&d, _comp_r09, a, _ath.GetTable()); + for (int i = 0; i<8; i++) { + for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode2(&d); + for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode3(_comp_r09, _comp_r08, _comp_r07 + _comp_r06, _comp_r05); + for (unsigned int j = 0; j<_channelCount - 1; j++)_channel[j].Decode4(i, _comp_r05 - _comp_r06, _comp_r06, _comp_r07); + for (unsigned int j = 0; j<_channelCount; j++)_channel[j].Decode5(i); + } + } + } + + return true; +} + +void clHCA::stChannel::Decode1(clData *data, unsigned int a, int b, unsigned char *ath) { + static unsigned char scalelist[] = { + // v2.0 + 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, + 0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, + 0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, + 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, + 0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, + 0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, + 0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // v1.3 + //0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, + //0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, + //0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, + //0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, + //0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, + //0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, + //0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, + //0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + }; + static unsigned int valueInt[] = { + 0x342A8D26,0x34633F89,0x3497657D,0x34C9B9BE,0x35066491,0x353311C4,0x356E9910,0x359EF532, + 0x35D3CCF1,0x360D1ADF,0x363C034A,0x367A83B3,0x36A6E595,0x36DE60F5,0x371426FF,0x3745672A, + 0x37838359,0x37AF3B79,0x37E97C38,0x381B8D3A,0x384F4319,0x388A14D5,0x38B7FBF0,0x38F5257D, + 0x3923520F,0x39599D16,0x3990FA4D,0x39C12C4D,0x3A00B1ED,0x3A2B7A3A,0x3A647B6D,0x3A9837F0, + 0x3ACAD226,0x3B071F62,0x3B340AAF,0x3B6FE4BA,0x3B9FD228,0x3BD4F35B,0x3C0DDF04,0x3C3D08A4, + 0x3C7BDFED,0x3CA7CD94,0x3CDF9613,0x3D14F4F0,0x3D467991,0x3D843A29,0x3DB02F0E,0x3DEAC0C7, + 0x3E1C6573,0x3E506334,0x3E8AD4C6,0x3EB8FBAF,0x3EF67A41,0x3F243516,0x3F5ACB94,0x3F91C3D3, + 0x3FC238D2,0x400164D2,0x402C6897,0x4065B907,0x40990B88,0x40CBEC15,0x4107DB35,0x413504F3, + }; + static unsigned int scaleInt[] = { + 0x00000000,0x3F2AAAAB,0x3ECCCCCD,0x3E924925,0x3E638E39,0x3E3A2E8C,0x3E1D89D9,0x3E088889, + 0x3D842108,0x3D020821,0x3C810204,0x3C008081,0x3B804020,0x3B002008,0x3A801002,0x3A000801, + }; + static float *valueFloat = (float *)valueInt; + static float *scaleFloat = (float *)scaleInt; + int v = data->GetBit(3); + if (v >= 6) { + for (unsigned int i = 0; iGetBit(6); + } + else if (v) { + int v1 = data->GetBit(6), v2 = (1 << v) - 1, v3 = v2 >> 1, v4; + value[0] = v1; + for (unsigned int i = 1; iGetBit(v); + if (v4 != v2) { v1 += v4 - v3; } + else { v1 = data->GetBit(6); } + value[i] = v1; + } + } + else { + memset(value, 0, 0x80); + } + if (type == 2) { + v = data->CheckBit(4); value2[0] = v; + if (v<15)for (int i = 0; i<8; i++)value2[i] = data->GetBit(4); + } + else { + for (unsigned int i = 0; iGetBit(6); + } + for (unsigned int i = 0; i> 8) - ((v * 5) /2) + 1; + if (v<0)v = 15; + else if (v >= 0x39)v = 1; + else v = scalelist[v]; + } + scale[i] = v; + } + memset(&scale[count], 0, 0x80 - count); + for (unsigned int i = 0; iGetBit(bitSize); + if (s<8) { + v += s << 4; + data->AddBit(list2[v] - bitSize); + f = list3[v]; + } + else { + v = (1 - ((v & 1) << 1))*(v /2); + if (!v)data->AddBit(-1); + f = (float)v; + } + block[i] = base[i] * f; + } + memset(&block[count], 0, sizeof(float)*(0x80 - count)); +} + +void clHCA::stChannel::Decode3(unsigned int a, unsigned int b, unsigned int c, unsigned int d) { + if (type != 2 && b>0) { + static unsigned int listInt[2][0x40] = { + { + 0x00000000,0x00000000,0x32A0B051,0x32D61B5E,0x330EA43A,0x333E0F68,0x337D3E0C,0x33A8B6D5, + 0x33E0CCDF,0x3415C3FF,0x34478D75,0x3484F1F6,0x34B123F6,0x34EC0719,0x351D3EDA,0x355184DF, + 0x358B95C2,0x35B9FCD2,0x35F7D0DF,0x36251958,0x365BFBB8,0x36928E72,0x36C346CD,0x370218AF, + 0x372D583F,0x3766F85B,0x3799E046,0x37CD078C,0x3808980F,0x38360094,0x38728177,0x38A18FAF, + 0x38D744FD,0x390F6A81,0x393F179A,0x397E9E11,0x39A9A15B,0x39E2055B,0x3A16942D,0x3A48A2D8, + 0x3A85AAC3,0x3AB21A32,0x3AED4F30,0x3B1E196E,0x3B52A81E,0x3B8C57CA,0x3BBAFF5B,0x3BF9295A, + 0x3C25FED7,0x3C5D2D82,0x3C935A2B,0x3CC4563F,0x3D02CD87,0x3D2E4934,0x3D68396A,0x3D9AB62B, + 0x3DCE248C,0x3E0955EE,0x3E36FD92,0x3E73D290,0x3EA27043,0x3ED87039,0x3F1031DC,0x3F40213B, + },{ + 0x3F800000,0x3FAA8D26,0x3FE33F89,0x4017657D,0x4049B9BE,0x40866491,0x40B311C4,0x40EE9910, + 0x411EF532,0x4153CCF1,0x418D1ADF,0x41BC034A,0x41FA83B3,0x4226E595,0x425E60F5,0x429426FF, + 0x42C5672A,0x43038359,0x432F3B79,0x43697C38,0x439B8D3A,0x43CF4319,0x440A14D5,0x4437FBF0, + 0x4475257D,0x44A3520F,0x44D99D16,0x4510FA4D,0x45412C4D,0x4580B1ED,0x45AB7A3A,0x45E47B6D, + 0x461837F0,0x464AD226,0x46871F62,0x46B40AAF,0x46EFE4BA,0x471FD228,0x4754F35B,0x478DDF04, + 0x47BD08A4,0x47FBDFED,0x4827CD94,0x485F9613,0x4894F4F0,0x48C67991,0x49043A29,0x49302F0E, + 0x496AC0C7,0x499C6573,0x49D06334,0x4A0AD4C6,0x4A38FBAF,0x4A767A41,0x4AA43516,0x4ADACB94, + 0x4B11C3D3,0x4B4238D2,0x4B8164D2,0x4BAC6897,0x4BE5B907,0x4C190B88,0x4C4BEC15,0x00000000, + } + }; + static float *listFloat = (float *)listInt[1]; + for (unsigned int i = 0; i>= 1) { + float *d1 = d; + float *d2 = &d[count2]; + for (int j = 0; j>= 1, count2 <<= 1) { + float *list1Float = (float *)list1Int[i]; + float *list2Float = (float *)list2Int[i]; + float *s1 = s; + float *s2 = &s1[count2]; + float *d1 = d; + float *d2 = &d1[count2 * 2 - 1]; + for (int j = 0; j0 + unsigned short muteHeader; // header no sound part (blockCount * 0x400 + 0x80) + unsigned short muteFooter; // footer no sound sample + }; + struct stCompress { // compress information (require this or decode information) + unsigned int comp; // 'comp' + unsigned short blockSize; // block size (when CBR available?) 8~0xFFFF, 0 is VBR + unsigned char r01; // unknown(1) 0~r02 v2.0 now 1 only + unsigned char r02; // unknown(15) r01~0x1F v2.0 now 15 only + unsigned char r03; // unknown(1)(1) + unsigned char r04; // unknown(1)(0) + unsigned char r05; // unknown(0x80)(0x80) + unsigned char r06; // unknown(0x80)(0x20) + unsigned char r07; // unknown(0)(0x20) + unsigned char r08; // unknown(0)(8) + unsigned char reserve1; + unsigned char reserve2; + }; + struct stDecode { // decode information (require this or compress information) + unsigned int dec; // 'dec' + unsigned short blockSize; // block size (when CBR available?) 8~0xFFFF, 0 is VBR + unsigned char r01; // unknown(1) 0~r02 v2.0 now 1 only + unsigned char r02; // unknown(15) r01~0x1F v2.0 now 15 only + unsigned char count1; // type0 and type1 count - 1 + unsigned char count2; // type2 count - 1 + unsigned char r03 : 4; // unknown(0) + unsigned char r04 : 4; // unknown(0) 0 is corrected to 1 + unsigned char enableCount2; // flag of using count2 + }; + struct stVBR { // variable bit rate information (unused?) + unsigned int vbr; // 'vbr' + unsigned short r01; // unknown 0~0x1FF + unsigned short r02; // unknown + }; + struct stATH { // ATH table information (unused from v2.0?) + unsigned int ath; // 'ath' + unsigned short type; // table type (0:all is 0, 1:table 1) + }; + struct stLoop { //loop information + unsigned int loop; // 'loop' + unsigned int start; // loop start block index 0~loopEnd + unsigned int end; // loop end block index loopStart~(stFormat::blockCount-1) + unsigned short count; // loop count, 0x80 is infinite loop + unsigned short r01; // unknown(0x226) + }; + struct stCipher { // cipher table information + unsigned int ciph; // 'ciph' + unsigned short type; // cipher type (0:no 1:no key 0x38:key) + }; + struct stRVA { // relative volume information + unsigned int rva; // 'rva' + float volume; // volume + }; + struct stComment { // comment information + unsigned int comm; // 'comm' + unsigned char len; // comment length? + //char comment[]; + }; + struct stPadding { // padding + unsigned int pad; // 'pad' + }; + unsigned int _version; + unsigned int _dataOffset; + unsigned int _channelCount; + unsigned int _samplingRate; + unsigned int _blockCount; + unsigned int _muteHeader; + unsigned int _muteFooter; + unsigned int _blockSize; + unsigned int _comp_r01; + unsigned int _comp_r02; + unsigned int _comp_r03; + unsigned int _comp_r04; + unsigned int _comp_r05; + unsigned int _comp_r06; + unsigned int _comp_r07; + unsigned int _comp_r08; + unsigned int _comp_r09; + unsigned int _vbr_r01; + unsigned int _vbr_r02; + unsigned int _ath_type; + unsigned int _loopStart; + unsigned int _loopEnd; + unsigned int _loopCount; + unsigned int _loop_r01; + bool _loopFlg; + unsigned int _ciph_type; + unsigned int _ciph_key1; + unsigned int _ciph_key2; + float _rva_volume; + unsigned int _comm_len; + char *_comm_comment; + class clATH { + public: + clATH(); + bool Init(int type, unsigned int key); + unsigned char *GetTable(void); + private: + unsigned char _table[0x80]; + void Init0(void); + void Init1(unsigned int key); + }_ath; + class clCipher { + public: + clCipher(); + bool Init(int type, unsigned int key1, unsigned int key2); + void Mask(void *data, int size); + private: + unsigned char _table[0x100]; + void Init0(void); + void Init1(void); + void Init56(unsigned int key1, unsigned int key2); + void Init56_CreateTable(unsigned char *table, unsigned char key); + }_cipher; + class clData { + public: + clData(void *data, int size); + int CheckBit(int bitSize); + int GetBit(int bitSize); + void AddBit(int bitSize); + private: + unsigned char *_data; + int _size; + int _bit; + }; + struct stChannel { + float block[0x80]; + float base[0x80]; + char value[0x80]; + char scale[0x80]; + char value2[8]; + int type; + char *value3; + unsigned int count; + float wav1[0x80]; + float wav2[0x80]; + float wav3[0x80]; + float wave[8][0x80]; + void Decode1(clData *data, unsigned int a, int b, unsigned char *ath); + void Decode2(clData *data); + void Decode3(unsigned int a, unsigned int b, unsigned int c, unsigned int d); + void Decode4(int index, unsigned int a, unsigned int b, unsigned int c); + void Decode5(int index); + }_channel[0x10]; + bool Decode(void *data, unsigned int size, unsigned int address); + bool DecodeToWavefile_Decode(void *fp1, void *fp2, unsigned int address, unsigned int count, void *data, void (*modeFunction)(float, void*)); + static void DecodeToWavefile_DecodeModeFloat(float f, void *fp); + static void DecodeToWavefile_DecodeMode8bit(float f, void *fp); + static void DecodeToWavefile_DecodeMode16bit(float f, void *fp); + static void DecodeToWavefile_DecodeMode24bit(float f, void *fp); + static void DecodeToWavefile_DecodeMode32bit(float f, void *fp); +}; + +#endif // !__CLHCA_H__ diff --git a/src/download.cpp b/src/download.cpp new file mode 100644 index 0000000..9f25deb --- /dev/null +++ b/src/download.cpp @@ -0,0 +1,226 @@ +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 +#endif + +#include +#include +#include +#include +#include "./download.h" +#pragma comment(lib, "ws2_32.lib") + +using namespace std; + +#define PROGRESS_LENGTH 38 + +long get_file_size (const char* strFileName) { + struct _stat info; + _stat(strFileName, &info); + long size = info.st_size; + return size; +} + +string Int_to_String (int n) { + ostringstream stream; + stream << n; + return stream.str(); +} + +void progress (double local, double current, double max, double speed) { + double p_local = round(local / max * PROGRESS_LENGTH); + double p_current = round(current / max * PROGRESS_LENGTH); + double percent = (local + current) / max * 100; + printf("\r"); + printf("%.2lf / %.2lf MB ", (local + current) / 1024 / 1024, max / 1024 / 1024); + printf("["); + for (int i = 0; i < (int)p_local; i++) { + printf("+"); + } + for (int i = 0; i < (int)p_current/* - 1*/; i++) { + printf("="); + } + printf(">"); + for (int i = 0; i < (int)(PROGRESS_LENGTH - p_local - p_current); i++) { + printf(" "); + } + printf("] "); + printf("%5.2f%% ", percent); + printf("%7.2lf KB/s", speed / 1024); + printf(" \b\b\b"); +} + +void progress (double current, double max) { + double p_current = floor(current / max * PROGRESS_LENGTH); + double percent = current / max * 100; + printf("Completed: %.0lf / %.0lf ", current, max); + printf("["); + for (int i = 0; i < (int)p_current - 1; i++) { + printf("="); + } + printf(">"); + for (int i = 0; i < (int)(PROGRESS_LENGTH - p_current); i++) { + printf(" "); + } + printf("] "); + printf("%5.2f%% ", percent); + printf(" \b\b\b"); +} + +const int BuffSize = 1024; + +void download (string url, string path) { + + size_t protocol = url.find("//") + 2; + string hostname = url.substr(protocol, url.substr(protocol).find_first_of('/')); + + string route = url.substr(protocol).substr(url.substr(protocol).find_first_of('/')); + + long size = get_file_size(path.c_str()); + + WSADATA WsaData; + if (WSAStartup(MAKEWORD(2, 2), &WsaData)) { + printf("Init failed.\n"); + return; + } + + SOCKET sockeId; + SOCKADDR_IN addr; + hostent *remoteHost; + remoteHost = gethostbyname(hostname.c_str()); + + if (-1 == (sockeId = socket(AF_INET, SOCK_STREAM, 0))) { + printf("Create socket failed.\n"); + return; + } + + addr.sin_addr.S_un.S_addr = *((unsigned long *)*remoteHost->h_addr_list); //inet_addr("104.116.243.18") + addr.sin_family = AF_INET; + addr.sin_port = htons(80); + + if (SOCKET_ERROR == connect(sockeId, (SOCKADDR *)&addr, sizeof(addr))) { + printf("Connect server failed.\n"); + closesocket(sockeId); + WSACleanup(); + return; + } + + char* pReqHead = new char[BuffSize]; + pReqHead[0] = '\0'; + + strcat(pReqHead, "GET "); + strcat(pReqHead, route.c_str()); + strcat(pReqHead, " HTTP/1.1\r\n"); + + string hosthead = "Host: " + hostname + "\r\n"; + + strcat(pReqHead, hosthead.c_str()); + strcat(pReqHead, "Accept: */*\r\n"); + strcat(pReqHead, "Connection: Keep-Alive\r\n"); + strcat(pReqHead, "User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; Nexus 42 Build/XYZZ1Y)\r\n"); + strcat(pReqHead, "X-Unity-Version: 5.4.5p1\r\n"); + strcat(pReqHead, "Accept-Encoding: gzip\r\n"); + if (size != 0) { + string range = "Range: bytes=" + Int_to_String(size) + "-\r\n"; + strcat(pReqHead, range.c_str()); + } + strcat(pReqHead, "\r\n"); + + if (SOCKET_ERROR == send(sockeId, pReqHead, (int)strlen(pReqHead), 0)) { + printf("Send data failed.\n"); + closesocket(sockeId); + WSACleanup(); + delete pReqHead; + return; + } + + delete pReqHead; + + FILE *fp; + fp = fopen(path.c_str(), "ab+"); + + if (NULL == fp) { + printf("Create file failed.\n"); + closesocket(sockeId); + WSACleanup(); + return; + } + + char* buff = (char*)malloc(BuffSize * sizeof(char)); + memset(buff, '\0', BuffSize); + int iRec = 1; + bool bStart = false; + int chars = 0; + + string str; + while (!bStart) { + iRec = recv(sockeId, buff, 1, 0); + str += *buff; + if (iRec < 0) { + bStart = true; + } + switch (*buff) + { + case '\r': + break; + case '\n': + if (chars == 0) { + bStart = true; + } + chars = 0; + break; + default: + chars++; + break; + } + } + + int length = -1; + if (str.find("Content-Length: ") != str.npos) { + string contentlength1 = str.substr(str.find("Content-Length: ")); + string contentlength2 = contentlength1.substr(0, contentlength1.find_first_of('\r')); + string contentlength3 = contentlength2.substr(16); + length = atoi(contentlength3.c_str()); + } + else { + printf("Download faild.\n"); + return; + } + + if (size == length && str.find("Content-Range") == str.npos) { + printf("File exists.\n"); + } + else { + int sum = 0; + int speed = 0; + double start_time = clock(); + double end_time = 0; + int last_time = 0; + do { + iRec = recv(sockeId, buff, BuffSize, 0); + if (iRec < 0) { + break; + } + sum += iRec; + speed += iRec; + int now = clock(); + if (now - last_time > 500) { + progress(size, sum, length + size, speed * 2); + last_time = now; + speed = 0; + } + + fwrite(buff, iRec, 1, fp); + if (sum == length) { + end_time = clock(); + progress(size, sum, length + size, (double)sum / ((end_time - start_time) / 1000)); + closesocket(sockeId); + WSACleanup(); + break; + } + } while (iRec > 0); + } + + fclose(fp); + free(buff); + printf("\n\n"); +} diff --git a/src/download.h b/src/download.h new file mode 100644 index 0000000..992323b --- /dev/null +++ b/src/download.h @@ -0,0 +1,16 @@ +#ifndef __DOWNLOAD_H__ +#define __DOWNLOAD_H__ + +#include + +long get_file_size (const char*); + +std::string Int_to_String (int); + +void progress (double local, double current, double max, double speed); + +void progress (double current, double max); + +void download (std::string url, std::string path); + +#endif // !__DOWNLOAD_H__ diff --git a/src/lz4.cpp b/src/lz4.cpp new file mode 100644 index 0000000..0ef5c01 --- /dev/null +++ b/src/lz4.cpp @@ -0,0 +1,140 @@ +#include +#include +#include "./lz4.h" + +using namespace std; + +vector readFile (string filename) { + ifstream file(filename, ios::binary); + + file.unsetf(ios::skipws); + + streampos fileSize; + + file.seekg(0, ios::end); + fileSize = file.tellg(); + file.seekg(0, ios::beg); + + vector vec; + vec.reserve(fileSize); + + vec.insert( + vec.begin(), + istream_iterator(file), + istream_iterator() + ); + + return vec; +} + +BinaryReader::BinaryReader (vector &array) { + ary = array; + curPos = 0; +} + +int BinaryReader::readByte () { + curPos++; + return ary[curPos - 1]; +} + +int BinaryReader::readShortLE () { + curPos += 2; + return ary[curPos - 2] + (ary[curPos - 1] << 8); +} + +int BinaryReader::readIntLE () { + curPos += 4; + return ary[curPos - 4] + (ary[curPos - 3] << 8) + (ary[curPos - 2] << 16) + (ary[curPos - 1] << 24); +} + +vector& BinaryReader::copyBytes (vector &dst, int &offset, int &size) { + curPos += size; + copy(ary.begin() + curPos - size, ary.begin() + curPos, dst.begin() + offset); + return dst; +} + +void BinaryReader::seekAbs (int pos) { + curPos = pos; +} + +void BinaryReader::seekRel (int diff) { + curPos += diff; +} + +int BinaryReader::getPos () { + return curPos; +} + +vector LZ4Decompressor::decompress (vector &array) { + BinaryReader r(array); + vector retArray; + int dataSize = 0; + int decompressedSize = 0; + + int token = 0; + int sqSize = 0; + int matchSize = 0; + int litPos = 0; + int offset = 0; + int retCurPos = 0; + int endPos = 0; + + r.seekAbs(4); + decompressedSize = r.readIntLE(); + dataSize = r.readIntLE(); + endPos = dataSize + 16; + retArray = vector(decompressedSize); + + r.seekAbs(16); + + while (true) { + token = r.readByte(); + sqSize = token >> 4; + matchSize = (token & 0x0f) + 4; + if (sqSize == 15) { + sqSize += readAdditionalSize(r); + } + + retArray = r.copyBytes(retArray, retCurPos, sqSize); + retCurPos += sqSize; + + if (r.getPos() >= endPos - 1) { + break; + } + + offset = r.readShortLE(); + + if (matchSize == 19) { + matchSize += readAdditionalSize(r); + } + + if (matchSize > offset) { + int matchPos = retCurPos - offset; + while (true) { + copy(retArray.begin() + matchPos, retArray.begin() + matchPos + offset, retArray.begin() + retCurPos); + retCurPos += offset; + matchSize -= offset; + if (matchSize < offset) { + break; + } + } + } + copy(retArray.begin() + retCurPos - offset, retArray.begin() + retCurPos - offset + matchSize, retArray.begin() + retCurPos); + retCurPos += matchSize; + } + return retArray; +} + +int LZ4Decompressor::readAdditionalSize (BinaryReader &reader) { + uint8_t size = reader.readByte(); + return size == 255 ? size + readAdditionalSize(reader) : size; +} + +void lz4dec (string filePath, string type) { + LZ4Decompressor lz4; + vector vec = readFile(filePath); + vector outBuffer = lz4.decompress(vec); + + ofstream output(filePath + "." + type, ios::binary); + output.write((char *)&outBuffer[0], outBuffer.size()); +} diff --git a/src/lz4.h b/src/lz4.h new file mode 100644 index 0000000..9a2c9d8 --- /dev/null +++ b/src/lz4.h @@ -0,0 +1,32 @@ +#ifndef __LZ4_H__ +#define __LZ4_H__ + +#include +#include + +std::vector readFile (std::string); + +class BinaryReader { +private: + std::vector ary; + int curPos; +public: + BinaryReader (std::vector&); + int readByte (); + int readShortLE (); + int readIntLE (); + std::vector& copyBytes (std::vector&, int&, int&); + void seekAbs (int); + void seekRel (int); + int getPos (); +}; + +class LZ4Decompressor { +public: + std::vector decompress (std::vector&); + int readAdditionalSize (BinaryReader&); +}; + +void lz4dec (std::string, std::string); + +#endif // !__LZ4_H__ diff --git a/src/sqlite3/README.md b/src/sqlite3/README.md new file mode 100644 index 0000000..9d58280 --- /dev/null +++ b/src/sqlite3/README.md @@ -0,0 +1,5 @@ +# ACBExtractor + +## Download + +https://www.sqlite.org/download.html diff --git a/vcbuild.bat b/vcbuild.bat new file mode 100644 index 0000000..e0c95c0 --- /dev/null +++ b/vcbuild.bat @@ -0,0 +1,76 @@ +@echo off + +set arch=%1 +set mode=%2 +set workspaceFolder=%3 +set targetName=%4 + +set compilerFlags= +set linkFlags= +set buildDir=build\%arch%\%mode% +set files= + +set preDefine=/D "_MBCS" /D "_CRT_SECURE_NO_DEPRECATE" + +set commonCompilerFlags=/permissive- /GS /W3 /Zc:wchar_t /Gm- /Zc:inline /sdl /Fd"%buildDir%\vc141.pdb" /fp:precise %preDefine% /errorReport:prompt /WX- /Zc:forScope /Gd /FC /Fa"%buildDir%/" /EHsc /nologo /Fo"%buildDir%/" /Fp"%buildDir%\%targetName%.pch" /diagnostics:classic + +set linkLib="kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" + +set commonLinkFlags=/OUT:"%workspaceFolder%\%buildDir%\%targetName%.exe" /MANIFEST /NXCOMPAT /PDB:"%workspaceFolder%\%buildDir%\%targetName%.pdb" /DYNAMICBASE + +set commonLinkFlags2=/MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"%buildDir%\%targetName%.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 + +if /i "%arch%"=="x64" ( + call "%VS_ROOT%\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + if /i "%mode%"=="Debug" goto debug-x64 + if /i "%mode%"=="Release" goto release-x64 +) + +if /i "%arch%"=="x86" ( + call "%VS_ROOT%\2017\Community\VC\Auxiliary\Build\vcvars32.bat" + if /i "%mode%"=="Debug" goto debug-x86 + if /i "%mode%"=="Release" goto release-x86 +) + +:debug-x64 +set compilerFlags=%commonCompilerFlags% /JMC /ZI /Od /RTC1 /MDd +set linkFlags=%commonLinkFlags% %linkLib% %commonLinkFlags2% /DEBUG:FASTLINK /INCREMENTAL /MACHINE:X64 +goto var-done + +:release-x64 +set compilerFlags=%commonCompilerFlags% /GL /Gy /Zi /O2 /Oi /MT +set linkFlags=%commonLinkFlags% /LTCG:incremental %linkLib% %commonLinkFlags2% /DEBUG:FULL /OPT:REF /OPT:ICF /MACHINE:X64 +goto var-done + +:debug-x86 +set compilerFlags=%commonCompilerFlags% /JMC /analyze- /ZI /Od /RTC1 /Oy- /MDd +set linkFlags=%commonLinkFlags% %linkLib% %commonLinkFlags2% /DEBUG:FASTLINK /INCREMENTAL /MACHINE:X86 +goto var-done + +:release-x86 +set compilerFlags=%commonCompilerFlags% /GL /analyze- /Gy /Zi /O2 /Oy- /Oi /MT +set linkFlags=%commonLinkFlags% /LTCG:incremental %linkLib% %commonLinkFlags2% /DEBUG:FULL /OPT:REF /SAFESEH /OPT:ICF /MACHINE:X86 +goto var-done + +:var-done +goto next-arg + +:next-arg +if /i "%5"=="" ( + goto args-done +) else ( + set files=%5 %files% + goto arg-ok +) + +:arg-ok +shift +goto next-arg + +:args-done +REM if exist %buildDir% rd /S /Q %buildDir% +if not exist %buildDir% mkdir %buildDir% +echo %buildDir% +echo cl %compilerFlags% %files% /link %linkFlags% +echo= +cl %compilerFlags% %files% /link %linkFlags%