diff --git a/src/Application.cpp b/src/Application.cpp index 7391ab9..44a12c2 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1354,7 +1354,7 @@ bool Application::unloadGame() if (_gamePathIsTemporary) { - _logger.debug(TAG "Deleting temporary content %s", _gamePath); + _logger.debug(TAG "Deleting temporary content %s", _gamePath.c_str()); util::deleteFile(_gamePath); _gamePathIsTemporary = false; } diff --git a/src/RAHasher.cpp b/src/RAHasher.cpp index 7fb8983..015118d 100644 --- a/src/RAHasher.cpp +++ b/src/RAHasher.cpp @@ -8,8 +8,21 @@ #include #include +#include #include +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include +#elif defined(__unix__) + #include + #include +#else + #include + #include + #include +#endif + #ifdef HAVE_CHD void rc_hash_init_chd_cdreader(); /* in HashCHD.cpp */ #endif @@ -22,7 +35,7 @@ static void usage(const char* appname) printf("\n"); printf(" -v (optional) enables verbose messages for debugging\n"); printf(" systemid specifies the system id associated to the game (which hash algorithm to use)\n"); - printf(" filepath specifies the path to the game file\n"); + printf(" filepath specifies the path to the game file (file may include wildcards, path may not)\n"); } class StdErrLogger : public Logger @@ -70,89 +83,237 @@ static void* rhash_file_open(const char* path) #define RC_CONSOLE_MAX 90 -int main(int argc, char* argv[]) +static int process_file(int consoleId, const std::string& file) { - int consoleId = 0; - std::string file; char hash[33]; int result = 1; - if (argc == 3) + std::string filePath = util::fullPath(file); + std::string ext = util::extension(file); + + if (consoleId != RC_CONSOLE_ARCADE && consoleId <= RC_CONSOLE_MAX && ext.length() == 4 && + tolower(ext[1]) == 'z' && tolower(ext[2]) == 'i' && tolower(ext[3]) == 'p') { - consoleId = atoi(argv[1]); - file = argv[2]; + std::string unzippedFilename; + size_t size; + void* data = util::loadZippedFile(logger.get(), filePath, &size, unzippedFilename); + if (data) + { + if (rc_hash_generate_from_buffer(hash, consoleId, (uint8_t*)data, size)) + printf("%s", hash); + + free(data); + } } - else if (argc == 4 && strcmp(argv[1], "-v") == 0) + else { - rc_hash_init_verbose_message_callback(rhash_log); + /* register a custom file_open handler for unicode support. use the default implementation for the other methods */ + struct rc_hash_filereader filereader; + memset(&filereader, 0, sizeof(filereader)); + filereader.open = rhash_file_open; + rc_hash_init_custom_filereader(&filereader); + + if (ext.length() == 4 && tolower(ext[1]) == 'c' && tolower(ext[2]) == 'h' && tolower(ext[3]) == 'd') + { +#ifdef HAVE_CHD + rc_hash_init_chd_cdreader(); +#else + printf("CHD not supported without HAVE_CHD compile flag"); + return 0; +#endif + } + else + { + rc_hash_init_default_cdreader(); + } - consoleId = atoi(argv[2]); - file = argv[3]; + if (consoleId > RC_CONSOLE_MAX) + { + rc_hash_iterator iterator; + rc_hash_initialize_iterator(&iterator, filePath.c_str(), NULL, 0); + while (rc_hash_iterate(hash, &iterator)) + printf("%s", hash); + rc_hash_destroy_iterator(&iterator); + } + else + { + if (rc_hash_generate_from_file(hash, consoleId, filePath.c_str())) + printf("%s", hash); + } } - if (consoleId != 0 && !file.empty()) - { - file = util::fullPath(file); + return result; +} - logger.reset(new StdErrLogger); +static int process_iterated_file(int console_id, const std::string& file) +{ + int result = process_file(console_id, file); + if (!result) + printf("????????????????????????????????"); - rc_hash_init_error_message_callback(rhash_log_error); + printf(" %s\n", util::fileNameWithExtension(file).c_str()); + return result; +} - std::string ext = util::extension(file); - if (consoleId != RC_CONSOLE_ARCADE && consoleId <= RC_CONSOLE_MAX && ext.length() == 4 && - tolower(ext[1]) == 'z' && tolower(ext[2]) == 'i' && tolower(ext[3]) == 'p') +static int process_files(int consoleId, const std::string& pattern) +{ + int count = 0; + +#ifdef _WIN32 + const std::string path = util::directory(pattern); + WIN32_FIND_DATAA fileData; + HANDLE hFind; + + hFind = FindFirstFileA(pattern.c_str(), &fileData); + if (hFind != INVALID_HANDLE_VALUE) + { + do { - std::string unzippedFilename; - size_t size; - void* data = util::loadZippedFile(logger.get(), file, &size, unzippedFilename); - if (data) + if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - if (rc_hash_generate_from_buffer(hash, consoleId, (uint8_t*)data, size)) - printf("%s\n", hash); - - free(data); + const std::string filePath = path + "\\" + fileData.cFileName; + count += process_iterated_file(consoleId, filePath); } - } - else + } while (FindNextFileA(hFind, &fileData)); + + FindClose(hFind); + } +#elif defined(__unix__) + glob_t globResult; + memset(&globResult, 0, sizeof(globResult)); + + if (glob(pattern.c_str(), GLOB_TILDE, NULL, &globResult) == 0) + { + struct stat filebuf; + size_t i; + for (i = 0; i < globResult.gl_pathc; ++i) { - /* register a custom file_open handler for unicode support. use the default implementation for the other methods */ - struct rc_hash_filereader filereader; - memset(&filereader, 0, sizeof(filereader)); - filereader.open = rhash_file_open; - rc_hash_init_custom_filereader(&filereader); + if (stat(globResult.gl_pathv[i], &filebuf) == 0 && !S_ISDIR(filebuf.st_mode)) + count += process_iterated_file(consoleId, globResult.gl_pathv[i]); + } + } - if (ext.length() == 4 && tolower(ext[1]) == 'c' && tolower(ext[2]) == 'h' && tolower(ext[3]) == 'd') - { -#ifdef HAVE_CHD - rc_hash_init_chd_cdreader(); + globfree(&globResult); #else - printf("CHD not supported without HAVE_CHD compile flag\n"); - return 0; -#endif - } - else + const std::string filePattern = util::fileNameWithExtension(pattern); + char resolved_path[PATH_MAX]; + std::string path = util::directory(pattern); + DIR* dirp; + + realpath(path.c_str(), resolved_path); + path = resolved_path; + + dirp = opendir(path.c_str()); + if (dirp) + { + struct stat filebuf; + struct dirent *dp; + + while ((dp = readdir(dirp))) + { + if (fnmatch(filePattern.c_str(), dp->d_name, 0) == 0) { - rc_hash_init_default_cdreader(); + if (stat(dp->d_name, &filebuf) == 0 && !S_ISDIR(filebuf.st_mode)) + { + const std::string filePath = path + "/" + dp->d_name; + count += process_iterated_file(consoleId, filePath); + } } + } + } +#endif + + if (count == 0) + printf("No matches found\n"); + + return count; +} + +int main(int argc, char* argv[]) +{ + int consoleId = 0; + int singleFile = 1; + + int argi = 1; + + while (argv[argi][0] == '-') + { + if (strcmp(argv[argi], "-v") == 0) + { + rc_hash_init_verbose_message_callback(rhash_log); + ++argi; + } + } + + if (argi + 2 > argc) + { + usage(argv[0]); + return 1; + } + consoleId = atoi(argv[argi++]); + if (consoleId == 0) + { + usage(argv[0]); + return 1; + } + + logger.reset(new StdErrLogger); + rc_hash_init_error_message_callback(rhash_log_error); + + if (argi + 1 < argc) + { + if (consoleId > RC_CONSOLE_MAX) + { + printf("Specific console must be specified when processing multiple files\n"); + return 0; + } + + singleFile = 0; + } + else + { + std::string file = argv[argi]; + if (file.find('*') != std::string::npos || file.find('?') != std::string::npos) + { if (consoleId > RC_CONSOLE_MAX) { - rc_hash_iterator iterator; - rc_hash_initialize_iterator(&iterator, file.c_str(), NULL, 0); - while (rc_hash_iterate(hash, &iterator)) - printf("%s\n", hash); - rc_hash_destroy_iterator(&iterator); - } - else - { - if (rc_hash_generate_from_file(hash, consoleId, file.c_str())) - printf("%s\n", hash); + printf("Specific console must be specified when using wildcards\n"); + return 0; } + + singleFile = 0; } + } - return result; + if (!singleFile) + { + /* verbose logging not allowed when processing multiple files */ + rc_hash_init_verbose_message_callback(NULL); + } + + while (argi < argc) + { + std::string file = argv[argi++]; + + if (file.find('*') != std::string::npos || file.find('?') != std::string::npos) + { + if (!process_files(consoleId, file)) + return 0; + } + else + { + int result = process_file(consoleId, file); + + if (singleFile) + printf("\n"); + else + printf(" %s\n", util::fileNameWithExtension(file).c_str()); + + if (!result) + return result; + } } - usage(argv[0]); return 1; }