Kaynağa Gözat

Completed patcher main features

Ivan Arkhipov 5 yıl önce
ebeveyn
işleme
032e8a320c

BIN
bin/LotRO_dat_extractor.exe


BIN
bin/LotRO_dat_patcher.exe


+ 2 - 2
include/DatFile.h

@@ -51,7 +51,7 @@ namespace LOTRO_DAT {
 
         DatLocaleManager &getLocaleManager();
         DatExporter &getExporter();
-//        DatPatcher &getPatcher();
+        DatPatcher &getPatcher();
 //        DatBackupManager &getBackupManager();
         DatIO &getIO();
         DatFileSystem &getFileSystem();
@@ -65,7 +65,7 @@ namespace LOTRO_DAT {
         std::unique_ptr<DatIO> io_;
         std::unique_ptr<DatFileSystem> fileSystem_;
         std::unique_ptr<DatLocaleManager> localeManager_;
-//        std::unique_ptr<DatPatcher> patcher_;
+        std::unique_ptr<DatPatcher> patcher_;
         std::unique_ptr<DatExporter> exporter_;
 //        std::unique_ptr<DatBackupManager> backupManager_;
         bool initialized_;

+ 4 - 0
include/DatSubsystems/DatLocaleManager.h

@@ -59,6 +59,10 @@ namespace LOTRO_DAT {
 
         void PrintInformaion(FILE *file);
 
+        bool CategoryIsInactive(long long category);
+
+        void UpdateCategory(long long file_id, long long category);
+
     private:
         std::map<long long, SubFile> &GetLocaleDictReference(LOCALE locale);
 

+ 10 - 7
include/DatSubsystems/DatPatcher.h

@@ -17,6 +17,15 @@ namespace LOTRO_DAT {
     class Database;
     class BinaryData;
 
+    /*!
+     * \brief Модуль экспорта файлов
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Класс для изменения файлов в dat контейнере. Позволяет обновлять файлы, сохраняя их оригинальные версии
+     *
+     * \warning Объекты этого класса не должны создаваться отдельно! Созданием и управлением ими занимается класс DatFile
+     */
+
     class DatPatcher {
     public:
         DatPatcher() = delete;
@@ -26,15 +35,9 @@ namespace LOTRO_DAT {
 
         explicit DatPatcher(DatFile *datFilePtr);
 
-        void Init();
-
         DatOperationResult<> PatchFile(const SubfileData &data);
 
-        DatOperationResult<> PatchFile(const char *filename, YAML::Node options);
-
-        DatOperationResult<> PatchAllDatabase(Database *db);
-
-        void DeInit();
+        DatOperationResult<int> PatchAllDatabase(Database *db);
 
     private:
         DatOperationResult<> ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data);

+ 2 - 1
include/SubFile.h

@@ -23,7 +23,8 @@ namespace LOTRO_DAT
     class SubFile
     {
         friend class DatFileSystem;
-		friend class SubDirectory;
+		friend class DatPatcher;
+
     public:
         struct SubFileOffsetComparator {
             bool operator() (const SubFile &f, const SubFile &s){

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 10 - 13
src/DatFile.cpp

@@ -26,18 +26,16 @@ namespace LOTRO_DAT {
 
     DatFile::DatFile() {
         el::Configurations defaultConf;
-        el::Loggers::addFlag(el::LoggingFlag::NewLineForContainer);
         el::Loggers::addFlag(el::LoggingFlag::LogDetailedCrashReason);
         el::Loggers::addFlag(el::LoggingFlag::ImmediateFlush);
         el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
-        el::Loggers::addFlag(el::LoggingFlag::HierarchicalLogging);
 
         defaultConf.setToDefault();
         defaultConf.setGlobally(el::ConfigurationType::Format, "%datetime %level : %msg (function: %func)");
 
 
         defaultConf.setGlobally(el::ConfigurationType::ToFile, "true");
-        //defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
+        defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
         defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
         defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
         defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
@@ -54,7 +52,7 @@ namespace LOTRO_DAT {
         fileSystem_ = std::make_unique<DatFileSystem>(this);
         localeManager_ = std::make_unique<DatLocaleManager>(this);
         exporter_ = std::make_unique<DatExporter>(this);
-//        patcher_ = std::make_unique<DatPatcher>(this);
+        patcher_ = std::make_unique<DatPatcher>(this);
 //        backupManager_ = std::make_unique<DatBackupManager>(this);
     }
 
@@ -65,11 +63,11 @@ namespace LOTRO_DAT {
     DatExporter &DatFile::getExporter() {
         return *exporter_;
     }
-//
-//    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
-//        return *patcher_;
-//    }
-//
+
+    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
+        return *patcher_;
+    }
+
 //    DatBackupManager &DatFile::getBackupManager() {
 //        return *backupManager_;
 //    }
@@ -91,16 +89,15 @@ namespace LOTRO_DAT {
 
         auto operation = io_->Init(filename);
         if (operation.result != SUCCESS)
-            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");
 
         operation = fileSystem_->Init();
         if (operation.result != SUCCESS)
-            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");
 
         operation = localeManager_->Init();
         if (operation.result != SUCCESS)
-            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
-
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");
 
         initialized_ = true;
         return DatOperationResult<>();

+ 14 - 14
src/DatSubsystems/DatFileSystem.cpp

@@ -43,7 +43,7 @@ namespace LOTRO_DAT {
             return DatOperationResult<BinaryData>(BinaryData(), ERROR,
                                                   "DATFSGETFILEDATA: no file with id = " + std::to_string(file_id));
 
-        auto file = getfile_operation.value;
+        auto& file = getfile_operation.value;
 
 
         BinaryData mfile_id(20);
@@ -123,8 +123,7 @@ namespace LOTRO_DAT {
         if (operation.result == ERROR)
             return DatOperationResult<>(ERROR, "DATFS: Unable to update file info - no file in dict with id = " +
                                                std::to_string(preinit_file.file_id()));
-        auto file = operation.value;
-
+        auto& file = operation.value;
         file->unknown1_ = preinit_file.unknown1();
         file->file_id_ = preinit_file.file_id();
         file->file_offset_ = preinit_file.file_offset();
@@ -133,6 +132,8 @@ namespace LOTRO_DAT {
         file->version_ = preinit_file.version();
         file->block_size_ = preinit_file.block_size();
         file->unknown2_ = preinit_file.unknown2();
+        subfile_pending_update.insert(preinit_file.file_id());
+
         return DatOperationResult<>();
     }
 
@@ -176,17 +177,16 @@ namespace LOTRO_DAT {
             if (dictionary_.count(file_id) == 0)
                 continue;
 
-            auto operation = CheckCorrectSubfile(dictionary_[file_id]);
-            if (operation.result == ERROR) {
-                LOG(ERROR) << "Check subfile correctness failed. Error message: " << operation.msg;
-                continue;
-            }
-
-            if (!operation.value) {
-                LOG(DEBUG) << "Incorrect SubFile " << file_id << " data: doesn't match";
-                continue;
-            }
+//            auto operation = CheckCorrectSubfile(dictionary_[file_id]);
+//            if (operation.result == ERROR) {
+//                LOG(ERROR) << "Check subfile correctness failed";
+//                continue;
+//            }
 
+//            if (!operation.value) {
+//                LOG(ERROR) << "Incorrect SubFile " << file_id << " data: doesn't match";
+//                continue;
+//            }
 
             auto operation1 = dat->getIO().WriteData(dictionary_[file_id]->MakeHeaderData(), 32,
                                                      dictionary_[file_id]->dictionary_offset());
@@ -490,7 +490,7 @@ namespace LOTRO_DAT {
 
     DatOperationResult<> DatFileSystem::PerformOperationOnAllFiles(const std::function<void (std::shared_ptr<SubFile>&)>& function) {
         InitAllFiles();
-        for (auto file_pair: dictionary_)
+        for (auto& file_pair: dictionary_)
             function(file_pair.second);
         return DatOperationResult<>();
     }

+ 39 - 21
src/DatSubsystems/DatLocaleManager.cpp

@@ -23,7 +23,7 @@ namespace LOTRO_DAT {
      * 4                                bytes for locale version
      * 4                                bytes for .dat file size (with patches)
      * 15                               bytes for "Hi from Gi1dor"
-     * 4                                bytes for LOCALE
+     * 4                                bytes for LOCALE mark ("PATC" or "ORIG")
      * 4                                bytes for orig_dict.size()
      * (32 + 4) * orig_dict.size()      bytes for orig_dict data
      * 4                                bytes for patch_dict.size()
@@ -62,9 +62,6 @@ namespace LOTRO_DAT {
 
         long long dict_size = locale_info.ToNumber<4>(0);
         long long dict_version = locale_info.ToNumber<4>(4);
-        dat->getIO().file_size = locale_info.ToNumber<4>(8);
-
-        LOG(INFO) << "Dictionary size is " << dict_size << ". Version is " << dict_version << ". Localed .dat size = " << dat->getIO().file_size;
 
         if (dict_version != 101) {
             dat->getIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
@@ -112,7 +109,7 @@ namespace LOTRO_DAT {
         for (size_t i = 0; i < patch_dict_size; i++) {
             auto file = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
             file.category = dicts_data.ToNumber<4>(offset);
-            orig_dict_[file.file_id()] = file;
+            patch_dict_[file.file_id()] = file;
             offset += 36;
         }
 
@@ -120,9 +117,11 @@ namespace LOTRO_DAT {
         LOG(INFO) << "There are " << orig_dict_.size() << " files in original locale dictionary";
         LOG(INFO) << "Finished initialising locales";
 
-        if (CheckLocaleCorrect())
+        if (CheckLocaleCorrect()) {
+            dat->getIO().file_size = locale_info.ToNumber<4>(8);
+            LOG(INFO) << "Locales initialisation success. Dictionary size is " << dict_size << ". Version is " << dict_version << ". Localed .dat size = " << dat->getIO().file_size;
             return DatOperationResult<>(SUCCESS);
-        else
+        } else
             return DatOperationResult<>(ERROR, "Locale dict is incorrect, through patched mark is standing. Dat file may be corrupted");
     }
 
@@ -145,7 +144,7 @@ namespace LOTRO_DAT {
             return DatOperationResult<>(SUCCESS);
         }
 
-        auto dict = GetLocaleDictReference(locale);
+        std::map<long long, SubFile>& dict = GetLocaleDictReference(locale);
         for (const auto &file : dict) {
             long long file_id = file.first;
 
@@ -222,13 +221,9 @@ namespace LOTRO_DAT {
                                             + 4 + (32 + 4) * patch_dict_.size()
                                             + 4 + 4 * inactive_categories.size());
 
-        size_t current_size = 0;
-        binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)));
-        binary_data.Append(BinaryData::FromNumber<4>(101));
-        binary_data.Append(BinaryData::FromNumber<4>(dat->getIO().file_size + binary_data.size() + 12 + 20 * 1024 * 1024));
-        current_size = 12;
-
-
+        // First 12 bytes will be filled just before writing data to file
+        size_t current_size = 12;
+        
         binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
         current_size += 15;
 
@@ -270,12 +265,20 @@ namespace LOTRO_DAT {
         long long dict_size = dicts_data.ToNumber<4>(0);
 
         if (binary_data.size() > dict_size || dict_offset == 0) {
-            auto operation = dat->getIO().WriteData(binary_data, binary_data.size(), dat->getIO().file_size + 12);
+            long long new_dict_offset = dat->getIO().file_size + 12;
+
+            // Updating first 12 bytes
+            binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 0);
+            binary_data.Append(BinaryData::FromNumber<4>(101), 4);
+            binary_data.Append(BinaryData::FromNumber<4>(dat->getIO().file_size + binary_data.size() + 20 * 1024 * 1024), 8);
+
+            auto operation = dat->getIO().WriteData(binary_data, binary_data.size(), new_dict_offset);
             if (operation.result != SUCCESS)
                 return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales");
 
-            dat->getIO().WriteData(BinaryData::FromNumber<4>(dat->getIO().file_size), 4, 300);
-            dat->getIO().WriteData(BinaryData::FromNumber<4>(current_locale_), 4, 296, 0);
+
+            dat->getIO().WriteData(BinaryData::FromNumber<4>(new_dict_offset), 4, 300);
+            dat->getIO().WriteData(BinaryData::FromNumber<4>(current_locale_), 4, 296);
 
             dat->getIO().file_size += binary_data.size();
 
@@ -284,6 +287,10 @@ namespace LOTRO_DAT {
             dat->getIO().WriteData(nulls, nulls.size(), dat->getIO().file_size);
             dat->getIO().file_size += nulls.size();
         } else {
+            binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 0);
+            binary_data.Append(BinaryData::FromNumber<4>(101), 4);
+            binary_data.Append(BinaryData::FromNumber<4>(dat->getIO().file_size), 8);
+
             dat->getIO().WriteData(BinaryData::FromNumber<4>(current_locale_), 4, 296, 0);
             auto operation = dat->getIO().WriteData(binary_data, binary_data.size(), dict_offset);
             if (operation.result != SUCCESS)
@@ -304,7 +311,7 @@ namespace LOTRO_DAT {
      */
 
     void DatLocaleManager::UpdateLocaleFile(DatLocaleManager::LOCALE locale, const SubFile &file) {
-        auto dict = GetLocaleDictReference(locale);
+        std::map<long long, SubFile>& dict = GetLocaleDictReference(locale);
         dict[file.file_id()] = file;
     }
 
@@ -317,8 +324,8 @@ namespace LOTRO_DAT {
      */
 
     DatOperationResult<SubFile> DatLocaleManager::GetLocaleFile(long long file_id, DatLocaleManager::LOCALE locale) {
-        auto dict = GetLocaleDictReference(locale);
-        if (dict.count(file_id) != 0)
+        std::map<long long, SubFile>& dict = GetLocaleDictReference(locale);
+        if (dict.count(file_id) == 0)
             return DatOperationResult<SubFile>(SubFile(), ERROR, "GETLOCFILE: cannot get file with id = " + std::to_string(file_id) + " from dict " + std::to_string(locale));
         return DatOperationResult<SubFile>(dict[file_id], SUCCESS);
     }
@@ -410,4 +417,15 @@ namespace LOTRO_DAT {
         LOCALE dat_locale = (locale == "PATC" ? PATCHED : ORIGINAL);
         return locale_status == dat_locale;
     }
+
+    bool DatLocaleManager::CategoryIsInactive(long long category) {
+        return inactive_categories.count(category) > 0;
+    }
+
+    void DatLocaleManager::UpdateCategory(long long file_id, long long category) {
+        if (orig_dict_.count(file_id))
+            orig_dict_[file_id].category = category;
+        if (patch_dict_.count(file_id))
+            patch_dict_[file_id].category = category;
+    }
 }

+ 147 - 4
src/DatSubsystems/DatPatcher.cpp

@@ -1,5 +1,148 @@
-//
-// Created by kikab on 04.06.2018.
-//
+#include <DatSubsystems/DatPatcher.h>
+#include <SubfileData.h>
+#include <DatFile.h>
+#include <yaml-cpp/yaml.h>
 
-#include "DatSubsystems/DatPatcher.h"
+namespace LOTRO_DAT {
+
+    DatPatcher::DatPatcher(DatFile *datFilePtr) : dat(datFilePtr) {
+    }
+
+    /*!
+     * \Author Gi1dor
+     * \date 07.07.2018
+     * Обновление файла. Записывает данные файла в dat контейнер, используя информацию в SubfileData. Если ранее файл не существовал - он не будет создан (вернёт ошибку).
+     * \warning В процессе применения локаль будет автоматически переключена в положение PATCHED
+     * \param[in] data Новые данные файла
+     */
+
+    DatOperationResult<> DatPatcher::PatchFile(const SubfileData &data) {
+        auto file_id = data.options["fid"].as<long long>();
+
+        auto getfile_operation = dat->getFileSystem().GetFile(file_id);
+        if (getfile_operation.result == ERROR)
+            return DatOperationResult<>(ERROR,
+                                        "PATCHSUBFILEDATA: Unable to find file with id " + std::to_string(file_id));
+
+        auto& file = getfile_operation.value;
+
+        // If file has inactive category, then we should set it to patched state in order to commit patch and
+        // then in ApplyFilePatch() function, if new category is still inactive, return dictionary to its original state;
+
+        if (dat->getLocaleManager().CategoryIsInactive(file->category) != 0) {
+            auto operation = dat->getLocaleManager().GetLocaleFile(file->file_id(), DatLocaleManager::PATCHED);
+            if (operation.result == SUCCESS)
+                dat->getFileSystem().UpdateFileInfo(operation.value);
+        }
+
+        if (data.options["cat"].IsDefined())
+            file->category = data.options["cat"].as<long long>();
+        else
+            file->category = 1;
+
+        auto getdata_operation = dat->getFileSystem().GetFileData(file_id, 0);
+        if (getdata_operation.result == ERROR)
+            return DatOperationResult<>(ERROR,
+                                        "PATCHSUBFILEDATA: can't get file data for id = " + std::to_string(file_id));
+        auto& file_data = getdata_operation.value;
+
+        BinaryData patch_data = file->MakeForImport(file_data, data);
+
+        auto result = ApplyFilePatch(file, patch_data);
+        if (result.result == ERROR)
+            return DatOperationResult<>(ERROR,
+                                        "PATCHSUBFILEDATA: applyfilepatch failed for id = " + std::to_string(file_id));
+
+        return DatOperationResult<>(SUCCESS);
+    }
+
+
+    /*!
+     * \Author Gi1dor
+     * \date 07.07.2018
+     * Обновление всех файлов в Database.
+     * \warning В процессе применения локаль будет автоматически переключена в положение PATCHED
+     * \param[in] db Указатель на базу данных. База должна быть проинициализирована
+     */
+
+    DatOperationResult<int> DatPatcher::PatchAllDatabase(Database *db) {
+        if (!db)
+            return DatOperationResult<int>(0, ERROR, "PATCHALLDATABASE: db is nullptr");
+
+        SubfileData data;
+        data = db->GetNextFile();
+
+        int successfully_patched = 0;
+
+        while (!data.Empty()) {
+            auto operation = PatchFile(data);
+            if (operation.result == SUCCESS)
+                successfully_patched++;
+
+            data = db->GetNextFile();
+        }
+
+        LOG(INFO) << "Successfully patched whole database";
+        return DatOperationResult<int>(successfully_patched, SUCCESS);
+    }
+
+
+    /*!
+     * \Author Gi1dor
+     * \date 07.07.2018
+     * Функция, вызываемая функцией PatchFile, отвечающая за корректную запись файла в dat контейнер и обновление
+     * информации о нём в файловой системе
+     * \param[in] file Указатель на объект файла в файловой системе (полученный через DatFileSystem::GetFileInfo)
+     * \param[in] data Бинарные данные собранного нового файла, готовые к записи в dat
+     */
+
+    DatOperationResult<> DatPatcher::ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data) {
+        long long file_id = file->file_id();
+
+        if (dat->getLocaleManager().GetCurrentLocale() != DatLocaleManager::PATCHED) {
+            LOG(INFO) << "Changing locale to PATCHED(RU) in order to patch file";
+            dat->getLocaleManager().SetLocale(DatLocaleManager::PATCHED);
+        }
+
+        LOG(INFO) << "Patching file with id = " << file_id;
+
+        if (dat->getLocaleManager().GetLocaleFile(file_id, DatLocaleManager::ORIGINAL).result == ERROR)
+            dat->getLocaleManager().UpdateLocaleFile(DatLocaleManager::ORIGINAL, SubFile(*file));
+
+
+        SubFile new_file = SubFile(*file);
+
+        if (dat->getLocaleManager().GetLocaleFile(file_id, DatLocaleManager::PATCHED).result == ERROR
+            || data.size() > file->block_size()) {
+
+            new_file.file_offset_ = dat->getIO().file_size;
+            new_file.block_size_ = std::max(data.size(), 256u);
+            dat->getIO().file_size += new_file.block_size_ + 8;
+        }
+        new_file.file_size_ = data.size() - 8;
+
+
+        data.Append(BinaryData::FromNumber<4>(0), 0); // set additional fragments count to zero
+
+        if (file_id != data.ToNumber<4>(8))
+            LOG(WARNING) << "Created data's file_id " << file_id << "doesn't match to original: " << data.ToNumber<4>(8);
+
+        auto operation = dat->getIO().WriteData(data, data.size(), new_file.file_offset());
+        if (operation.result == ERROR)
+            return DatOperationResult<>(ERROR, "APPLYPATCHFILE: Unable to write data for file with id " + std::to_string(file_id));
+
+
+        dat->getFileSystem().UpdateFileInfo(new_file);
+        dat->getLocaleManager().UpdateLocaleFile(DatLocaleManager::PATCHED, new_file);
+
+
+        // If file category is inactive, then return file header data in dictionary to original state
+        if (dat->getLocaleManager().CategoryIsInactive(new_file.category))
+            dat->getFileSystem().UpdateFileInfo(dat->getLocaleManager().GetLocaleFile(file_id, DatLocaleManager::ORIGINAL).value);
+
+        dat->getLocaleManager().UpdateCategory(file_id, new_file.category);
+        LOG(INFO) << "Successfully patched file with id = " << file_id;
+
+        return DatOperationResult<>(SUCCESS);
+    }
+};

+ 1 - 1
src/Examples/info_gatherer.cpp

@@ -29,7 +29,7 @@ int main() {
     std::string filename;
     std::getline(in, filename);
     std::cout << "Opening file " << filename << std::endl;
-    auto operation = file.Initialise(filename);
+    auto operation = file.Initialise(filename, 0);
     if (operation.result != SUCCESS) {
         std::cout << "Unable to initialize file. DatFile message: " << operation.msg;
         system("pause");

+ 57 - 77
src/Examples/patcher_example.cpp

@@ -35,18 +35,12 @@ int main() {
 
         std::cout << "Using .dat file from dat_file_path.txt...\n";
         std::cout << "Opening file " << filename << std::endl;
-        DAT_RESULT result = file.InitDatFile(filename, 0);
-        if (result >= 2) {
-            std::cout << "Dat file may be corrupted! It's opened, but all functions MAY WORK INCORRECTLY! It's better to DOWNLOAD CLEAR .DAT FILE\n";
-        }
-        if (result <= 0) {
-            std::cout << "Dat file path from dat_file_path.txt - " << filename << " may be incorrect (cannot open "
-                    "DatFile due to error. See it in errors.log)\n";
-            file.CloseDatFile();
-        }
+        auto operation = file.Initialise(filename, 0);
+        if (operation.result == ERROR)
+            std::cout << "Cannot initialise dat file " << filename << " \n";
     }
 
-    while (file.DatFileState() == CLOSED) {
+    while (!file.Initialized()) {
         std::cout << "Please, tell, where the .dat file is\n";
         std::cout << "Enter path to file (including filename): ";
         std::string filename;
@@ -54,26 +48,12 @@ int main() {
 
         std::cout << "Opening file " << filename << std::endl;
 
-        if (file.InitDatFile(filename, 0) == false) {
-                std::cout << "Some error caused while opening the file... "
-                        "Could you enter .dat filename once more?" << std::endl;
-            file.CloseDatFile();
-        }
+        auto operation = file.Initialise(filename, 0);
+        if (operation.result == ERROR)
+            std::cout << "Cannot initialise dat file " << filename << ", please, try again\n";
     }
 
     std::cout << "Great! File initialised successfully!\n";
-    file.WriteUnorderedDictionary("");
-
-    if (file.CheckIfNotPatched())
-        std::cout << "MESSAGE: Dat file is new and haven't been patched yet\n";
-
-    if (file.CheckIfPatchedByOldLauncher())
-        std::cout << "MESSAGE: Dat file was patched by old launcher. Capability isn't guaranteed! Some functions may not work properly!!!\n";
-
-    if (file.CheckIfUpdatedByGame())
-        std::cout << "MESSAGE: .dat file was updated by game! Need to repair patches with functions RepairPatches() and FinishRepairingPatches()\n";
-
-    std::cout << "Files number: " << file.files_number() << std::endl;
 
     while (true) {
         std::cout << "Please, choose, what should I do. I can patch datfile from database to .dat file (enter 1), "
@@ -81,6 +61,7 @@ int main() {
                 "print disabled categories (enter 6), create backup (enter 7), remove backup (enter 8), "
                 "restore .dat file from backup (enter 9), check if backup exists (enter 10) or exit (enter -1)\n";
 
+        std::cout << "\n=================\nOptions 4,5,6,7,8,9,10 are currently unavailable\n";
         int cmd = 0;
         std::cout << "Enter number of command (1-10): ";
         std::cin >> cmd;
@@ -90,6 +71,7 @@ int main() {
 
         if (cmd == -1) {
             std::cout << "Exiting. Thanks for using me!\n";
+            file.Deinitialize();
             break;
         }
 
@@ -130,7 +112,7 @@ int main() {
 
                 SubfileData subfile = db.GetNextFile();
                 while (!subfile.Empty()) {
-                    if (!file.PatchFile(subfile)) {
+                    if (file.getPatcher().PatchFile(subfile).result == ERROR) {
                         fprintf(stderr, "Error! Caught exception while patching file! Passing it\n");
                     }
 
@@ -150,61 +132,59 @@ int main() {
             }
         }
         if (cmd == 2) {
-            std::cout << "Old locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl;
+            std::cout << "Old locale is " << (file.getLocaleManager().GetCurrentLocale() == DatLocaleManager::PATCHED ? "RU" : "Original") << endl;
             std::cout << "Changing locale..." << std::endl;
-            file.SetLocale(file.current_locale() == PATCHED ? ORIGINAL : PATCHED);
-            std::cout << "New locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
+            file.getLocaleManager().SetLocale(file.getLocaleManager().GetCurrentLocale() == DatLocaleManager::PATCHED  ? DatLocaleManager::ORIGINAL : DatLocaleManager::PATCHED);
+            std::cout << "New locale is " << (file.getLocaleManager().GetCurrentLocale() == DatLocaleManager::PATCHED ? "RU" : "Original") << endl;
         }
 
         if (cmd == 3) {
-            std::cout << "Current locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
-        }
-
-        if (cmd == 4) {
-            int category_id = 0;
-            std::cout << "Enter category id: ";
-            std::cin >> category_id;
-            file.EnableCategory(category_id);
-            std::cout << "Category successfully enabled!" << std::endl;
-        }
-
-        if (cmd == 5) {
-            int category_id = 0;
-            std::cout << "Enter category id: ";
-            std::cin >> category_id;
-            file.DisableCategory(category_id);
-            std::cout << "Category successfully disabled!" << std::endl;
-        }
-
-        if (cmd == 6) {
-            std::cout << "Disabled categories: ";
-            for (auto i : file.GetInactiveCategoriesList())
-                std::cout << i << " ";
-            std::cout << endl;
-        }
-
-        if (cmd == 7) {
-            std::cout << "Creating backup..." << std::endl;
-            std::cout << "Create backup function returned " << file.CreateBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 8) {
-            std::cout << "Removing backup..." << std::endl;
-            std::cout << "Remove backup function returned " << file.RemoveBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 9) {
-            std::cout << "Restoring file from backup..." << std::endl;
-            std::cout << "Restore file function returned " << file.RestoreFromBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 10) {
-            std::cout << "Backup file " << (file.CheckIfBackupExists("clie_local_En.backup") ? "exists!" : "doesn't exist.") << std::endl;
+            std::cout << "Current locale is " << (file.getLocaleManager().GetCurrentLocale() == DatLocaleManager::PATCHED ? "RU" : "Original") << endl;
         }
+//
+//        if (cmd == 4) {
+//            int category_id = 0;
+//            std::cout << "Enter category id: ";
+//            std::cin >> category_id;
+//            file.EnableCategory(category_id);
+//            std::cout << "Category successfully enabled!" << std::endl;
+//        }
+//
+//        if (cmd == 5) {
+//            int category_id = 0;
+//            std::cout << "Enter category id: ";
+//            std::cin >> category_id;
+//            file.DisableCategory(category_id);
+//            std::cout << "Category successfully disabled!" << std::endl;
+//        }
+//
+//        if (cmd == 6) {
+//            std::cout << "Disabled categories: ";
+//            for (auto i : file.GetInactiveCategoriesList())
+//                std::cout << i << " ";
+//            std::cout << endl;
+//        }
+//
+//        if (cmd == 7) {
+//            std::cout << "Creating backup..." << std::endl;
+//            std::cout << "Create backup function returned " << file.CreateBackup("cli_local_En.backup") << std::endl;
+//        }
+//
+//        if (cmd == 8) {
+//            std::cout << "Removing backup..." << std::endl;
+//            std::cout << "Remove backup function returned " << file.RemoveBackup("cli_local_En.backup") << std::endl;
+//        }
+//
+//        if (cmd == 9) {
+//            std::cout << "Restoring file from backup..." << std::endl;
+//            std::cout << "Restore file function returned " << file.RestoreFromBackup("cli_local_En.backup") << std::endl;
+//        }
+//
+//        if (cmd == 10) {
+//            std::cout << "Backup file " << (file.CheckIfBackupExists("clie_local_En.backup") ? "exists!" : "doesn't exist.") << std::endl;
+//        }
     }
-    file.CloseDatFile();
-
-    system("pause");
+    //system("pause");
     return 0;
 }