From 8ec2eeeaec32fcfe1d4e25439ff6d70e9a92d138 Mon Sep 17 00:00:00 2001 From: George Wu Date: Thu, 16 Apr 2020 12:15:37 +0200 Subject: [PATCH] Fixed 'use cue name' behavior and used smarter naming --- src/apps/acb2hcas/acb2hcas.cpp | 22 ++--- src/apps/acb2wavs/acb2wavs.cpp | 25 +++--- src/apps/acbunpack/acbunpack.cpp | 148 +++++++++++-------------------- src/apps/common/acbextract.cpp | 30 ++++--- src/apps/common/utils.cpp | 6 +- src/apps/common/utils.h | 1 + src/lib/ichinose/CAcbFile.cpp | 43 ++++++++- src/lib/ichinose/CAcbFile.h | 6 ++ 8 files changed, 142 insertions(+), 139 deletions(-) diff --git a/src/apps/acb2hcas/acb2hcas.cpp b/src/apps/acb2hcas/acb2hcas.cpp index 0466e35..92a48cb 100644 --- a/src/apps/acb2hcas/acb2hcas.cpp +++ b/src/apps/acb2hcas/acb2hcas.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -24,7 +23,7 @@ struct Acb2HcasOptions { static void PrintHelp(); -static int ParseArgs(int argc, const char *argv[], const char **input, Acb2HcasOptions &options); +static int ParseArgs(int argc, const char *argv[], string &inputFile, Acb2HcasOptions &options); static int DoWork(const string &inputFile, const Acb2HcasOptions &options); @@ -33,15 +32,10 @@ static int ProcessHca(AcbWalkCallbackParams *params); static void WriteHcaKeyFile(const string &fileName, uint64_t key, uint16_t modifier = 0); int main(int argc, const char *argv[]) { - if (argc < 2) { - PrintHelp(); - return 0; - } - - const char *inputFile; + string inputFile; Acb2HcasOptions options = {0}; - const auto parsed = ParseArgs(argc, argv, &inputFile, options); + const auto parsed = ParseArgs(argc, argv, inputFile, options); if (parsed < 0) { return 0; @@ -49,6 +43,11 @@ int main(int argc, const char *argv[]) { return parsed; } + if (!cgssHelperFileExists(inputFile.c_str())) { + fprintf(stderr, "File '%s' does not exist or cannot be opened.\n", inputFile.c_str()); + return -1; + } + return DoWork(inputFile, options); } @@ -61,13 +60,13 @@ static void PrintHelp() { cout << "\t-n\tUse cue names for output waveforms" << endl; } -static int ParseArgs(int argc, const char *argv[], const char **input, Acb2HcasOptions &options) { +static int ParseArgs(int argc, const char *argv[], string &inputFile, Acb2HcasOptions &options) { if (argc < 2) { PrintHelp(); return -1; } - *input = argv[1]; + inputFile = argv[1]; for (int i = 2; i < argc; ++i) { if (argv[i][0] == '-' || argv[i][0] == '/') { @@ -91,6 +90,7 @@ static int ParseArgs(int argc, const char *argv[], const char **input, Acb2HcasO options.useCueName = TRUE; break; default: + fprintf(stderr, "Unknown option: %s\n", argv[i]); return 2; } } diff --git a/src/apps/acb2wavs/acb2wavs.cpp b/src/apps/acb2wavs/acb2wavs.cpp index 5a988e7..29e91f2 100644 --- a/src/apps/acb2wavs/acb2wavs.cpp +++ b/src/apps/acb2wavs/acb2wavs.cpp @@ -8,8 +8,8 @@ #include "../common/common.h" #include "../common/acbextract.h" -using namespace cgss; using namespace std; +using namespace cgss; struct Acb2WavsOptions { HCA_DECODER_CONFIG decoderConfig; @@ -18,7 +18,7 @@ struct Acb2WavsOptions { static void PrintHelp(); -static int ParseArgs(int argc, const char *argv[], const char **input, Acb2WavsOptions &options); +static int ParseArgs(int argc, const char *argv[], string &inputFile, Acb2WavsOptions &options); static int DoWork(const string &inputFile, const Acb2WavsOptions &options); @@ -27,15 +27,10 @@ static int ProcessHca(AcbWalkCallbackParams *params); static int DecodeHca(IStream *hcaDataStream, IStream *waveStream, const HCA_DECODER_CONFIG &dc); int main(int argc, const char *argv[]) { - if (argc < 2) { - PrintHelp(); - return 0; - } - - const char *inputFile; + string inputFile; Acb2WavsOptions options = {0}; - const auto parsed = ParseArgs(argc, argv, &inputFile, options); + const auto parsed = ParseArgs(argc, argv, inputFile, options); if (parsed < 0) { return 0; @@ -43,6 +38,11 @@ int main(int argc, const char *argv[]) { return parsed; } + if (!cgssHelperFileExists(inputFile.c_str())) { + fprintf(stderr, "File '%s' does not exist or cannot be opened.\n", inputFile.c_str()); + return -1; + } + return DoWork(inputFile, options); } @@ -52,13 +52,13 @@ static void PrintHelp() { cout << "\t-n\tUse cue names for output waveforms" << endl; } -static int ParseArgs(int argc, const char *argv[], const char **input, Acb2WavsOptions &options) { +static int ParseArgs(int argc, const char *argv[], string &inputFile, Acb2WavsOptions &options) { if (argc < 2) { PrintHelp(); return -1; } - *input = argv[1]; + inputFile = argv[1]; options.decoderConfig.waveHeaderEnabled = TRUE; options.decoderConfig.decodeFunc = CDefaultWaveGenerator::Decode16BitS; @@ -82,6 +82,7 @@ static int ParseArgs(int argc, const char *argv[], const char **input, Acb2WavsO options.useCueName = TRUE; break; default: + fprintf(stderr, "Unknown option: %s\n", argv[i]); return 2; } } @@ -113,7 +114,7 @@ static int ProcessHca(AcbWalkCallbackParams *params) { HCA_DECODER_CONFIG decoderConfig = params->walkOptions->decoderConfig; const string extractFilePath = common_utils::ReplaceAnyExtension(params->extractPathHint, ".wav"); - fprintf(stdout, "Decoding to %s...\n", extractFilePath.c_str()); + fprintf(stdout, ": decoding to %s...\n", extractFilePath.c_str()); try { CFileStream fs(extractFilePath.c_str(), FileMode::Create, FileAccess::Write); diff --git a/src/apps/acbunpack/acbunpack.cpp b/src/apps/acbunpack/acbunpack.cpp index 79dfbac..ece7b47 100644 --- a/src/apps/acbunpack/acbunpack.cpp +++ b/src/apps/acbunpack/acbunpack.cpp @@ -1,139 +1,91 @@ #include -#include -#include -#include - -#if defined(_WIN32) || defined(WIN32) - -#define WIN32_LEAN_AND_MEAN - -#include - -#else -#include -#include -#endif +#include #include "../../lib/cgss_api.h" #include "../common/common.h" #include "../common/acbextract.h" +using namespace std; using namespace cgss; -static void print_help(); +struct AcbUnpackOptions { + bool_t useCueName; +}; -static void MakeDirectories(const std::string &s); +static void PrintHelp(); -static std::string GetDirectoryFromPath(const std::string &s); +static int ParseArgs(int argc, const char *argv[], string &inputFile, AcbUnpackOptions &options); -static std::string GetFileNameFromPath(const std::string &s); +static int DoWork(const string &inputFile, const AcbUnpackOptions &options); static int ExtractFile(AcbWalkCallbackParams *params); int main(int argc, const char *argv[]) { - if (argc == 1) { - print_help(); + string inputFile; + AcbUnpackOptions options = {0}; + + const auto parsed = ParseArgs(argc, argv, inputFile, options); + + if (parsed < 0) { return 0; + } else if (parsed > 0) { + return parsed; } - const char *filePath = argv[1]; - - if (!cgssHelperFileExists(filePath)) { - fprintf(stderr, "File '%s' does not exist or cannot be opened.\n", filePath); + if (!cgssHelperFileExists(inputFile.c_str())) { + fprintf(stderr, "File '%s' does not exist or cannot be opened.\n", inputFile.c_str()); return -1; } - AcbWalkOptions options; - options.useCueName = true; - options.callback = ExtractFile; + return DoWork(inputFile, options); +} - const auto r = AcbWalk(filePath, &options); +static int DoWork(const string &inputFile, const AcbUnpackOptions &options) { + AcbWalkOptions o; + o.useCueName = options.useCueName; + o.callback = ExtractFile; - return r; + return AcbWalk(inputFile, &o); } static int ExtractFile(AcbWalkCallbackParams *params) { + fprintf(stdout, "Unpacking: %s\n", params->extractPathHint.c_str()); + CFileStream fs(params->extractPathHint.c_str(), FileMode::Create, FileAccess::Write); common_utils::CopyStream(params->entryDataStream, &fs); return 0; } -static void print_help() { - fprintf(stderr, "Usage:\n\n\tacbunpack \n"); -} - -static std::string GetDirectoryFromPath(const std::string &s) { - const char sep1 = '/', sep2 = '\\'; - - size_t i1 = s.rfind(sep1, s.length()); - size_t i2 = s.rfind(sep2, s.length()); - - if (i1 != std::string::npos) { - if (i2 != std::string::npos) { - auto i = i1 > i2 ? i1 : i2; - return (s.substr(0, i)); - } else { - return (s.substr(0, i1)); - } - } else { - if (i2 != std::string::npos) { - return (s.substr(0, i2)); - } else { - return std::string(""); - } - } +static void PrintHelp() { + static const char *helpMessage = "Usage:\n" + "\n" + "\tacbunpack [-n]\n" + "\n" + "\t-n Use cue names for output waveforms\n"; + fprintf(stderr, "%s", helpMessage); } -static std::string GetFileNameFromPath(const std::string &s) { - const char sep1 = '/', sep2 = '\\'; - - size_t i1 = s.rfind(sep1, s.length()); - size_t i2 = s.rfind(sep2, s.length()); - - if (i1 != std::string::npos) { - if (i2 != std::string::npos) { - auto i = i1 > i2 ? i1 : i2; - return (s.substr(i + 1)); - } else { - return (s.substr(i1 + 1)); - } - } else { - if (i2 != std::string::npos) { - return (s.substr(i2 + 1)); - } else { - return std::string(""); - } +static int ParseArgs(int argc, const char *argv[], string &inputFile, AcbUnpackOptions &options) { + if (argc < 2) { + PrintHelp(); + return -1; } -} -#if defined(WIN32) || defined(_WIN32) - -static void MakeDirectories(const std::string &s) { - CreateDirectory(s.c_str(), nullptr); -} - -#else - -static void MakeDirectories(const std::string &s) { - char str[512] = {0}; - - strncpy(str, s.c_str(), 512); - auto len = strlen(str); - - for (auto i = 0; i < len; i++) { - if (str[i] == '/') { - str[i] = '\0'; - if (access(str, 0) != 0) { - mkdir(str, 0777); + inputFile = argv[1]; + + for (int i = 2; i < argc; ++i) { + if (argv[i][0] == '-' || argv[i][0] == '/') { + switch (argv[i][1]) { + case 'n': + options.useCueName = TRUE; + break; + default: + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return 2; } - str[i] = '/'; } } - if (len > 0 && access(str, 0) != 0) { - mkdir(str, 0777); - } + return 0; } - -#endif diff --git a/src/apps/common/acbextract.cpp b/src/apps/common/acbextract.cpp index 507295d..617285b 100644 --- a/src/apps/common/acbextract.cpp +++ b/src/apps/common/acbextract.cpp @@ -28,8 +28,8 @@ int AcbWalk(const std::string &inputAcbFile, AcbWalkOptions *options) { acb.Initialize(); - CAfs2Archive *archive = nullptr; - uint32_t formatVersion = acb.GetFormatVersion(); + CAfs2Archive *archive; + const uint32_t formatVersion = acb.GetFormatVersion(); int r; try { @@ -90,7 +90,7 @@ int AcbWalk(const std::string &inputAcbFile, AcbWalkOptions *options) { static int ProcessAllBinaries(CAcbFile &acb, uint32_t formatVersion, AcbWalkOptions *options, const string &extractDir, CAfs2Archive *archive, IStream *archiveDataStream, bool_t isInternal, unordered_set &extractedCueIds) { if (!CFileSystem::DirectoryExists(extractDir)) { if (!CFileSystem::MkDir(extractDir)) { - fprintf(stderr, "Failed to create directory %s.\n", extractDir.c_str()); + fprintf(stderr, "Failed to create directory '%s.\n", extractDir.c_str()); return -1; } } @@ -121,22 +121,30 @@ static int ProcessAllBinaries(CAcbFile &acb, uint32_t formatVersion, AcbWalkOpti const auto &fileNames = acb.GetFileNames(); uint32_t i = 0; - for (const auto &extractFileName : fileNames) { - if (extractFileName.empty()) { + for (const auto &fileName : fileNames) { + if (fileName.empty()) { continue; } - p.extractPathHint = CPath::Combine(extractDir, extractFileName); - - auto entryDataStream = acb.OpenDataStream(extractFileName.c_str()); + auto entryDataStream = acb.OpenDataStream(fileName.c_str()); if (entryDataStream) { p.entryDataStream = entryDataStream; - const auto fileRecord = acb.GetFileRecord(extractFileName.c_str()); + const auto fileRecord = acb.GetFileRecord(fileName.c_str()); assert(fileRecord != nullptr); + string extractFileName; + + if (options->useCueName) { + extractFileName = fileName; + } else { + extractFileName = acb.GetSymbolicFileNameHintFromCueId(fileRecord->cueId); + } + + p.extractPathHint = CPath::Combine(extractDir, extractFileName); + p.cueInfo.id = fileRecord->cueId; p.cueInfo.offset = fileRecord->fileOffsetAligned; p.cueInfo.size = fileRecord->fileSize; @@ -145,7 +153,7 @@ static int ProcessAllBinaries(CAcbFile &acb, uint32_t formatVersion, AcbWalkOpti extractedCueIds.insert(fileRecord->cueId); } else { - fprintf(stderr, "Cue #%" PRIu32 " (%s) cannot be retrieved.\n", i + 1, extractFileName.c_str()); + fprintf(stderr, "Cue #%" PRIu32 " (%s) cannot be retrieved.\n", i + 1, fileName.c_str()); } ++i; @@ -172,7 +180,7 @@ static int ProcessAllBinaries(CAcbFile &acb, uint32_t formatVersion, AcbWalkOpti if (options->useCueName) { extractFileName = acb.GetCueNameFromCueId(record.cueId); } else { - extractFileName = CAcbFile::GetSymbolicFileNameFromCueId(record.cueId); + extractFileName = acb.GetSymbolicFileNameHintFromCueId(record.cueId); } auto entryDataStream = CAcbHelper::ExtractToNewStream(archiveDataStream, record.fileOffsetAligned, (uint32_t)record.fileSize); diff --git a/src/apps/common/utils.cpp b/src/apps/common/utils.cpp index 660c58a..5f8144e 100644 --- a/src/apps/common/utils.cpp +++ b/src/apps/common/utils.cpp @@ -25,12 +25,12 @@ string common_utils::ReplaceExtension(const string &s, const string &oldExt, con auto extl = oldExt; // ALERT! - // Since the only usage here is replacing extensions, and we promise that the + // Since the only usage here is replacing extensions, and we guarantee that the // extensions are in ASCII, and we don't care about chars before the extension, // we can use this method (tolower()). Otherwise, it causes trouble for non- // ASCII encodings. - std::transform(sl.begin(), sl.end(), sl.begin(), ::tolower); - std::transform(extl.begin(), extl.end(), extl.begin(), ::tolower); + std::transform(sl.begin(), sl.end(), sl.begin(), std::tolower); + std::transform(extl.begin(), extl.end(), extl.begin(), std::tolower); if (!hasEnding(sl, extl)) { return s; diff --git a/src/apps/common/utils.h b/src/apps/common/utils.h index baf19dc..92c687c 100644 --- a/src/apps/common/utils.h +++ b/src/apps/common/utils.h @@ -25,6 +25,7 @@ namespace cgss { public: + [[deprecated]] static std::string ReplaceExtension(const std::string &s, const std::string &oldExt, const std::string &newExt); static std::string ReplaceAnyExtension(const std::string &s, const std::string &newExt); diff --git a/src/lib/ichinose/CAcbFile.cpp b/src/lib/ichinose/CAcbFile.cpp index 2b96ee7..a0713bc 100644 --- a/src/lib/ichinose/CAcbFile.cpp +++ b/src/lib/ichinose/CAcbFile.cpp @@ -17,6 +17,8 @@ using namespace cgss; using namespace std; +#define DEFAULT_BINARY_FILE_EXTENSION ".bin" + static string GetExtensionForEncodeType(uint8_t encodeType); template @@ -290,9 +292,20 @@ const char *CAcbFile::GetFileName() const { } string CAcbFile::GetSymbolicFileNameFromCueId(uint32_t cueId) { - char buffer[40] = {0}; + char buffer[256] = {0}; - sprintf(buffer, "cue_%06" PRIu32 ".bin", cueId); + sprintf(buffer, "cue_%06" PRIu32 DEFAULT_BINARY_FILE_EXTENSION, cueId); + + return string(buffer); +} + +string CAcbFile::GetSymbolicFileNameHintFromCueId(uint32_t cueId) { + char buffer[256] = {0}; + + const auto extHint = GetFileExtensionHint(cueId); + const auto ext = extHint.empty() ? DEFAULT_BINARY_FILE_EXTENSION : extHint.c_str(); + + sprintf(buffer, "cue_%06" PRIu32 "%s", cueId, ext); return string(buffer); } @@ -304,7 +317,7 @@ string CAcbFile::GetCueNameFromCueId(uint32_t cueId) { } } - return GetSymbolicFileNameFromCueId(cueId); + return GetSymbolicFileNameHintFromCueId(cueId); } const ACB_CUE_RECORD *CAcbFile::GetCueRecord(const char *waveformFileName) { @@ -361,6 +374,26 @@ uint32_t CAcbFile::GetFormatVersion() const { return _formatVersion; } +std::string CAcbFile::GetFileExtensionHint(uint32_t cueId) { + const auto cue = GetCueRecord(cueId); + + if (cue == nullptr) { + return std::string(); + } else { + return GetExtensionForEncodeType(cue->encodeType); + } +} + +std::string CAcbFile::GetFileExtensionHint(const char *waveformFileName) { + const auto cue = GetCueRecord(waveformFileName); + + if (cue == nullptr) { + return std::string(); + } else { + return GetExtensionForEncodeType(cue->encodeType); + } +} + std::string CAcbFile::FindExternalAwbFileName() { const string acbFileName = _fileName; const auto awbDirPath = CPath::GetDirectoryName(acbFileName); @@ -462,10 +495,12 @@ static string GetExtensionForEncodeType(uint8_t encodeType) { return ".bcwav"; case CGSS_ACB_WAVEFORM_NINTENDO_DSP: return ".dsp"; + default: + break; } char buffer[20] = {0}; - sprintf(buffer, ".et-%d.bin", static_cast(encodeType)); + sprintf(buffer, ".et-%" PRId32 DEFAULT_BINARY_FILE_EXTENSION, static_cast(encodeType)); return string(buffer); } diff --git a/src/lib/ichinose/CAcbFile.h b/src/lib/ichinose/CAcbFile.h index 9fee03e..0cbd8ea 100644 --- a/src/lib/ichinose/CAcbFile.h +++ b/src/lib/ichinose/CAcbFile.h @@ -34,6 +34,8 @@ CGSS_NS_BEGIN static std::string GetSymbolicFileNameFromCueId(uint32_t cueId); + std::string GetSymbolicFileNameHintFromCueId(uint32_t cueId); + std::string GetCueNameFromCueId(uint32_t cueId); const ACB_CUE_RECORD *GetCueRecord(const char *waveformFileName); @@ -54,6 +56,10 @@ CGSS_NS_BEGIN uint32_t GetFormatVersion() const; + std::string GetFileExtensionHint(uint32_t cueId); + + std::string GetFileExtensionHint(const char *waveformFileName); + static const uint32_t KEY_MODIFIER_ENABLED_VERSION; private: