Browse Source

Improved localisation initialization process

Ivan Arkhipov 4 years ago
parent
commit
057e44a5e1
3 changed files with 115 additions and 100 deletions
  1. 2 0
      include/DatSubsystems/DatLocaleManager.h
  2. 3 3
      src/DatFile.cpp
  3. 110 97
      src/DatSubsystems/DatLocaleManager.cpp

+ 2 - 0
include/DatSubsystems/DatLocaleManager.h

@@ -84,6 +84,8 @@ namespace LOTRO_DAT {
         std::map<long long, SubFile> patch_dict_;
         std::set<long long> inactive_categories;
         LOCALE current_locale_;
+        uint64_t dict_offset_ = 0;
+        uint64_t dict_size_ = 0;
     };
 }
 };

+ 3 - 3
src/DatFile.cpp

@@ -3,6 +3,7 @@
 //
 #define NOMINMAX
 
+#include <LotroDat.h>
 #include <DatFile.h>
 #include <DatOperationResult.h>
 #include <EasyLogging++/easylogging++.h>
@@ -12,8 +13,6 @@
 #define ftell _ftelli64
 #endif
 
-#define VERSION "7.1.0"
-
 INITIALIZE_EASYLOGGINGPP
 
 extern "C++"
@@ -127,6 +126,7 @@ namespace LOTRO_DAT {
         initialized_ = true;
 
         status_->SetDefaultStatus();
+        LOG(INFO) << "DATINIT: All initialization processes finished successfully";
         return DatOperationResult<>();
     }
 
@@ -143,7 +143,7 @@ namespace LOTRO_DAT {
                      "# Is part of LOTRO Legacy project (http://translate.lotros.ru/)                        #\n"
                      "# Last version is available on http://git.gi1dor.ru/LotRO_Legacy/Universal_dat_library #\n"
                      "########################################################################################\n\n\n",
-                VERSION);
+                LOTRO_DAT_VERSION);
 
         io_->PrintInformaion(out);
         fileSystem_->PrintInformaion(out);

+ 110 - 97
src/DatSubsystems/DatLocaleManager.cpp

@@ -35,91 +35,78 @@ namespace LOTRO_DAT {
      * 4 * inactive_categories.size()   bytes for inactive_categories data
      * ========================================
      * Помимо этого:
-     * 0x128-0x12C - Флаг, установлена ли альтернативная версия (flag)
+     * 0x128-0x12C - 0, если .dat файл не был изменен библиотекой или активна локаль ORIGINAL и обновление клиентом игры не испортит .dat file
+     *               Версия словаря локалей, если активна локаль PATCHED  и обновление клиентом игры может испортить .dat file
+     *               Отличие значения в 0x128 от версии словаря локалей => файл ресурсов мог быть повреждён или структура устарела и необходимо перекачать
      * 0x12C-0x130 - Офсет начала словаря локализации (offset)
      *
-     * \warning Если flag != 0 и offset == 0 - то dat файл считается повреждённым. Проверка осуществляется функцией CheckLocaleCorrectж
+     * \warning Если flag != 0 и offset == 0 - то dat файл считается повреждённым. Проверка осуществляется функцией CheckLocaleCorrect
      */
 
     DatOperationResult<> DatLocaleManager::Init() {
         if (!dat)
             return DatOperationResult<>(ERROR, "LOCALEINIT: no connection with Dat (dat is nullptr)");
 
-        orig_dict_.clear();
-        patch_dict_.clear();
-        inactive_categories.clear();
-        current_locale_ = ORIGINAL;
+        ClearData();
 
         LOG(INFO) << "Initialising locales...";
-        BinaryData locale_offset_data(4);
-        dat->GetIO().ReadData(locale_offset_data, 4, 300);
-        long long locale_offset = locale_offset_data.ToNumber<4>(0);
-
-        if (locale_offset == 0 || locale_offset + 8 >= dat->GetIO().GetActualDatSize().value) {
-            if (CheckLocaleCorrect()) {
-                LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
-                return DatOperationResult<>();
-            } else {
-                return DatOperationResult<>(ERROR,
-                                            "Locale dict is incorrect, through patched mark is standing. Dat file may be corrupted");
-            }
+        
+        if (!CheckLocaleCorrect()) {
+            return DatOperationResult<>(ERROR, "LOCALEINIT: Check locale correct failed!");
         }
 
+        BinaryData locale_dict_offset_data(4);
+        dat->GetIO().ReadData(locale_dict_offset_data, 4, 300);
+        long long dict_offset_ = locale_dict_offset_data.ToNumber<4>(0);
+
         BinaryData locale_info(16);
-        dat->GetIO().ReadData(locale_info, 16, locale_offset);
+        auto operation = dat->GetIO().ReadData(locale_info, 16, dict_offset_);
+        if (!operation.result) {
+            dict_offset_ = 0;
+            dict_size_ = 0;
+            LOG(WARNING) << "LOCALEINIT: Locale offset is incorrect, skipping initialization";
+            return DatOperationResult<>(SUCCESS);
+        }
 
-        long long dict_size = locale_info.ToNumber<4>(0);
+        dict_size_ = locale_info.ToNumber<4>(0);
         long long dict_version = locale_info.ToNumber<4>(4);
         long long patched_file_end = locale_info.ToNumber<4>(8);
         long long dat_file_header_hash = locale_info.ToNumber<4>(12);
 
         if (dict_version != DAT_LOCALE_DICT_VERSION) {
-            dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            if (CheckLocaleCorrect())
-                return DatOperationResult<>(SUCCESS);
-            else
-                return DatOperationResult<>(ERROR,
-                                            "Version of locales' dictionary is incorrect, through patched mark is standing. Dat file may be corrupted");
+            dict_offset_ = 0;
+            dict_size_ = 0;
+            LOG(WARNING) << "LOCALEINIT: Locale dictionary version is outdated, passing it.";
+            return DatOperationResult<>(SUCCESS);
         }
 
         if (dat_file_header_hash != dat->GetIO().GetHeaderHash()) {
-            LOG(INFO) << "Header hash, written after last patch apply doesn't match current hash. Seems like dat-file was modified somewhere else, so removing all patch data";
-            dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            if (CheckLocaleCorrect())
-                return DatOperationResult<>(SUCCESS);
-            else
-                return DatOperationResult<>(ERROR,
-                                            "Version of locales' dictionary is incorrect, through patched mark is standing. Dat file may be corrupted");
+            dict_offset_ = 0;
+            dict_size_ = 0;
+            LOG(WARNING) << "LOCALEINIT: Locale header hash does not match real dat file header hash. Passing initialization!";
+            return DatOperationResult<>(SUCCESS);
         }
 
-        BinaryData dicts_data = BinaryData((unsigned) dict_size);
-        dat->GetIO().ReadData(dicts_data, dict_size - 16, locale_offset + 16);
-
-        if (dicts_data.size() < 15) {
-            dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            return DatOperationResult<>(ERROR, "INITLOCALE: Data in locales' dictionary is incorrect.");
-        }
+        BinaryData dicts_data = BinaryData((unsigned)dict_size_);
+        dat->GetIO().ReadData(dicts_data, dict_size_ - 16, dict_offset_ + 16);
 
         BinaryData hi_data = dicts_data.CutData(0, 15) + BinaryData("\0", 1);
         std::string hi = std::string((char *) (hi_data.data()));
-
-        if (hi != "Hi from Gi1dor!")
-            return DatOperationResult<>(ERROR,
-                                        "INITLOCALE: Data in locales' dictionary is incorrect (couldn't receive 'Hello').");
+        if (hi != "Hi from Gi1dor!") {
+            dict_offset_ = 0;
+            LOG(WARNING) << "LOCALEINIT: couldn't receive Hello, skipping initialization";
+            return DatOperationResult<>(SUCCESS);
+        }
 
         int offset = 15;
         BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
         std::string locale((char *) (current_locale_data.data()));
-        offset += 4;
-
-        if (locale != "PATC" && locale != "ORIG")
-            return DatOperationResult<>(ERROR,
-                                        "INITLOCALE: Data in locales' dictionary is incorrect (current locale mark is invalid).");
-
         current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
-
+        offset += 4;
+        
         size_t orig_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
         offset += 4;
+
         for (size_t i = 0; i < orig_dict_size; i++) {
             auto file = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
             file.category = dicts_data.ToNumber<4>(offset + 32);
@@ -149,19 +136,10 @@ namespace LOTRO_DAT {
         LOG(INFO) << "There are " << inactive_categories.size() << " categories inactive: ";
         LOG(INFO) << "Finished initialising locales";
 
-        if (CheckLocaleCorrect()) {
-            dat->GetFileSystem().patched_file_end = patched_file_end;
-            LOG(INFO) << "Locales initialisation success. Dictionary size is " << dict_size << ". Version is "
-                      << dict_version << ". Localed .dat size = " << patched_file_end;
-            return DatOperationResult<>(SUCCESS);
-        } else {
-            orig_dict_.clear();
-            patch_dict_.clear();
-            inactive_categories.clear();
-            current_locale_ = ORIGINAL;
-            return DatOperationResult<>(ERROR,
-                                        "Locale dict is incorrect, through patched mark is standing. Dat file may be corrupted");
-        }
+        dat->GetFileSystem().patched_file_end = patched_file_end;
+        LOG(INFO) << "Locales initialisation success. Dictionary size is " << dict_size_ << ". Version is "
+                  << dict_version << ". Localed .dat size = " << patched_file_end;
+        return DatOperationResult<>(SUCCESS);
     }
 
     /*!
@@ -350,37 +328,81 @@ namespace LOTRO_DAT {
      */
 
     bool DatLocaleManager::CheckLocaleCorrect() {
-        BinaryData locale_info(4);
-        dat->GetIO().ReadData(locale_info, 4, 296);
-        long long locale_status = locale_info.ToNumber<4>(0);
+        BinaryData locale_dict_version_data(4); // 0, если файл не был пропатчен или активна локаль ORIGINAL,
+                                                // DAT_LOCALE_DICT_VERSION иначе 
+
+        dat->GetIO().ReadData(locale_dict_version_data, 4, 296);
+        uint32_t locale_dict_version = locale_dict_version_data.ToNumber<4>(0);
 
         BinaryData locale_offset_data(4);
         dat->GetIO().ReadData(locale_offset_data, 4, 300);
         long long locale_offset = locale_offset_data.ToNumber<4>(0);
 
-        if (locale_offset == 0 || locale_offset + 8 >= dat->GetIO().GetActualDatSize().value)
-            return locale_status == 0;
+        if (locale_offset == 0) {
+            if (locale_dict_version == 0) {
+                LOG(INFO) << "CHCKLOCALECORRECT: No file patch info found, check successfull!";
+                return true;
+            } else {
+                LOG(ERROR) << "CHCKLOCALECORRECT: Locale offset is null, but patch mark exists!";
+                return false;
+            }
+        }
 
-        BinaryData dicts_data = BinaryData(4);
-        auto operation = dat->GetIO().ReadData(dicts_data, 4, locale_offset + 16 + 15);
-        if (operation.result == ERROR)
-            return locale_status == 0;
+        BinaryData locale_dict_header(16 + 15 + 4);
+        auto operation = dat->GetIO().ReadData(locale_dict_header, 16 + 15 + 4, locale_offset);
+        LOG(INFO) << std::string((char* )BinaryData(locale_dict_header + BinaryData("\0", 1)).data());
 
-        BinaryData locale_data = dicts_data + BinaryData("\0", 1);
-        std::string locale((char *) (locale_data.data()));
+        if (!operation.result) {
+            if (locale_dict_version != 0) {
+                LOG(ERROR) << "CHCKLOCALECORRECT: incorrect locale offset (cannot read data at offset" << locale_offset << ")";
+                return false;
+            } else {
+                LOG(WARNING) << "CHCKLOCALECORRECT: incorrect locale offset (cannot read data at offset" << locale_offset << "), but patch mark is not standing, so passing by";
+                return true;
+            }
+        }
+
+        long long dict_version = locale_dict_header.ToNumber<4>(4);
+        long long dat_header_hashsum = locale_dict_header.ToNumber<4>(12);
+        BinaryData hi_data = locale_dict_header.CutData(16, 16 + 15) + BinaryData("\0", 1);
+        std::string hi_string = std::string((char *) (hi_data.data()));
 
-        LOCALE dat_locale = (locale == "PATC" ? PATCHED : ORIGINAL);
+        BinaryData current_locale_data = locale_dict_header.CutData(16 + 15, 16 + 15 + 4) + BinaryData("\0", 1);
+        std::string locale_string = std::string((char *) (current_locale_data.data()));
 
-        if ((locale_status == 0 && dat_locale == PATCHED) || (locale_status != 0 && dat_locale == ORIGINAL)) {
-            LOG(ERROR) << "CHCKLOCALECORRECT: Locale status and current_locale doesn't match!";
+        if (dict_version != DAT_LOCALE_DICT_VERSION) {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Locale dict version is incorrect:" << dict_version << " expected: " << DAT_LOCALE_DICT_VERSION;
             return false;
         }
 
-        if (locale_status != 0 && locale_status != dat->GetIO().GetHeaderHash()){
-            LOG(ERROR) << "CHCKLOCALECORRECT: Locale hash doesn't match!";
+        if (locale_string != "PATC" && locale_string != "ORIG") {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Data in locales' dictionary is incorrect (current locale mark is invalid)." << locale_string;
             return false;
         }
 
+        LOCALE file_locale = (locale_string == "PATC" ? PATCHED : ORIGINAL);
+
+        if (file_locale == ORIGINAL && locale_dict_version != 0) {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Locale from dictionary is original, but patched mark already exists!";
+            return false;
+        }
+
+        if (file_locale == PATCHED && locale_dict_version != DAT_LOCALE_DICT_VERSION) {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Locale from dictionary is PATCHED, but patched mark version is incorrect!";
+            return false;
+        }
+
+        if (hi_string != "Hi from Gi1dor!" && locale_dict_version != 0) {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Data in locales' dictionary is incorrect (couldn't receive 'Hello').";
+            return false;
+        }
+        
+        if (dat_header_hashsum != dat->GetIO().GetHeaderHash() && locale_dict_version != 0) {
+            LOG(ERROR) << "CHCKLOCALECORRECT: Dat header checksum from header does not match dat header checksum from locale dictionary!";
+            return false;
+        }
+
+        LOG(INFO) << "CHCKLOCALECORRECT: All checks passed successfully!";
         return true;
     }
 
@@ -444,9 +466,9 @@ namespace LOTRO_DAT {
      * 4 * inactive_categories.size()   bytes for inactive_categories data
      * ========================================
      * Помимо этого:
-     * 0x128-0x12C - 0, если выбрана локаль ORIGINAL и обновление клиентом игры не испортит .dat file
-     *               хэш хедера файла в противном случае.
-     *               Отличие значения в 0x128 от 0 и значения в 0x148 => файл ресурсов мог быть повреждён
+     * 0x128-0x12C - 0, если .dat файл не был изменен библиотекой или активна локаль ORIGINAL и обновление клиентом игры не испортит .dat file
+     *               Версия словаря локалей, если активна локаль PATCHED  и обновление клиентом игры может испортить .dat file
+     *               Отличие значения в 0x128 от версии словаря локалей => файл ресурсов мог быть повреждён или структура устарела и необходимо перекачать
      *
      * 0x12C-0x130 - Офсет начала словаря локализации
      */
@@ -456,8 +478,6 @@ namespace LOTRO_DAT {
             return DatOperationResult<>(SUCCESS);
 
         if (patch_dict_.empty()) {
-            dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
-            dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
             return DatOperationResult<>(SUCCESS);
         }
 
@@ -510,14 +530,7 @@ namespace LOTRO_DAT {
             current_size += 4;
         }
 
-
-        BinaryData dicts_data(4);
-        dat->GetIO().ReadData(dicts_data, 4, 300);
-        long long dict_offset = dicts_data.ToNumber<4>(0);
-        dat->GetIO().ReadData(dicts_data, 4, dict_offset);
-        long long dict_size = dicts_data.ToNumber<4>(0);
-
-        if (binary_data.size() > dict_size || dict_offset == 0) {
+        if (binary_data.size() > dict_size_ || dict_offset_ == 0) {
             long long new_dict_offset = dat->GetFileSystem().patched_file_end + 16;
 
             // Updating first 16 bytes
@@ -534,7 +547,7 @@ namespace LOTRO_DAT {
             dat->GetIO().WriteData(BinaryData::FromNumber<4>(new_dict_offset), 4, 300);
 
             if (current_locale_ == PATCHED) {
-                dat->GetIO().WriteData(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 4, 296);
+                dat->GetIO().WriteData(BinaryData::FromNumber<4>(DAT_LOCALE_DICT_VERSION), 4, 296);
             } else {
                 dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
             }
@@ -552,12 +565,12 @@ namespace LOTRO_DAT {
             binary_data.Append(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 12);
 
             if (current_locale_ == PATCHED) {
-                dat->GetIO().WriteData(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 4, 296);
+                dat->GetIO().WriteData(BinaryData::FromNumber<4>(DAT_LOCALE_DICT_VERSION), 4, 296);
             } else {
                 dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
             }
 
-            auto operation = dat->GetIO().WriteData(binary_data, binary_data.size(), dict_offset);
+            auto operation = dat->GetIO().WriteData(binary_data, binary_data.size(), dict_offset_);
 
             if (operation.result != SUCCESS) {
                 return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales. ERRMSG: " + operation.msg);
@@ -573,7 +586,7 @@ namespace LOTRO_DAT {
         orig_dict_.clear();
         patch_dict_.clear();
         inactive_categories.clear();
-        current_locale_ = LOCALE(-1);
+        current_locale_ = ORIGINAL;
     }
 
     DatOperationResult<> DatLocaleManager::EnableCategory(long long category) {