Browse Source

Finished with DatFilesystem module

Ivan Arkhipov 5 years ago
parent
commit
d7e9f9901c

+ 6 - 0
Third_party/EasyLogging++/easylogging++.h

@@ -15,6 +15,12 @@
 //
 #ifndef EASYLOGGINGPP_H
 #define EASYLOGGINGPP_H
+
+#define ELPP_FEATURE_CRASH_LOG
+#define ELPP_HANDLE_SIGABRT
+#define ELPP_DEFAULT_LOG_FILE "dat_library.log"
+#define ELPP_DEBUG_ERRORS
+
 // Compilers and C++0x/C++11 Evaluation
 #if __cplusplus >= 201103L
 #  define ELPP_CXX11 1

+ 19 - 13
include/DatFile.h

@@ -25,13 +25,13 @@ extern "C++"
 {
 namespace LOTRO_DAT {
     enum FILE_TYPE : int {
-        TEXT,
-        JPG,
-        DDS,
-        WAV,
-        OGG,
-        FONT,
-        UNKNOWN
+        TEXT = 0,
+        JPG = 1,
+        DDS = 2,
+        WAV = 3,
+        OGG = 4,
+        FONT = 5,
+        UNKNOWN = 6
     };
 
     class DatFile {
@@ -50,19 +50,25 @@ namespace LOTRO_DAT {
         DatFile &operator=(DatFile &&other) = default;
 
         DatLocaleManager &getLocaleManager();
-        DatExporter &getExporter();
-        DatPatcher &getPatcher();
-        DatBackupManager &getBackupManager();
+//        DatExporter &getExporter();
+//        DatPatcher &getPatcher();
+//        DatBackupManager &getBackupManager();
         DatIO &getIO();
         DatFileSystem &getFileSystem();
 
+        DatOperationResult<> Initialise(const std::string &filename);
+        DatOperationResult<> GatherInformation(const std::string &output_filename);
+        DatOperationResult<> Deinitialize();
+        bool Initialized();
+
     private:
         std::unique_ptr<DatIO> io_;
         std::unique_ptr<DatFileSystem> fileSystem_;
         std::unique_ptr<DatLocaleManager> localeManager_;
-        std::unique_ptr<DatPatcher> patcher_;
-        std::unique_ptr<DatExporter> exporter_;
-        std::unique_ptr<DatBackupManager> backupManager_;
+//        std::unique_ptr<DatPatcher> patcher_;
+//        std::unique_ptr<DatExporter> exporter_;
+//        std::unique_ptr<DatBackupManager> backupManager_;
+        bool initialized_;
     };
 }
 }

+ 25 - 10
include/DatOperationResult.h

@@ -9,6 +9,8 @@
 #include <memory>
 #include <utility>
 #include <BinaryData.h>
+#include <EasyLogging++/easylogging++.h>
+
 extern "C++"
 {
 namespace LOTRO_DAT {
@@ -17,7 +19,8 @@ namespace LOTRO_DAT {
         ERROR = 0
     };
 
-    template<typename... OutputData> class DatOperationResult {
+    template<typename... OutputData>
+    class DatOperationResult {
         typedef DAT_OPERATION_RESULT RESULT;
     };
 
@@ -26,24 +29,32 @@ namespace LOTRO_DAT {
         typedef DAT_OPERATION_RESULT RESULT;
 
         __DatOperationResult_base() : result(SUCCESS), msg("No message") {}
+
         __DatOperationResult_base(const __DatOperationResult_base &other) = default;
+
         __DatOperationResult_base(__DatOperationResult_base &&other) noexcept = default;
 
-        __DatOperationResult_base(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {}
+        __DatOperationResult_base(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {
+            if (result_ == ERROR)
+                LOG(ERROR) << msg;
+        }
+
+        __DatOperationResult_base &operator=(const __DatOperationResult_base &other) = default;
 
-        __DatOperationResult_base &operator=(const __DatOperationResult_base& other) = default;
-        __DatOperationResult_base &operator=(__DatOperationResult_base&& other) = default;
+        __DatOperationResult_base &operator=(__DatOperationResult_base &&other) = default;
 
         RESULT result;
         std::string msg;
     };
 
-    template <>
+    template<>
     class DatOperationResult<> : public __DatOperationResult_base {
     public:
 
         DatOperationResult() : __DatOperationResult_base() {}
+
         explicit DatOperationResult(RESULT result_) : __DatOperationResult_base(result_, "No message") {}
+
         DatOperationResult(RESULT result_, std::string msg_) : __DatOperationResult_base(result_, std::move(msg_)) {}
     };
 
@@ -55,13 +66,17 @@ namespace LOTRO_DAT {
 
         DatOperationResult() = delete;
 
-        DatOperationResult(const DatOperationResult<Output>& other) :  __DatOperationResult_base(), value(other.value) {}
-        DatOperationResult(DatOperationResult<Output> &&other) noexcept : __DatOperationResult_base(), value(std::move(other.value)) {}
+        DatOperationResult(const DatOperationResult<Output> &other) : __DatOperationResult_base(), value(other.value) {}
+
+        DatOperationResult(DatOperationResult<Output> &&other) noexcept
+                : __DatOperationResult_base(), value(std::move(other.value)) {}
 
-        template <typename OutputRef>
-        DatOperationResult(OutputRef&& output_, RESULT result_, const std::string& msg_ = std::string("No message provided")) : __DatOperationResult_base(result_, msg_), value(std::forward<Output>(output_)) {}
+        template<typename OutputRef>
+        DatOperationResult(OutputRef &&output_, RESULT result_,
+                           const std::string &msg_ = std::string("No message provided")) : __DatOperationResult_base(
+                result_, msg_), value(std::forward<Output>(output_)) {}
 
-        operator Output() const {return value;}
+        operator Output() const { return value; }
 
         Output value;
     };

+ 2 - 1
include/DatSubsystems/DatFileSystem.h

@@ -75,7 +75,8 @@ namespace LOTRO_DAT {
         std::unordered_set<long long> visited_subfiles_ids_;
 
         std::set<SubDirectory, SubDirectory::SubDirectoryOffsetComparator> subdir_init_queue_;
-        std::unordered_map<long long, SubFile> subfile_init_queue_;
+        std::unordered_map<long long, SubFile> subfile_init_map_;
+        std::set<SubFile, SubFile::SubFileOffsetComparator> subfile_init_queue_;
     };
 }
 };

+ 5 - 4
include/DatSubsystems/DatLocaleManager.h

@@ -17,9 +17,9 @@ namespace LOTRO_DAT {
 
     class DatLocaleManager {
     public:
-        enum LOCALE {
-            PATCHED,
-            ORIGINAL
+        enum LOCALE : int {
+            ORIGINAL = 0,
+            PATCHED = 1
         };
 
         DatLocaleManager() = delete;
@@ -37,6 +37,8 @@ namespace LOTRO_DAT {
         void UpdateLocaleFile(LOCALE locale, const SubFile& file);
         DatOperationResult<SubFile> GetLocaleFile(long long file_id, LOCALE locale);
 
+        void PrintInformaion(FILE* file);
+
     private:
         std::map<long long, SubFile>& GetLocaleDictReference(LOCALE locale);
 
@@ -45,7 +47,6 @@ namespace LOTRO_DAT {
         std::map<long long, SubFile> orig_dict_;
         std::map<long long, SubFile> patch_dict_;
         std::set<long long> inactive_categories;
-
         LOCALE current_locale_;
     };
 }

+ 3 - 3
include/SubDirectory.h

@@ -16,11 +16,11 @@ namespace LOTRO_DAT {
             }
         };
 
-        SubDirectory() = delete;
+        SubDirectory() = default;
 
-        explicit SubDirectory(const SubDirectory &other) = delete;
+        SubDirectory(const SubDirectory &other) = default;
 
-        SubDirectory &operator=(const SubDirectory &other) = delete;
+        SubDirectory &operator=(const SubDirectory &other) = default;
 
         SubDirectory(long long unknown, long long offset);
 

+ 2 - 2
include/SubFile.h

@@ -25,9 +25,9 @@ namespace LOTRO_DAT
         friend class DatFileSystem;
 		friend class SubDirectory;
     public:
-        struct SubFileIdComparator {
+        struct SubFileOffsetComparator {
             bool operator() (const SubFile &f, const SubFile &s){
-                return f.file_id_ < s.file_id_;
+                return f.file_offset_ < s.file_offset_;
             }
         };
 

+ 98 - 22
src/DatFile.cpp

@@ -3,17 +3,19 @@
 //
 #define NOMINMAX
 
-#include "DatFile.h"
+#include <DatFile.h>
+#include <DatOperationResult.h>
 #include <EasyLogging++/easylogging++.h>
 
-#define ELPP_FEATURE_CRASH_LOG
-INITIALIZE_EASYLOGGINGPP
-
 #ifdef WIN32
 #define fseek _fseeki64
 #define ftell _ftelli64
 #endif
 
+#define VERSION "7.0.0"
+
+INITIALIZE_EASYLOGGINGPP
+
 extern "C++"
 {
 namespace LOTRO_DAT {
@@ -24,53 +26,127 @@ namespace LOTRO_DAT {
 
     DatFile::DatFile() {
         el::Configurations defaultConf;
+        el::Loggers::removeFlag(el::LoggingFlag::CreateLoggerAutomatically);
+        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 %fbase (line %line) : %msg (function: %func)");
+        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::ToStandardOutput, "true");
+        defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
         defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
         defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
-        defaultConf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1"); // Flush after every one log
 
         defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
-        defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "dat_library_debug.log");
+        defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "logs/dat_library_debug.log");
 
         el::Loggers::reconfigureAllLoggers(defaultConf);
+
         LOG(INFO) << "==================================================================";
         LOG(INFO) << "Starting new DatFile class instance";
 
         io_ = std::make_unique<DatIO>(this);
         fileSystem_ = std::make_unique<DatFileSystem>(this);
         localeManager_ = std::make_unique<DatLocaleManager>(this);
-        exporter_ = std::make_unique<DatExporter>(this);
-        patcher_ = std::make_unique<DatPatcher>(this);
-        backupManager_ = std::make_unique<DatBackupManager>(this);
+//        exporter_ = std::make_unique<DatExporter>(this);
+//        patcher_ = std::make_unique<DatPatcher>(this);
+//        backupManager_ = std::make_unique<DatBackupManager>(this);
     }
 
     LOTRO_DAT::DatLocaleManager &DatFile::getLocaleManager() {
         return *localeManager_;
     }
 
-    DatExporter &DatFile::getExporter() {
-        return *exporter_;
+//    DatExporter &DatFile::getExporter() {
+//        return *exporter_;
+//    }
+//
+//    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
+//        return *patcher_;
+//    }
+//
+//    DatBackupManager &DatFile::getBackupManager() {
+//        return *backupManager_;
+//    }
+
+    DatIO &DatFile::getIO() {
+        return *io_;
+    }
+
+    DatFileSystem &DatFile::getFileSystem() {
+        return *fileSystem_;
     }
 
-    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
-        return *patcher_;
+    DatOperationResult<> DatFile::Initialise(const std::string &filename) {
+        if (initialized_ && io_->GetFilename().result == SUCCESS && io_->GetFilename().value == filename)
+            return DatOperationResult<>();
+
+
+        auto operation = io_->Init(filename);
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
+
+        operation = fileSystem_->Init();
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
+
+        operation = localeManager_->Init();
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize. msg: " + operation.msg);
+
+
+        initialized_ = true;
+        return DatOperationResult<>();
     }
 
-    DatBackupManager &DatFile::getBackupManager() {
-        return *backupManager_;
+    DatOperationResult<> DatFile::GatherInformation(const std::string &output_filename) {
+        FILE *out = fopen(output_filename.c_str(), "w");
+        if (!out)
+            return DatOperationResult<>(ERROR, "GATHERDATINFO: Cannot open file " + output_filename);
+
+        fprintf(out, "########################################################################################\n"
+                     "# LOTRO Dat library version: %8s                                                  #\n"
+                     "# Author: Gi1dor (e1.gildor@gmail.com)                                                 #\n"
+                     "# 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);
+
+        io_->PrintInformaion(out);
+        fileSystem_->PrintInformaion(out);
+        localeManager_->PrintInformaion(out);
+
+        return DatOperationResult<>(SUCCESS);
     }
 
-    DatIO &DatFile::getIO() {
-        return *io_;
+    DatOperationResult<> DatFile::Deinitialize() {
+        if (!initialized_)
+            return DatOperationResult<>();
+
+        auto operation = localeManager_->DeInit();
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);
+
+        operation = fileSystem_->DeInit();
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);
+
+        operation = io_->DeInit();
+        if (operation.result != SUCCESS)
+            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);
+
+        return DatOperationResult<>();
     }
 
-    DatFileSystem &DatFile::getFileSystem() {
-        return *fileSystem_;
+
+    bool DatFile::Initialized() {
+        return initialized_;
     }
 }
 }

+ 54 - 29
src/DatSubsystems/DatFileSystem.cpp

@@ -32,7 +32,8 @@ namespace LOTRO_DAT {
 
         auto getfile_operation = GetFile(file_id);
         if (getfile_operation.result == ERROR)
-            return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DATFSGETFILEDATA: no file with id = " + std::to_string(file_id));
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR,
+                                                  "DATFSGETFILEDATA: no file with id = " + std::to_string(file_id));
 
         auto file = getfile_operation.value;
 
@@ -40,7 +41,8 @@ namespace LOTRO_DAT {
         BinaryData mfile_id(20);
         auto operation = CheckCorrectSubfile(file);
         if (operation.result == ERROR || !operation.value)
-            return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DATFSGETFILEDATA: Incorrect file" + std::to_string(file_id));
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR,
+                                                  "DATFSGETFILEDATA: Incorrect file" + std::to_string(file_id));
 
 
         BinaryData data((unsigned) (file->file_size() + (8 - offset)));
@@ -137,7 +139,8 @@ namespace LOTRO_DAT {
 
     DatOperationResult<bool> DatFileSystem::CheckCorrectSubfile(const std::shared_ptr<SubFile> &file) {
         if (!dat)
-            return DatOperationResult<bool>(false, ERROR, "DATFSCORRECTSUBFILE: no connection with Dat (dat is nullptr)");
+            return DatOperationResult<bool>(false, ERROR,
+                                            "DATFSCORRECTSUBFILE: no connection with Dat (dat is nullptr)");
 
         BinaryData mfile_id(20);
         auto operation = dat->getIO().ReadData(mfile_id, 20, file->file_offset() + 8);
@@ -154,7 +157,7 @@ namespace LOTRO_DAT {
      * \date 29.06.2018
      * Записывает все изменения структуры файловой системы в dat-файл. 
      */
-     
+
     DatOperationResult<> DatFileSystem::CommitDirectories() {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSCOMMITDIRS: no connection with Dat (dat is nullptr)");
@@ -189,7 +192,7 @@ namespace LOTRO_DAT {
      * \date 29.06.2018
      * Подготавливает файловую систему для работы 
      */
-     
+
     DatOperationResult<> DatFileSystem::Init() {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSINIT: no connection with Dat (dat is nullptr)");
@@ -208,19 +211,21 @@ namespace LOTRO_DAT {
      * 
      * \return Вернёт DatOperationResult<>(ERROR), если случилась ошибка записи структуры файлов в dat файл
      */
-    
+
     DatOperationResult<> DatFileSystem::DeInit() {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSDEINIT: no connection with Dat (dat is nullptr)");
 
         auto operation = CommitDirectories();
+
         dictionary_.clear();
 
         visited_subdirectories_offsets_.clear();
         visited_subfiles_ids_.clear();
 
-        subfile_init_queue_.clear();
         subdir_init_queue_.clear();
+        subfile_init_map_.clear();
+        subfile_init_queue_.clear();
 
         subfile_pending_update.clear();
 
@@ -229,7 +234,7 @@ namespace LOTRO_DAT {
         return DatOperationResult<>(SUCCESS);
     }
 
-    
+
     /*!
      * \author Gi1dor
      * \date 29.06.2018
@@ -243,11 +248,13 @@ namespace LOTRO_DAT {
             LOG(ERROR) << "DATFSPRINTINFO: no connection with Dat (dat is nullptr)";
             return;
         }
-        
+
         InitAllFiles();
 
         fprintf(file, "============= FS INFO SECTION =============\n");
-        fprintf(file, "Files number: %d\n", dictionary_.size());
+        fprintf(file, "Files in dictionary number: %d\n", dictionary_.size());
+        fprintf(file, "Files visited: %d\n", visited_subfiles_ids_.size());
+        fprintf(file, "Folders visited: %d\n", visited_subdirectories_offsets_.size());
 
         std::vector<size_t> filetypes_count(7, 0);
 
@@ -280,24 +287,36 @@ namespace LOTRO_DAT {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSINITSUBFILE: no connection with Dat (dat is nullptr)");
 
-
-        while (subfile_init_queue_.count(file_id) == 0) {
+        while (subfile_init_map_.count(file_id) == 0) {
             if (subdir_init_queue_.empty())
                 return DatOperationResult<>(ERROR,
                                             "DATFSINITSUBFILE: Cannot init file with id = "
                                             + std::to_string(file_id) + " (NOT FOUND)");
 
             SubDirectory dir = *subdir_init_queue_.begin();
-            InitSubDirectory(dir);
             subdir_init_queue_.erase(subdir_init_queue_.begin());
+            InitSubDirectory(dir);
         }
 
-        SubFile file = subfile_init_queue_[file_id];
-        subfile_init_queue_.erase(file_id);
-
+        SubFile file = subfile_init_map_[file_id];
+        subfile_init_queue_.erase(file);
+        subfile_init_map_.erase(file_id);
 
         auto initialised_file = SubFile::MakeSubfile(*dat, file);
-        dictionary_[initialised_file->file_id()] = initialised_file;
+
+        if (dictionary_.count(file_id) > 0 && CheckCorrectSubfile(initialised_file)) {
+            LOG(WARNING) << "Dublicate files id = " << file_id << "dictionary offsets = "
+                         << dictionary_[file_id]->dictionary_offset() << " and "
+                         << initialised_file->dictionary_offset();
+            if (CheckCorrectSubfile(dictionary_[file_id]))
+                LOG(ERROR) << "    FILE IN DICTIONARY IS ALREADY CORRECT!";
+
+            dictionary_[file_id] = initialised_file;
+        }
+
+        if (dictionary_.count(file_id) == 0)
+            dictionary_[file_id] = initialised_file;
+
         return DatOperationResult<>();
     }
 
@@ -317,8 +336,8 @@ namespace LOTRO_DAT {
 
         while (!subdir_init_queue_.empty()) {
             SubDirectory dir = *subdir_init_queue_.begin();
-            InitSubDirectory(dir);
             subdir_init_queue_.erase(subdir_init_queue_.begin());
+            InitSubDirectory(dir);
         }
         return DatOperationResult<>();
     }
@@ -337,10 +356,11 @@ namespace LOTRO_DAT {
             return DatOperationResult<>(ERROR, "DATFSINITALLFILES: no connection with Dat (dat is nullptr)");
 
         InitAllDirectories();
+        std::cout << "DONE ALL DIRS" << std::endl;
+
         while (!subfile_init_queue_.empty()) {
-            long long file_id = (*subfile_init_queue_.begin()).first;
-            InitSubFile(file_id);
-            subfile_init_queue_.erase(file_id);
+            SubFile file = *subfile_init_queue_.begin();
+            InitSubFile(file.file_id());
         }
         return DatOperationResult<>();
     }
@@ -371,23 +391,28 @@ namespace LOTRO_DAT {
      * block_size - размер блока данных, выделенного под файл
 	 * unknown2 - неизвестное поле
      *
-     * \param[in] dir Указатель на объект папки
+     * \param[in] dir объект папки SubDirectory
      * \return Объект DatOperationResult
      */
 
     DatOperationResult<> DatFileSystem::InitSubDirectory(SubDirectory dir) {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSINITSUBDIR: no connection with Dat (dat is nullptr)");
-
         BinaryData subdir_data(63 * 8 + 4 + 32 * 64);
         auto operation = dat->getIO().ReadData(subdir_data, 63 * 8 + 4 + 32 * 64, dir.offset());
-        if (!operation.result == SUCCESS)
+        if (operation.result == ERROR)
             return DatOperationResult<>(ERROR, "DATFSINITSUBDIR: cannot init dir (read error) with offset = " +
                                                std::to_string((dir.offset())));
 
         if (subdir_data.ToNumber<4>(0) != 0 || subdir_data.ToNumber<4>(4) != 0)
             return DatOperationResult<>(ERROR, "DATFSINITSUBDIR: incorrect dir. Nulls must be at first 8 bytes of dir");
 
+        // Subfiles section
+        long long subfiles_number = subdir_data.ToNumber<4>(63 * 8);
+        if (subfiles_number >= 64)
+            return DatOperationResult<>(ERROR, "DATINITSUBDIR: incorrect subdir: files number > 64");
+
+
         // Subdirs section
         for (unsigned i = 8; i < 63 * 8; i += 8) {
             if (subdir_data.ToNumber<4>(i) == 0 || subdir_data.ToNumber<4>(i + 4) == 0)
@@ -396,6 +421,9 @@ namespace LOTRO_DAT {
             long long unknown = subdir_data.ToNumber<4>(i);
             long long offset = subdir_data.ToNumber<4>(i + 4);
 
+            if (unknown == 0 || offset == 0)
+                break;
+
             if (visited_subdirectories_offsets_.count(offset) != 0)
                 continue;
 
@@ -403,11 +431,7 @@ namespace LOTRO_DAT {
             subdir_init_queue_.insert(SubDirectory(unknown, offset));
         }
 
-        // Subfiles section
-        long long subfiles_number = subdir_data.ToNumber<4>(63 * 8);
-        if (subfiles_number >= 64)
-            return DatOperationResult<>(ERROR, "DATINITSUBDIR: incorrect subdir: files number > 64");
-
+        // Subfiles' section
 
         for (int i = 0; i < subfiles_number; i++) {
             long long header_start = 63 * 8 + 4 + 32 * i;
@@ -432,6 +456,7 @@ namespace LOTRO_DAT {
                 break;
 
             visited_subfiles_ids_.insert(file.file_id());
+            subfile_init_map_[file.file_id_] = file;
             subfile_init_queue_.insert(file);
         }
         return DatOperationResult<>();

+ 32 - 13
src/DatSubsystems/DatLocaleManager.cpp

@@ -105,24 +105,19 @@ namespace LOTRO_DAT {
         for (const auto &file : dict) {
             long long file_id = file.first;
 
-            if (!dat->getFileSystem().FileExists(file_id)) {
-                LOG(WARNING) << "In locale dictionary there is file with file_id = " << file_id
-                             << "which is not in .dat file! Passing it and removing from locale dictionary";
-                dict.erase(file_id);
-                continue;
-            }
-
             auto dict_file_result = dat->getFileSystem().GetFile(file_id);
             if (dict_file_result.result != SUCCESS) {
-                LOG(WARNING) << "Unable to get file with id = " << file_id << "from datFileSystem! Error msg:" << dict_file_result.msg;
+                LOG(WARNING) << "Unable to get file with id = " << file_id << "from datFileSystem!";
+                dict.erase(file_id);
                 continue;
             }
-            SubFile dict_file = dict_file_result.value;
 
-            if (dict_file.MakeHeaderData().CutData(8, 16) == file.second.MakeHeaderData().CutData(8, 16))
+            std::shared_ptr<SubFile> dict_file = dict_file_result.value;
+
+            if (dict_file->MakeHeaderData().CutData(8, 16) == file.second.MakeHeaderData().CutData(8, 16))
                 continue;
 
-            dat->getFileSystem().UpdateFile(file.second);
+            dat->getFileSystem().UpdateFileInfo(file.second);
         }
         current_locale_ = locale;
         return DatOperationResult<>(SUCCESS);
@@ -224,8 +219,32 @@ namespace LOTRO_DAT {
         return DatOperationResult<SubFile>(dict[file_id], SUCCESS);
     }
 
-
     std::map<long long, SubFile> &DatLocaleManager::GetLocaleDictReference(DatLocaleManager::LOCALE locale) {
-        return current_locale_ == PATCHED ? patch_dict_ : orig_dict_;
+        return locale == PATCHED ? patch_dict_ : orig_dict_;
+    }
+
+    void DatLocaleManager::PrintInformaion(FILE *file) {
+        fprintf(file, "========= Locales info ========\n");
+        BinaryData locale_offset_data(4);
+        dat->getIO().ReadData(locale_offset_data, 4, 300);
+        long long locale_offset = locale_offset_data.ToNumber<4>(0);
+
+        fprintf(file, "Locales' dictionary offset = %lld\n", locale_offset);
+
+        if (locale_offset != 0) {
+            BinaryData locale_info(12);
+            dat->getIO().ReadData(locale_info, 12, locale_offset);
+
+            long long dict_size = locale_info.ToNumber<4>(0);
+            long long dict_version = locale_info.ToNumber<4>(4);
+
+            fprintf(file, "Locales' dictionary size = %lld, version = %lld\n", dict_size, dict_version);
+
+            dat->getIO().file_size = locale_info.ToNumber<4>(8);
+        }
+
+        fprintf(file, "Current locale id = %d\n", current_locale_);
+        fprintf(file, "Patch dictionary size = %d\n", patch_dict_.size());
+        fprintf(file, "Original dictionary size = %d\n", orig_dict_.size());
     }
 }