From 1398b8f816549dedf03b8892bd474b1154dcb7ba Mon Sep 17 00:00:00 2001 From: modeco80 Date: Wed, 7 Jun 2023 23:04:33 -0400 Subject: [PATCH] Add HashTool This is probably my last addition to the C++ version of this code, at least if an Experimental ~~Rodeo~~ Rewrite doesn't end up panning out. This is a tool for generating the HashID values that the game uses. Maybe later on I might try and see if I can write a multi-threaded hash cracker, or better yet, a GPU powered one (no better way to try and learn GPGPU then actually doing it!), but for now, this is all you get. Feel free to lavish in my argument parsing implementation. I just wanted something simple and fairly easy to read, and this seems to work ok, while still being platform-independent (no getopt, and I wouldn't need to drag in additional code to reimplement getopt or such for Windows/Mac/...) --- src/tools/CMakeLists.txt | 10 ++- src/tools/jmmt_hashtool.cpp | 125 ++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/tools/jmmt_hashtool.cpp diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 16b6b90..4c03005 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -14,4 +14,12 @@ target_link_libraries(jmmt_pack_extractor PUBLIC jmmt) set_target_properties(jmmt_pack_extractor PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON - ) \ No newline at end of file + ) + +add_executable(jmmt_hashtool jmmt_hashtool.cpp) +target_link_libraries(jmmt_hashtool PUBLIC jmmt) + +set_target_properties(jmmt_hashtool PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + ) diff --git a/src/tools/jmmt_hashtool.cpp b/src/tools/jmmt_hashtool.cpp new file mode 100644 index 0000000..4fb3687 --- /dev/null +++ b/src/tools/jmmt_hashtool.cpp @@ -0,0 +1,125 @@ +// JMMT HashTool + +#include + +#include +#include +#include +#include +#include + +struct Arguments { + enum class OutputMode { + Hex, ///< Hexadecimal output. + Decimal ///< Decimal output. + }; + + char* hashName {}; + bool useCase { false }; + OutputMode outMode { OutputMode::Hex }; + + /** Parse arguments from the main() argv. **/ + static Arguments FromArgv(int argc, char** argv) { + Arguments args; + args.progname = argv[0]; + + // no options provided + if(argc == 1) { + args.DispHelp(); + std::exit(1); + } + + // non-pepper getopt(). I'm too lazy to make it any better though + for(int i = 1; i < argc; ++i) { + if(argv[i][0] == '-' && argv[i][1] != '\0') { + char sw = argv[i][1]; + + switch(sw) { + // flag options + + case 'c': + args.useCase = true; + break; + + case 'd': + if(args.outMode == OutputMode::Hex) + args.outMode = OutputMode::Decimal; + break; + + case 'h': + if(args.outMode == OutputMode::Decimal) + args.outMode = OutputMode::Hex; + break; + + // terminals + case '?': + args.DispHelp(); + std::exit(0); + + default: + std::printf("Unknown command-line switch '-%c'\n", sw); + args.DispHelp(); + std::exit(1); + } + } else { + // Assume any non-positional argument is what we're supposed to hash + args.hashName = argv[i]; + } + } + return args; + } + + bool Validate() const { + if(!hashName) { + std::printf("No hash name provided\n"); + DispHelp(); + return false; + } + return true; + } + + private: + char* progname {}; + + void DispHelp() const { + // no I'm not sorry + std::printf( + // clang-format off + "JMMT HashTool - a thing for generating TECH HashID's\n" + "Usage: %s [-c] [-?] \n" + " -c Use case-senstive HashID variant (default is case-insensitive)\n" + " -d Output in decimal (default hex)\n" + " -h Output as hexadecimal (if previously overridden; kinda pointless)\n" + " -? Show this help message (and exit)\n", + progname + // clang-format on + ); + } +}; + +int main(int argc, char** argv) { + auto args = Arguments::FromArgv(argc, argv); + + if(!args.Validate()) { + return 1; + } + + jmmt::crc32_t result {}; + if(args.useCase) + result = jmmt::HashStringCase(args.hashName); + else + result = jmmt::HashString(args.hashName); + + // clang-format off + using enum Arguments::OutputMode; + switch(args.outMode) { + case Decimal: std::printf("%d\n", result); break; + case Hex: std::printf("0x%08x\n", result); break; +#ifdef __GNUC__ + // Mark this path explicitly as UB + default: __builtin_unreachable(); +#endif + } + // clang-format on + return 0; +}