diff --git a/src/GUI/LoadFromTheFileWindow.cpp b/src/GUI/LoadFromTheFileWindow.cpp index f07465d..88fd7ab 100644 --- a/src/GUI/LoadFromTheFileWindow.cpp +++ b/src/GUI/LoadFromTheFileWindow.cpp @@ -17,7 +17,7 @@ LoadFromTheFileWindow::LoadFromTheFileWindow(QWidget* parent) : QWidget(parent) QPushButton* btnCancel = new QPushButton(tr("BACK")); QHBoxLayout* ltBtnOk = new QHBoxLayout(); QHBoxLayout* ltBtnCancel = new QHBoxLayout(); - QLabel* lblSelectFile = new QLabel(tr("Select .csf file:")); + QLabel* lblSelectFile = new QLabel(tr("Select .csf or .big file:")); btnOk->setObjectName(nameof(btnOk)); btnOk->setFixedWidth(80); @@ -47,7 +47,7 @@ LoadFromTheFileWindow::LoadFromTheFileWindow(QWidget* parent) : QWidget(parent) QFileDialog* fileDialog = new QFileDialog(); // dialog for selecting the path to the file fileDialog->setFileMode(QFileDialog::FileMode::ExistingFile); fileDialog->setAcceptMode(QFileDialog::AcceptMode::AcceptOpen); - fileDialog->setNameFilters({tr("Binary files") + " (*.csf)", + fileDialog->setNameFilters({tr("Binary files") + " (*.csf, *.big)", tr("Any files") + " (*)"}); connect(fileDialog, &QFileDialog::fileSelected, lneFilePath, &QLineEdit::setText); diff --git a/src/GUI/SetUpWindowsWrapper.cpp b/src/GUI/SetUpWindowsWrapper.cpp index cd40361..3563c61 100644 --- a/src/GUI/SetUpWindowsWrapper.cpp +++ b/src/GUI/SetUpWindowsWrapper.cpp @@ -125,16 +125,22 @@ void SetUpWindowsWrapper::LoadFromTheGameWindow_AcceptConfiguration() // TODO: Make it load vanila Generals // Also as work with non-ascii paths // Also as search in big-archives (see more at GZH source code) - QString path = QString::fromStdString(Registry::GetPathToGame(Registry::Games::GeneralsZeroHour)) + "Data\\English\\generals.csf"; - - if (!QFile::exists(path)) + QString gamePath = QString::fromStdString(Registry::GetPathToGame(Registry::Games::GeneralsZeroHour)); + QString pathDataEngGenCsf = gamePath + "Data\\English\\generals.csf"; + QString pathEngBig = gamePath + "\\EnglishZH.big"; + + if (!QFile::exists(pathDataEngGenCsf) && !QFile::exists(pathEngBig)) { - QMessageBox::critical(nullptr, L10N(PROGRAM_CONSTANTS->CSF_ERROR_HEADER), - L10N(PROGRAM_CONSTANTS->CSF_EMPTY_DATA_ENGLISH)); + QMessageBox::critical(nullptr, L10N(PROGRAM_CONSTANTS->GMFILES_SRCH_ERR_HEADER), + L10N(PROGRAM_CONSTANTS->BIG_NO_ENGLISH_ZH).arg(pathEngBig)); return; } + + if (QFile::exists(pathDataEngGenCsf)) + WINDOW_MANAGER->SetCSFFilePath(pathDataEngGenCsf); + else + WINDOW_MANAGER->SetCSFFilePath(pathEngBig); - WINDOW_MANAGER->SetCSFFilePath(path); WINDOW_MANAGER->StartUpWindow_AcceptConfiguration(); } diff --git a/src/GUI/Translations/ru.ts b/src/GUI/Translations/ru.ts index d694be5..656bb62 100644 --- a/src/GUI/Translations/ru.ts +++ b/src/GUI/Translations/ru.ts @@ -40,89 +40,89 @@ File - Файл + Файл Open - Открыть + Открыть Save - Сохранить + Сохранить Save As... - Сохранить как... + Сохранить как... Special - Дополнительно + Дополнительно View - Вид + Вид Status Bar - Строка состояния + Строка состояния Enable - Включить + Включить Disable - Отключить + Отключить Settings - Настройки + Настройки About - О программе + О программе Layout %1 - Раскладка %1 + Раскладка %1 Authors: - Авторы: + Авторы: Version: - Версия: + Версия: Program licensed with - Программа лицензирована под + Программа лицензирована под GitHub repository: - Репозиторий на GitHub: + Репозиторий на GitHub: Support development: - Поддержать разработку: + Поддержать разработку: @@ -160,109 +160,6 @@ ЯЗЫК - - HotkeysMainWindow - - File - Файл - - - Open - Открыть - - - Save - Сохранить - - - Save As... - Сохранить как... - - - Special - Дополнительно - - - View - Вид - - - Status Bar - Строка состояния - - - Enable - Включить - - - Disable - Отключить - - - Settings - Настройки - - - Language - Язык - - - About - О программе - - - Layout %1 - Раскладка %1 - - - Authors: - Авторы: - - - Version: - Версия: - - - Program licensed with - Программа лицензирована под - - - GitHub repository: - Репозиторий на GitHub: - - - Support development: - Поддержать разработку: - - - Lanugage - Язык - - - LANGUAGE - ЯЗЫК - - - OK - Ок - - - Cancel - Отмена - - - Program licensed by GNU GPL v3 - Программа лицензирована под лицензией GNU GPL v3 - - - GitHub Repository - Репозиторий на GitHub - - - <a href="https://github.com/MahBoiDeveloper/GZHHotkeysEditor">GitHub Repository</a> - <a href="https://github.com/MahBoiDeveloper/GZHHotkeysEditor">Репозиторий на GitHub</a> - - LoadFromTheFileWindow @@ -280,9 +177,13 @@ Текстовые файлы - Select .csf file: - Выберите .csf файл: + Выберите .csf файл: + + + + Select .csf or .big file: + Выберите .csf или .big файл: @@ -352,17 +253,17 @@ Возникла неизвестная ошибка - + Error with CSF file Ошибка с CSF файлом - + Cannot process the empty file. Невозможно обработать пустой файл. - + Unable to find selected CSF file. Невозможно найти указанный CSF файл. @@ -373,7 +274,7 @@ Make sure that you are load correct file. Проверьте, что вы загружаете правильный файл. - + Choosen CSF file doesn't have CONTROLBAR category. Make sure that you are load correct file. У выбранного CSF файла отсутствует категория CONTROLBAR. Проверьте, что вы загружаете правильный файл. @@ -386,32 +287,51 @@ Make sure that you are load correct file. Невозможно найти "generals.csf" в папке "Game/Data/English". - + Choosen CSF file doesn't have OBJECT category. Make sure that you are load correct file. У выбранного CSF файла отсутствует категория OBJECT. Проверьте, что вы загружаете правильный файл. - Unable find "generals.csf" file in "Game/Data/English" folder. - Невозможно найти "generals.csf" в папке "Game/Data/English". + Невозможно найти "generals.csf" в папке "Game/Data/English". + + + + Unable to find "generals.csf" file in "%1" folder. + Невозможно найти "generals.csf" в папке "%1". + + + + Unable to find CSF file inside BIG archive "%1" + Невозможно найти CSF файл внутри BIG архива "%1" + + + + Game files search error + Ошибка поиска по игровым файлам + + + + Unable to find "EnglishZH.big" archive in "%1" folder. + Невозможно найти "EnglishZH.big" в папке "%1". - + Buildings Здания - + Infantry Пехота - + Vehicles Техника - + Aircrafts Авиация diff --git a/src/GUI/WindowManager.cpp b/src/GUI/WindowManager.cpp index da1ade2..70d472b 100644 --- a/src/GUI/WindowManager.cpp +++ b/src/GUI/WindowManager.cpp @@ -7,6 +7,7 @@ #include "../Unsorted.hpp" #include "../Convert.hpp" #include "../Registry.hpp" +#include "../Exception.hpp" #include "ImageManager.hpp" #include "WindowManager.hpp" @@ -56,7 +57,17 @@ void WindowManager::StartUpWindow_AcceptConfiguration() return; } - CSF_PARSER = std::make_unique(strCSFFilePath); + try + { + CSF_PARSER = std::make_unique(strCSFFilePath); + } + catch(const Exception& e) + { + QMessageBox::critical(nullptr, L10N(PROGRAM_CONSTANTS->CSF_ERROR_HEADER), + e.what()); + return; + } + if (!CSF_PARSER->ExistCategory(PROGRAM_CONSTANTS->HOTKEY_CSF_CATEGORY)) { diff --git a/src/Parsers/CSFParser.cpp b/src/Parsers/CSFParser.cpp index c5b836e..daa4d20 100644 --- a/src/Parsers/CSFParser.cpp +++ b/src/Parsers/CSFParser.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "../Logger.hpp" #include "../Convert.hpp" #include "../Unsorted.hpp" @@ -17,20 +20,46 @@ using namespace std; #pragma region Parsing void CSFParser::Parse(const char* strFilePath) { - Path = QString(strFilePath).toStdWString(); - ifstream csfFile(Path.c_str(), ios::binary | ios::in); - LOGMSG("Attempt to read binary file \"" + Path.c_str() + "\"..."); + Path = QString(strFilePath).toUpper().toStdWString(); + ifstream file(Path.c_str(), ios::binary | ios::in); - if (csfFile.is_open()) + if (file.is_open()) { - ReadHeader(&csfFile); - ReadBody(&csfFile); + if (Path.ends_with(L".BIG")) + { + LOGMSG("BIG archive detected. Try to find CSF file inside..."); + + bool searchResult = false; + char fourC[4] = {' ', ' ', ' ', ' '}; + std::streampos fourCharOffset = sizeof(char) * 4; + + while (!searchResult && file.good()) + { + file.read(fourC, fourCharOffset); + searchResult = (fourC[0] == FSC[0]) && (fourC[1] == FSC[1]) && (fourC[2] == FSC[2]) && (fourC[3] == FSC[3]); + } + + if (!file.good()) + { + LOGMSG(PROGRAM_CONSTANTS->CSF_NO_CSF_IN_BIG.arg(Path)); + throw Exception(L10N(PROGRAM_CONSTANTS->CSF_NO_CSF_IN_BIG).arg(Path)); + } + + auto offset = file.tellg(); + file.clear(); + file.seekg(offset - fourCharOffset); + + LOGMSG("CSF file data found at offset : " + reinterpret_cast(offset)); + } + LOGMSG("Attempt to read string table from \"" + Path.c_str() + "\" file..."); + ReadHeader(&file); + ReadBody(&file); LOGMSG("File \"" + Path.c_str() + "\" has been parsed; strings count : " + Table.size()); } else { - throw Exception(QString("") + "Bad file name; unable to open file \"" + Path + "\""); + throw Exception(QString("") + "Bad file name error; unable to open file \"" + Path + "\""); } } void CSFParser::Parse(const wstring& filePath) { Parse(filePath.c_str()); } diff --git a/src/Parsers/CSFParser.hpp b/src/Parsers/CSFParser.hpp index 1390e5a..0d0f50a 100644 --- a/src/Parsers/CSFParser.hpp +++ b/src/Parsers/CSFParser.hpp @@ -2,9 +2,7 @@ #include #include #include -#include #include -#include #define CSF_PARSER CSFParser::Instance diff --git a/src/ProgramConstants.hpp b/src/ProgramConstants.hpp index 21c43a6..b279a1a 100644 --- a/src/ProgramConstants.hpp +++ b/src/ProgramConstants.hpp @@ -26,62 +26,68 @@ class ProgramConstants std::unique_ptr pSettingsFile = nullptr; // Folders - const QString RESOURCE_FOLDER = "Resources"; - const QString BINARIES_FOLDER = RESOURCE_FOLDER + "\\Binaries"; - const QString TRANSLATIONS_FOLDER = RESOURCE_FOLDER + "/Translations"; - const QString ICONS_FOLDER = RESOURCE_FOLDER + "/Icons"; - const QString THEME_FOLDER = RESOURCE_FOLDER + "/Theme"; - const QString QT_ICONS_FOLDER = ":/icons"; + const QString RESOURCE_FOLDER = "Resources"; + const QString BINARIES_FOLDER = RESOURCE_FOLDER + "\\Binaries"; + const QString TRANSLATIONS_FOLDER = RESOURCE_FOLDER + "/Translations"; + const QString ICONS_FOLDER = RESOURCE_FOLDER + "/Icons"; + const QString THEME_FOLDER = RESOURCE_FOLDER + "/Theme"; + const QString QT_ICONS_FOLDER = ":/icons"; // Resource files - const QString TECH_TREE_FILE = RESOURCE_FOLDER + "/TechTree.json"; - const QString SETTINGS_FILE = RESOURCE_FOLDER + "/Settings.json"; - const QString STYLES_SHEET_FILE = THEME_FOLDER + "/Styles.css"; + const QString TECH_TREE_FILE = RESOURCE_FOLDER + "/TechTree.json"; + const QString SETTINGS_FILE = RESOURCE_FOLDER + "/Settings.json"; + const QString STYLES_SHEET_FILE = THEME_FOLDER + "/Styles.css"; // Build-in files - const QString MISSING_ICON_FILE = QT_ICONS_FOLDER + "/NoImageSmall.webp"; - const QString EDITOR_ICON_FILE = QT_ICONS_FOLDER + "/EditorIconSmall.webp"; - const QString EDITOR_BIG_ICON_FILE = QT_ICONS_FOLDER + "/EditorIconBig.webp"; - const QString GEARS_ICON_FILE = QT_ICONS_FOLDER + "/Gears.webp"; + const QString MISSING_ICON_FILE = QT_ICONS_FOLDER + "/NoImageSmall.webp"; + const QString EDITOR_ICON_FILE = QT_ICONS_FOLDER + "/EditorIconSmall.webp"; + const QString EDITOR_BIG_ICON_FILE = QT_ICONS_FOLDER + "/EditorIconBig.webp"; + const QString GEARS_ICON_FILE = QT_ICONS_FOLDER + "/Gears.webp"; // Window titles - const QString COMMON_TITLE = "C&C: Generals Zero Hour Hotkey Editor"; - const QString SHORT_COMMON_TITLE = "C&C: GZH Hotkey Editor"; - const QString EDITOR_TITLE = SHORT_COMMON_TITLE + " — Editor"; - const QString LOAD_TITLE = SHORT_COMMON_TITLE + " — Load"; - const QString CREATE_TITLE = SHORT_COMMON_TITLE + " — New Set Up"; + const QString COMMON_TITLE = "C&C: Generals Zero Hour Hotkey Editor"; + const QString SHORT_COMMON_TITLE = "C&C: GZH Hotkey Editor"; + const QString EDITOR_TITLE = SHORT_COMMON_TITLE + " — Editor"; + const QString LOAD_TITLE = SHORT_COMMON_TITLE + " — Load"; + const QString CREATE_TITLE = SHORT_COMMON_TITLE + " — New Set Up"; // Magic numbers that become known - const double START_WIDGET_SIZE_RATIO = 3./7.; - const QSize START_BUTTON_SIZE = QSize(230, 110); - const QSize LANGUAGE_CHANGE_SIZE = QSize(250, 100); - const QSize SET_UP_WINDOW_SIZE = QSize(795, 440); - const int ICON_MIN_HEIGHT = 80; - const int ICON_SCALING_HEIGHT = 25; - const int KEYBOARD_KEY_WIDTH = 50; - const int EMPTY_KEY_WIDTH = 25; - - // Errors - const char* SETTINGS_NO_FOUND = "Unable to find \"Settings.json\" in \"Resource\" folder."; - const char* TECH_TREE_NO_FOUND = "Unable to find \"TechTree.json\" in \"Resource\" folder."; - const char* THEME_FOLDER_NO_FOUND = "Unable to find \"Resource/Theme\" folder."; - const char* ICONS_FOLDER_NO_FOUND = "Unable to find \"Resource/Icons\" folder."; - const char* TRANSLATIONS_NO_FOUND = "Unable to find \"Resource/Translations\" folder."; - const char* UNKNOWN_ERROR = "Unknown error has been occured."; - - const QString CSF_ERROR_HEADER = QObject::tr("Error with CSF file"); - const QString CSF_EMPTY_STRING_ERROR = QObject::tr("Cannot process the empty file."); - const QString CSF_DOESNT_EXIST_ERROR = QObject::tr("Unable to find selected CSF file."); - const QString CSF_NO_CTLBAR_ERROR = QObject::tr("Choosen CSF file doesn't have CONTROLBAR category. Make sure that you are load correct file."); - const QString CSF_NO_OBJECT_ERROR = QObject::tr("Choosen CSF file doesn't have OBJECT category. Make sure that you are load correct file."); - const QString CSF_EMPTY_DATA_ENGLISH = QObject::tr("Unable find \"generals.csf\" file in \"Game/Data/English\" folder."); - - // Other constants - const QString HOTKEY_CSF_CATEGORY = "CONTROLBAR"; - const QString OBJECT_CSF_CATEGORY = "OBJECT"; - const QVector GLA_SHORT_NAMES = {"GLA", "TOX", "STL", "DML"}; - const QVector USA_SHORT_NAMES = {"USA", "SWG", "AIR", "LSR"}; - const QVector PRC_SHORT_NAMES = {"PRC", "TNK", "INF", "NUK"}; + const double START_WIDGET_SIZE_RATIO = 3./7.; + const QSize START_BUTTON_SIZE = QSize(230, 110); + const QSize LANGUAGE_CHANGE_SIZE = QSize(250, 100); + const QSize SET_UP_WINDOW_SIZE = QSize(795, 440); + const int ICON_MIN_HEIGHT = 80; + const int ICON_SCALING_HEIGHT = 25; + const int KEYBOARD_KEY_WIDTH = 50; + const int EMPTY_KEY_WIDTH = 25; + + // Error strings + const char* SETTINGS_NO_FOUND = "Unable to find \"Settings.json\" in \"Resource\" folder."; + const char* TECH_TREE_NO_FOUND = "Unable to find \"TechTree.json\" in \"Resource\" folder."; + const char* THEME_FOLDER_NO_FOUND = "Unable to find \"Resource/Theme\" folder."; + const char* ICONS_FOLDER_NO_FOUND = "Unable to find \"Resource/Icons\" folder."; + const char* TRANSLATIONS_NO_FOUND = "Unable to find \"Resource/Translations\" folder."; + const char* UNKNOWN_ERROR = "Unknown error has been occured."; + + // Translated error strings + const QString CSF_ERROR_HEADER = QObject::tr("Error with CSF file"); + const QString CSF_EMPTY_STRING_ERROR = QObject::tr("Cannot process the empty file."); + const QString CSF_DOESNT_EXIST_ERROR = QObject::tr("Unable to find selected CSF file."); + const QString CSF_NO_CTLBAR_ERROR = QObject::tr("Choosen CSF file doesn't have CONTROLBAR category. Make sure that you are load correct file."); + const QString CSF_NO_OBJECT_ERROR = QObject::tr("Choosen CSF file doesn't have OBJECT category. Make sure that you are load correct file."); + const QString CSF_EMPTY_DATA_ENGLISH = QObject::tr("Unable to find \"generals.csf\" file in \"%1\" folder."); + const QString CSF_NO_CSF_IN_BIG = QObject::tr("Unable to find CSF file inside BIG archive \"%1\""); + const QString GMFILES_SRCH_ERR_HEADER = QObject::tr("Game files search error"); + const QString BIG_NO_ENGLISH_ZH = QObject::tr("Unable to find \"EnglishZH.big\" archive in \"%1\" folder."); + + // Other string constants + const QString HOTKEY_CSF_CATEGORY = "CONTROLBAR"; + const QString OBJECT_CSF_CATEGORY = "OBJECT"; + + // Constant containers + const QVector GLA_SHORT_NAMES = {"GLA", "TOX", "STL", "DML"}; + const QVector USA_SHORT_NAMES = {"USA", "SWG", "AIR", "LSR"}; + const QVector PRC_SHORT_NAMES = {"PRC", "TNK", "INF", "NUK"}; const QSet DEFAULT_ALLOWED_KEYS = {