Browse Source

INCOMPLETE. Restructured DatFile class. Created subclasses. Need to implement all DatSubsystems classes

Ivan Arkhipov 6 years ago
parent
commit
83083a432a

+ 26 - 12
CMakeLists.txt

@@ -5,12 +5,12 @@ set(CMAKE_CXX_STANDARD 14)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 5.2.0)
 
-SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O3 -Wall -Wextra")
-SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O3 -Wall -Wextra")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
 
 if (MSVS)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} /MT /SAFESEH:NO")
-endif(MSVS)
+endif (MSVS)
 
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
@@ -40,7 +40,14 @@ set(HEADER_FILES
         ${CMAKE_SOURCE_DIR}/include/Subfiles/FontSubfile.h
         ${CMAKE_SOURCE_DIR}/include/Subfiles/WavSubfile.h
         ${CMAKE_SOURCE_DIR}/include/Subfiles/UnknownSubfile.h
-        src/DatFileIO.cpp include/DatFileIO.h src/DatFileExporter.cpp include/DatFileExporter.h src/DatFilePatcher.cpp include/DatFilePatcher.h include/DatOperationResult.h)
+
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatBackupManager.h
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatExporter.h
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatFileSystem.h
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatIO.h
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatLocaleManager.h
+        ${CMAKE_SOURCE_DIR}/include/DatSubsystems/DatPatcher.h
+        )
 
 set(SOURCE_FILES
         ${CMAKE_SOURCE_DIR}/src/DatFile.cpp
@@ -59,7 +66,14 @@ set(SOURCE_FILES
 
         ${CMAKE_SOURCE_DIR}/Third_party/SQLite/sqlite3.c
         ${CMAKE_SOURCE_DIR}/Third_party/EasyLogging++/easylogging++.cc
-        src/DatFileIO.cpp include/DatFileIO.h src/DatFileExporter.cpp include/DatFileExporter.h src/DatFilePatcher.cpp include/DatFilePatcher.h include/DatOperationResult.h)
+
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatBackupManager.cpp
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatExporter.cpp
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatFileSystem.cpp
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatIO.cpp
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatLocaleManager.cpp
+        ${CMAKE_SOURCE_DIR}/src/DatSubsystems/DatPatcher.cpp
+        )
 
 set(CompilerFlags
         CMAKE_CXX_FLAGS
@@ -74,9 +88,9 @@ set(CompilerFlags
         CMAKE_C_FLAGS_RELWITHDEBINFO
         )
 
-foreach(CompilerFlag ${CompilerFlags})
+foreach (CompilerFlag ${CompilerFlags})
     string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
-endforeach()
+endforeach ()
 
 # STATIC LIBRARY
 add_library(LotroDat_static STATIC ${SOURCE_FILES} ${HEADER_FILES})
@@ -87,14 +101,14 @@ add_executable(LotRO_dat_extractor ${SOURCE_FILES} ${HEADER_FILES} ${CMAKE_SOURC
 # CONSOLE PATCHER TOOL
 add_executable(LotRO_dat_patcher ${SOURCE_FILES} ${HEADER_FILES} ${CMAKE_SOURCE_DIR}/src/Examples/patcher_example.cpp)
 
-foreach(TARGET LotroDat_static LotroDat LotRO_dat_extractor LotRO_dat_patcher)
+foreach (TARGET LotroDat_static LotroDat LotRO_dat_extractor LotRO_dat_patcher)
     #if(MSVC)
     #    target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/Zlib/zlibstatic.lib)
     #    target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/Yaml-cpp/libyaml-cppmt.lib)
     #    target_link_libraries(${TARGET} vcruntime.lib MSVCRT.lib)
     #else(MSVC)
-        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/lib/libzlibstatic.a)
-        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/lib/libyaml-cpp.a)
-        target_link_libraries(${TARGET} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
+    target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/lib/libzlibstatic.a)
+    target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Third_Party/lib/libyaml-cpp.a)
+    target_link_libraries(${TARGET} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
     #endif(MSVC)
-endforeach(TARGET LotroDat_static LotroDat LotRO_dat_extractor LotRO_dat_patcher)
+endforeach (TARGET LotroDat_static LotroDat LotRO_dat_extractor LotRO_dat_patcher)

BIN
bin/LotRO_dat_patcher.exe


+ 2 - 1
include/BinaryData.h

@@ -21,7 +21,8 @@ namespace LOTRO_DAT
     public:
         BinaryData();
         BinaryData(const BinaryData &d);
-        explicit BinaryData(const char* data, unsigned int size);
+        BinaryData(BinaryData&& other) noexcept;
+        BinaryData(const char* data, unsigned int size);
         explicit BinaryData(unsigned int size);
         ~BinaryData();
 

+ 30 - 180
include/DatFile.h

@@ -11,32 +11,19 @@
 #define LOTRO_DAT_API __declspec(dllimport)
 #endif
 
-#include <fstream>
-#include <map>
-#include <unordered_map>
-#include <set>
-#include <vector>
-#include <yaml-cpp/node/node.h>
-#include <unordered_set>
-
-#include "Database.h"
-#include "DatFileIO.h"
+#include <bits/unique_ptr.h>
+#include "DatSubsystems/DatBackupManager.h"
+#include "DatSubsystems/DatExporter.h"
+#include "DatSubsystems/DatFileSystem.h"
+#include "DatSubsystems/DatIO.h"
+#include "DatSubsystems/DatLocaleManager.h"
+#include "DatSubsystems/DatPatcher.h"
 
 // Dat file names definitions
 
 extern "C++"
 {
 namespace LOTRO_DAT {
-    class BinaryData;
-
-    class DatException;
-
-    class SubDirectory;
-
-    class SubFile;
-
-    class SubfileData;
-
     enum FILE_TYPE : int {
         TEXT,
         JPG,
@@ -47,172 +34,35 @@ namespace LOTRO_DAT {
         UNKNOWN
     };
 
-    enum DAT_RESULT : int {
-        //----BASE----///
-        FAILED = 0,
-        SUCCESS = 1,
-
-        //----WARNINGS----//
-        CORRUPTED_FILE_WARNING = 2,
-
-        //----ERRORS----//
-        INCORRECT_STATE_ERROR = -1,
-        NO_FILE_ERROR = -2,
-        WRITE_TO_FILE_ERROR = -3,
-        INCORRECT_DAT_ID = -4,
-        INCORRECT_SUPERBLOCK_ERROR = -5,
-        INIT_ERROR = -6,
-        DUBLICATE_PATCH_FILES_ERROR = -8,
-        INCORRECT_PATCH_FILE = -9,
-        DAT_PATCH_FILE_ERROR = -10,
-        DAT_READ_ERROR = -11,
-        DAT_WRITE_ERROR = -12,
-        CRITICAL_DAT_ERROR = -14,
-        NO_BACKUP_ERROR = -15,
-        REMOVE_FILE_ERROR = -16
-    };
-
-    enum DAT_STATE {
-        CLOSED = 1,
-        SUCCESS_OPENED = 2,
-        SUCCESS_SUPERBLOCK = 3,
-        SUCCESS_DIRECTORIES = 4,
-        SUCCESS_DICTIONARY = 5,
-        READY = 6,
-        UPDATED = 7
-    };
-
-    enum LOCALE : unsigned {
-        ORIGINAL = 0,
-        PATCHED = 1
-    };
-
     class DatFile {
-        friend class SubDirectory;
+        friend class DatIO;
+        friend class DatFileSystem;
+        friend class DatLocaleManager;
+        friend class DatPatcher;
+        friend class DatExporter;
+        friend class DatBackupManager;
 
     public:
         DatFile();
-        explicit DatFile(const DatFile &other) = delete;
-        DatFile& operator=(const DatFile &other) = delete;
-
-        DAT_RESULT InitDatFile(const std::string &filename, int dat_id);
-
-        DAT_STATE DatFileState() const;
-
-        DAT_RESULT PerformDictionaryCheck();
-
-        DAT_RESULT ModifyFragmentationJournal();
-
-        ~DatFile();
-
-        // EXTRACT BASE SECTION
-
-        DAT_RESULT ExtractFile(long long file_id, const std::string &path = "");
-
-        DAT_RESULT ExtractFile(long long file_id, Database *db);
-
-        int ExtractAllFilesByType(FILE_TYPE type, std::string path = "");
-
-        int ExtractAllFilesByType(FILE_TYPE type, Database *db);
-
-        // PATCH BASE SECTION
-
-        //DAT_RESULT PatchFile(const char *filename, YAML::Node options);
-
-        DAT_RESULT PatchFile(const SubfileData &data);
-
-        DAT_RESULT PatchAllDatabase(Database *db);
-
-
-        long long files_number() const;
-
-        const std::string& filename() const;
-
-        BinaryData GetFileData(const std::shared_ptr<SubFile>& file, long long offset = 0);
-
-        DAT_RESULT CloseDatFile();
-
-    private:
-        DAT_RESULT MakeDictionary();
-
-        // PATCH SECTION
+        DatFile(const DatFile &other) = delete;
+        DatFile(DatFile &&other) = default;
+        DatFile &operator=(const DatFile &other) = delete;
+        DatFile &operator=(DatFile &&other) = default;
+
+        DatLocaleManager &getLocaleManager();
+        DatExporter &getExporter();
+        DatPatcher &getPatcher();
+        DatBackupManager &getBackupManager();
+        DatIO &getIO();
+        DatFileSystem &getFileSystem();
 
-        DAT_RESULT ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data);
-
-    private:
-        long long free_buffered_size_;
-
-        const unsigned MAX_BUFFERED_SIZE = 10 * 1024 * 1024; // 50 megabytes;
-        const unsigned MIN_BUFFERED_SIZE = 1 * 1024 * 1024; // 5 megabytes;
-
-        void AddBufferedSize();
-
-
-        // LOCALE MANAGING SECTION
-    private:
-        DAT_RESULT InitLocales();
-
-        DAT_RESULT CommitLocales();
-
-        DAT_RESULT CommitDirectories();
-
-    public:
-        DAT_RESULT SetLocale(LOCALE locale);
-
-        LOCALE current_locale();
-
-        // CATEGORY MANAGEMENT SECTION
-
-        DAT_RESULT EnableCategory(int category);
-
-        DAT_RESULT DisableCategory(int category);
-
-        const std::set<long long>& GetInactiveCategoriesList();
-
-        // SOME PRIOR TOOLS
-
-        DAT_RESULT RepairDatFile();
-
-        bool CorrectSubfile(std::shared_ptr<SubFile> file);
-
-        bool CheckIfUpdatedByGame();
-
-        DAT_RESULT WriteUnorderedDictionary(std::string path) const;
-
-        bool CheckIfNotPatched();
-
-        bool CheckIfPatchedByOldLauncher();
-
-        bool CheckIfBackupExists(const std::string &backup_datname);
-
-        DAT_RESULT CreateBackup(const std::string &backup_datname);
-
-        DAT_RESULT RestoreFromBackup(const std::string &backup_datname);
-
-        DAT_RESULT RemoveBackup(const std::string &backup_datname);
     private:
-        std::map<long long, std::shared_ptr<SubFile>>& GetLocaleDictReference(LOCALE locale);
-
-    private:
-        LOCALE current_locale_;
-
-        std::string filename_;
-
-        std::map<long long, std::shared_ptr<SubFile>> orig_dict_;
-        std::map<long long, std::shared_ptr<SubFile>> patch_dict_;
-        std::set<long long> pending_patch_;
-        std::set<long long> inactive_categories;
-
-    private:
-        DatFileIO io;
-
-        std::set<long long> pending_dictionary_;
-        std::map<long long, std::shared_ptr<SubFile> > dictionary_;
-
-        DAT_STATE dat_state_;
-
-        int dat_id_;
-        bool dat_without_patches_;
+        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_;
     };
 }
 }

+ 0 - 14
include/DatFileExporter.h

@@ -1,14 +0,0 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
-#ifndef LOTRO_DAT_LIBRARY_DATFILEEXPORTER_H
-#define LOTRO_DAT_LIBRARY_DATFILEEXPORTER_H
-
-
-class DatFileExporter {
-
-};
-
-
-#endif //LOTRO_DAT_LIBRARY_DATFILEEXPORTER_H

+ 0 - 95
include/DatFileIO.h

@@ -1,95 +0,0 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
-#ifndef LOTRO_DAT_LIBRARY_DATFILEIO_H
-#define LOTRO_DAT_LIBRARY_DATFILEIO_H
-
-#include <fstream>
-#include <map>
-#include <unordered_map>
-#include <set>
-#include <vector>
-#include <yaml-cpp/node/node.h>
-#include <unordered_set>
-
-
-namespace LOTRO_DAT {
-    class BinaryData;
-
-    class DatFile;
-
-    class DatOperationResult;
-
-    class SubDirectory;
-
-    class SubFile;
-
-    class DatFileIO {
-    public:
-        DatFileIO() = delete;
-
-        DatFileIO(const DatFileIO &other) = delete;
-
-        explicit DatFileIO(DatFile &dat_ref);
-
-        DatOperationResult Init(const std::string &filename);
-
-        DatOperationResult
-        ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0) const;
-
-        DatOperationResult
-        WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
-
-        std::shared_ptr<SubDirectory> GetRootDirectory();
-
-        long long GetActualDatSize();
-
-        DatOperationResult DeInit();
-
-    private:
-
-        //------------------------------------------------//
-        // PRIVATE INIT SECTION
-        //------------------------------------------------//
-
-        DatOperationResult OpenDatFile();
-
-        DatOperationResult ReadSuperBlock();
-
-        DatOperationResult MakeDirectories();
-
-
-        //------------------------------------------------//
-        // PRIVATE DEINIT SECTION
-        //------------------------------------------------//
-
-        DatOperationResult ModifyFragmentationJournal();
-
-        DatOperationResult UpdateHeader();
-
-    private:
-        DatFile &dat_file_ref;
-        FILE *file_handler_;
-        std::string filename_;
-
-        std::shared_ptr<SubDirectory> root_directory_;
-
-    public:
-        long long constant1;
-        long long constant2;
-        long long file_size;
-        long long version1;
-        long long version2;
-        long long fragmentation_journal_size;
-        long long fragmentation_journal_end;
-        long long root_directory_offset;
-        long long fragmentation_journal_offset;
-        long long free_dat_size;
-
-    private:
-        long long actual_dat_size_;
-    };
-};
-#endif //LOTRO_DAT_LIBRARY_DATFILEIO_H
-

+ 0 - 14
include/DatFilePatcher.h

@@ -1,14 +0,0 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
-#ifndef LOTRO_DAT_LIBRARY_DATFILEPATCHER_H
-#define LOTRO_DAT_LIBRARY_DATFILEPATCHER_H
-
-
-class DatFilePatcher {
-
-};
-
-
-#endif //LOTRO_DAT_LIBRARY_DATFILEPATCHER_H

+ 46 - 8
include/DatOperationResult.h

@@ -6,25 +6,63 @@
 #define LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H
 
 #include <string>
+#include <memory>
 #include <utility>
-
+#include <BinaryData.h>
 extern "C++"
 {
 namespace LOTRO_DAT {
-    class DatOperationResult {
+    enum DAT_OPERATION_RESULT {
+        SUCCESS = 1,
+        ERROR = 0
+    };
+
+    template<typename... OutputData> class DatOperationResult {
+        typedef DAT_OPERATION_RESULT RESULT;
+    };
+
+    class __DatOperationResult_base {
     public:
-        enum RESULT {
-            SUCCESS = 1,
-            ERROR = 0
-        };
+        typedef DAT_OPERATION_RESULT RESULT;
 
-        DatOperationResult(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {}
+        __DatOperationResult_base() : result(SUCCESS), msg("No message") {}
+        __DatOperationResult_base(const __DatOperationResult_base &other) = default;
+        __DatOperationResult_base(__DatOperationResult_base &&other) noexcept = default;
 
-        DatOperationResult &operator=(const DatOperationResult &other) = default;
+        __DatOperationResult_base(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {}
+
+        __DatOperationResult_base &operator=(const __DatOperationResult_base& other) = default;
+        __DatOperationResult_base &operator=(__DatOperationResult_base&& other) = default;
 
         RESULT result;
         std::string msg;
     };
+
+    template <>
+    class DatOperationResult<> : public __DatOperationResult_base {
+    public:
+
+        DatOperationResult() : __DatOperationResult_base() {}
+        DatOperationResult(RESULT result_, std::string msg_) : __DatOperationResult_base(result_, msg_) {}
+    };
+
+
+    template<typename Output>
+    class DatOperationResult<Output> : public __DatOperationResult_base {
+    public:
+        typedef DAT_OPERATION_RESULT RESULT;
+
+        DatOperationResult() = delete;
+
+        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_)) {}
+
+        Output value;
+    };
+
 }
 }
 

+ 46 - 0
include/DatSubsystems/DatBackupManager.h

@@ -0,0 +1,46 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATBACKUP_H
+#define LOTRO_DAT_LIBRARY_DATBACKUP_H
+
+#include <string>
+#include <DatOperationResult.h>
+
+extern "C++" {
+namespace LOTRO_DAT {
+    class DatFile;
+
+    class DatBackupManager {
+    public:
+        DatBackupManager() = delete;
+
+        DatBackupManager(const DatBackupManager &other) = delete;
+
+        DatBackupManager &operator=(const DatBackupManager &other) = delete;
+
+        ~DatBackupManager() = default;
+
+        explicit DatBackupManager(DatFile *datFilePtr);
+
+        void Init();
+
+        bool CheckIfBackupExists(const std::string &backup_datname);
+
+        DatOperationResult<> CreateBackup(const std::string &backup_datname);
+
+        DatOperationResult<> RestoreFromBackup(const std::string &backup_datname);
+
+        DatOperationResult<> RemoveBackup(const std::string &backup_datname);
+
+        void DeInit();
+
+    private:
+        DatFile *dat;
+
+    };
+}
+};
+
+#endif //LOTRO_DAT_LIBRARY_DATBACKUP_H

+ 28 - 0
include/DatSubsystems/DatExporter.h

@@ -0,0 +1,28 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATEXPORTER_H
+#define LOTRO_DAT_LIBRARY_DATEXPORTER_H
+
+extern "C++" {
+namespace LOTRO_DAT {
+    class DatFile;
+
+    class DatExporter {
+    public:
+        DatExporter() = delete;
+        DatExporter(const DatExporter &other) = delete;
+        DatExporter& operator=(const DatExporter &other) = delete;
+        ~DatExporter() = default;
+
+        explicit DatExporter(DatFile *datFilePtr);
+
+    private:
+        DatFile *dat;
+
+    };
+}
+};
+
+#endif //LOTRO_DAT_LIBRARY_DATEXPORTER_H

+ 62 - 0
include/DatSubsystems/DatFileSystem.h

@@ -0,0 +1,62 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATFILESYSTEM_H
+#define LOTRO_DAT_LIBRARY_DATFILESYSTEM_H
+
+#include <set>
+#include <map>
+#include <utility>
+#include <memory>
+#include "DatOperationResult.h"
+
+extern "C++" {
+namespace LOTRO_DAT {
+    class DatFile;
+    class BinaryData;
+    class SubFile;
+
+    class DatFileSystem {
+    public:
+        DatFileSystem() = delete;
+        DatFileSystem(const DatFileSystem &other) = delete;
+        DatFileSystem& operator=(const DatFileSystem &other) = delete;
+        ~DatFileSystem() = default;
+
+        explicit DatFileSystem(DatFile *datFilePtr);
+
+        DatOperationResult<> Init();
+
+        DatOperationResult<BinaryData> GetFileData(long long file_id, long long int offset);
+
+        DatOperationResult<SubFile> GetFile(long long file_id);
+
+        DatOperationResult<> UpdateFile(const SubFile& file);
+
+        DatOperationResult<> DeInit();
+
+    private:
+        //------------------------------------------------//
+        // PRIVATE INIT SECTION
+        //------------------------------------------------//
+
+        DatOperationResult<> MakeDirectories();
+
+        DatOperationResult<> MakeDictionary();
+
+        //------------------------------------------------//
+        // PRIVATE DEINIT SECTION
+        //------------------------------------------------//
+
+        DatOperationResult<> CommitDirectories();
+
+    private:
+        DatFile *dat;
+        std::set<long long> subfile_pending_update;
+        std::map<long long, std::shared_ptr<SubFile> > dictionary_;
+    };
+}
+};
+
+#endif //LOTRO_DAT_LIBRARY_DATFILESYSTEM_H

+ 84 - 0
include/DatSubsystems/DatIO.h

@@ -0,0 +1,84 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATIO_H
+#define LOTRO_DAT_LIBRARY_DATIO_H
+
+#include <utility>
+#include "DatOperationResult.h"
+
+extern "C++" {
+namespace LOTRO_DAT {
+    class BinaryData;
+
+    class DatFile;
+
+    class SubDirectory;
+
+    class SubFile;
+
+
+    class DatIO {
+    public:
+        DatIO() = delete;
+        DatIO(const DatIO &other) = delete;
+        DatIO& operator=(const DatIO &other) = delete;
+        ~DatIO() = default;
+
+        explicit DatIO(DatFile *datFilePtr);
+
+        DatOperationResult<> Init(const std::string &filename);
+
+        DatOperationResult<> ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0) const;
+
+        DatOperationResult<> WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
+
+        DatOperationResult<long long> GetActualDatSize();
+
+        DatOperationResult<std::string> GetFilename();
+
+        DatOperationResult<> DeInit();
+
+    private:
+
+        //------------------------------------------------//
+        // PRIVATE INIT SECTION
+        //------------------------------------------------//
+
+        DatOperationResult<> OpenDatFile();
+
+        DatOperationResult<> ReadSuperBlock();
+
+        //------------------------------------------------//
+        // PRIVATE DEINIT SECTION
+        //------------------------------------------------//
+
+        DatOperationResult<> ModifyFragmentationJournal();
+
+        DatOperationResult<> UpdateHeader();
+
+    private:
+        DatFile *dat;
+        FILE *file_handler_;
+        std::string filename_;
+
+    public:
+        long long constant1;
+        long long constant2;
+        long long file_size;
+        long long version1;
+        long long version2;
+        long long fragmentation_journal_size;
+        long long fragmentation_journal_end;
+        long long root_directory_offset;
+        long long fragmentation_journal_offset;
+        long long free_dat_size;
+
+    private:
+        long long actual_dat_size_;
+    };
+}
+};
+#endif //LOTRO_DAT_LIBRARY_DATIO_H
+

+ 28 - 0
include/DatSubsystems/DatLocaleManager.h

@@ -0,0 +1,28 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATLOCALEMANAGER_H
+#define LOTRO_DAT_LIBRARY_DATLOCALEMANAGER_H
+
+extern "C++" {
+namespace LOTRO_DAT {
+    class DatFile;
+
+    class DatLocaleManager {
+    public:
+        DatLocaleManager() = delete;
+        DatLocaleManager(const DatLocaleManager &other) = delete;
+        DatLocaleManager& operator=(const DatLocaleManager &other) = delete;
+        ~DatLocaleManager() = default;
+
+        explicit DatLocaleManager(DatFile *datFilePtr);
+
+    private:
+        DatFile *dat;
+
+    };
+}
+};
+
+#endif //LOTRO_DAT_LIBRARY_DATLOCALEMANAGER_H

+ 48 - 0
include/DatSubsystems/DatPatcher.h

@@ -0,0 +1,48 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATPATCHER_H
+#define LOTRO_DAT_LIBRARY_DATPATCHER_H
+
+#include "yaml-cpp/yaml.h"
+#include <DatOperationResult.h>
+
+extern "C++"
+{
+namespace LOTRO_DAT {
+    class DatFile;
+    class SubfileData;
+    class SubFile;
+    class Database;
+    class BinaryData;
+
+    class DatPatcher {
+    public:
+        DatPatcher() = delete;
+        DatPatcher(const DatPatcher &other) = delete;
+        DatPatcher& operator=(const DatPatcher &other) = delete;
+        ~DatPatcher() = default;
+
+        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();
+
+    private:
+        DatOperationResult<> ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data);
+
+    private:
+        DatFile *dat;
+    };
+}
+}
+
+#endif //LOTRO_DAT_LIBRARY_DATFILEPATCHER_H

BIN
lib/libLotroDat_static.a


+ 9 - 1
src/BinaryData.cpp

@@ -7,6 +7,8 @@
 #include "EasyLogging++/easylogging++.h"
 
 #include <algorithm>
+#include <BinaryData.h>
+
 
 extern  "C++"
 {
@@ -23,6 +25,13 @@ namespace LOTRO_DAT {
         memcpy(data_, d.data_, size_);
     }
 
+    BinaryData::BinaryData(BinaryData &&other) noexcept {
+        size_ = other.size_;
+        data_ = other.data_;
+        other.size_ = 0;
+        other.data_ = nullptr;
+    }
+
     BinaryData::BinaryData(const char* data, unsigned int size) {
         size_ = size;
         data_ = new unsigned char[size_];
@@ -266,7 +275,6 @@ namespace LOTRO_DAT {
         memcpy(data_ + append_offset, b.data_, b.size_);
     }
 
-
     template long long BinaryData::ToNumber<1>(long long const&) const;
     template long long BinaryData::ToNumber<2>(long long const&) const;
     template long long BinaryData::ToNumber<4>(long long const&) const;

+ 21 - 1042
src/DatFile.cpp

@@ -2,19 +2,9 @@
 // Created by Иван_Архипов on 31.10.2017.
 //
 #define NOMINMAX
-#include "DatFile.h"
-#include "BinaryData.h"
-
-#include "SubDirectory.h"
-#include "SubFile.h"
-#include "SubfileData.h"
-#include "DatOperationResult.h"
 
+#include "DatFile.h"
 #include <EasyLogging++/easylogging++.h>
-//#include <unistd.h>
-#include <algorithm>
-#include <iterator>
-#include <locale>
 
 #define ELPP_FEATURE_CRASH_LOG
 INITIALIZE_EASYLOGGINGPP
@@ -32,21 +22,14 @@ namespace LOTRO_DAT {
     // INIT SECTION
     //------------------------------------------------//
 
-    DatFile::DatFile() : io(*this) {
-        dat_state_ = CLOSED;
-        free_buffered_size_ = 0;
-
-        orig_dict_.clear();
-        patch_dict_.clear();
-        dictionary_.clear();
-
+    DatFile::DatFile() {
         el::Configurations defaultConf;
         defaultConf.setToDefault();
         defaultConf.setGlobally(el::ConfigurationType::Format,
                                 "%datetime %level %fbase (line %line) : %msg (function: %func)");
         defaultConf.setGlobally(el::ConfigurationType::ToFile, "true");
         defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
-        defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
+        defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "true");
         defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
         defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
         defaultConf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1"); // Flush after every one log
@@ -57,1041 +40,37 @@ namespace LOTRO_DAT {
         el::Loggers::reconfigureAllLoggers(defaultConf);
         LOG(INFO) << "==================================================================";
         LOG(INFO) << "Starting new DatFile class instance";
-    }
-
-    DAT_RESULT DatFile::InitDatFile(const std::string &filename, int dat_id) {
-        LOG(DEBUG) << "Started initialisation of DatFile " << filename;
-        if (dat_state_ != CLOSED && filename == filename_) {
-            LOG(DEBUG) << "Trying to reopen the same file: " << filename << ". Doing nothing.";
-            return SUCCESS;
-        }
-
-        if (dat_state_ != CLOSED && filename != filename_) {
-            LOG(DEBUG) << "DatFile wasn't closed yet. Closing in order to reopen.";
-            if (CloseDatFile() != SUCCESS) {
-                LOG(ERROR) << "Unable to perform CloseDatFile()! Aborting initialization!";
-                return FAILED;
-            }
-        }
-
-        dat_id_ = dat_id;
-        dat_state_ = CLOSED;
-        current_locale_ = ORIGINAL;
-        free_buffered_size_ = 0;
-        filename_ = "none";
-
-        DAT_RESULT result;
-        DAT_RESULT return_value = SUCCESS;
-
-        auto res = io.Init(filename);
-        if (res.result == DatOperationResult::ERROR) {
-            LOG(ERROR) << "ERROR! Unable to initialize input-output!";
-            CloseDatFile();
-            return NO_FILE_ERROR;
-        }
-
-        dat_state_ = SUCCESS_DIRECTORIES;
-        LOG(INFO) << "Starting MakeDictionary";
-
-        result = MakeDictionary();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to make dictionary. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        LOG(INFO) << "Starting InitLocales";
-
-        result = InitLocales();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to initialize locales. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        LOG(INFO) << "File " << filename << " opened successfully!";
-        filename_ = filename;
-        dat_state_ = READY;
-
-        LOG(INFO) << "Making last preparations...";
-        return_value = std::max(return_value, result);
-
-        PerformDictionaryCheck();
-
-        if (return_value >= 2) {
-            LOG(WARNING) << "Dat file could be corrupted. Trying to delete corrupted dictionary rows";
-            if (RepairDatFile() != SUCCESS)
-                return CRITICAL_DAT_ERROR;
-        }
-
-        if (CheckIfUpdatedByGame()) {
-            LOG(INFO) << ".dat file was updated by game! Need to reinitialize files and directories!";
-            CloseDatFile();
-            InitDatFile(filename, dat_id);
-        }
-
-        std::cout << "Visited subdirs: " << SubDirectory::visited_subdirectories_.size() << std::endl;
-        std::cout << "Visited files: " << SubDirectory::visited_subfiles_.size() << std::endl;
-        dat_without_patches_ = CheckIfNotPatched();
-        LOG(INFO) << "Preparations made successfully! Init return value = " << return_value;
-        return return_value;
-    }
-
-    DAT_RESULT DatFile::MakeDictionary() {
-        LOG(DEBUG) << "Started making dictionary";
-        if (dat_state_ != SUCCESS_DIRECTORIES) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_DIRECTORIES. Cannot make directories.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        if (io.GetRootDirectory() == nullptr) {
-            LOG(ERROR) << "root_directory is nullptr!!";
-            return INIT_ERROR;
-        }
-
-        io.GetRootDirectory()->MakeDictionary(dictionary_);
-        dat_state_ = SUCCESS_DICTIONARY;
-        LOG(DEBUG) << "Dictionary made successfull";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::InitLocales() {
-        LOG(INFO) << "Initialising locales...";
-        BinaryData dicts_data(4);
-
-        io.ReadData(dicts_data, 4, 300);
-        long long dict_offset = dicts_data.ToNumber<4>(0);
-
-        if (dict_offset == 0 || dict_offset + 8 >= io.GetActualDatSize()) {
-            LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
-            return SUCCESS;
-        }
-
-        io.ReadData(dicts_data, 4, dict_offset);
-        long long dict_size = dicts_data.ToNumber<4>(0);
-
-        io.ReadData(dicts_data, 4, dict_offset + 4);
-        long long dict_version = dicts_data.ToNumber<4>(0);
-
-        io.ReadData(dicts_data, 4, dict_offset + 8);
-        io.file_size = dicts_data.ToNumber<4>(0);
-
-        LOG(INFO) << "Dictionary size is " << dict_size << ". Version is " << dict_version << ". Localed .dat size = "
-                  << io.file_size;
-
-        if (dict_version != 101) {
-            LOG(WARNING) << "DICTIONARY IS OLD!!!";
-            orig_dict_.clear();
-            patch_dict_.clear();
-            io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            dat_state_ = UPDATED;
-            dat_without_patches_ = true;
-            return SUCCESS;
-        }
-
-        dicts_data = BinaryData((unsigned)dict_size);
-        io.ReadData(dicts_data, dict_size, dict_offset + 12);
-
-        if (dicts_data.size() < 15) {
-            LOG(ERROR) << "Incorrect dictionary. Passing without it.";
-            orig_dict_.clear();
-            patch_dict_.clear();
-            io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            dat_state_ = UPDATED;
-            dat_without_patches_ = true;
-            return SUCCESS;
-        }
-
-        BinaryData hi_data = dicts_data.CutData(0, 15) + BinaryData("\0", 1);
-        std::string hi = std::string((char *) (hi_data.data()));
-        LOG(DEBUG) << "hi info is " << hi;
-
-        if (hi != "Hi from Gi1dor!") {
-            LOG(WARNING) << "Didn't receive 'hi' from Gi1dor... Initialising locale dicts as empty";
-            LOG(INFO) << "Could't init locales' file... Continuing without them";
-            return 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;
-        LOG(DEBUG) << "current locale:" << locale;
-
-        if (locale != "PATC" && locale != "ORIG") {
-            LOG(WARNING) << "Incorrect locale... Initialising locale dicts as empty";
-            LOG(INFO) << "Could't recognize locale... Continuing without locales";
-            return SUCCESS;
-        }
-        current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
-
-        // 15 bytes for "Hi from Gi1dor"
-        // 4 bytes for LOCALE
-        // 4 bytes for orig_dict.size()
-        // (32 + 4) * orig_dict.size() bytes for orig_dict data
-        // 4 bytes for patch_dict.size()
-        // (32 + 4) * patch_dict.size() bytes for patch_dict data
-        // 4 bytes for inactive_categories dict
-        // 4 * inactive_categories.size() bytes for inactive_categories data
-
-        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 = std::make_shared<SubFile>(*this, dicts_data.CutData(offset, offset + 32));
-            orig_dict_[file->file_id()] = file;
-            offset += 32;
-            orig_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
-            offset += 4;
-
-            if (orig_dict_[file->file_id()]->category == 0)
-                LOG(DEBUG) << "file category is undefined (0)!";
-        }
-
-        size_t patch_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
-        offset += 4;
-        for (size_t i = 0; i < patch_dict_size; i++) {
-            auto file = std::make_shared<SubFile>(*this, dicts_data.CutData(offset, offset + 32));
-            patch_dict_[file->file_id()] = file;
-            offset += 32;
-            patch_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
-            offset += 4;
-            if (patch_dict_[file->file_id()]->category == 0)
-                LOG(DEBUG) << "file category is undefined (0)!";
-
-        }
-
-        size_t active_patches_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
-        offset += 4;
-        for (size_t i = 0; i < active_patches_dict_size; i++) {
-            inactive_categories.insert(dicts_data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        LOG(INFO) << "There are " << patch_dict_.size() << " files in patch locale dictionary";
-        LOG(INFO) << "There are " << orig_dict_.size() << " files in original locale dictionary";
-        std::string inactive_cat_s;
-        for (auto i : inactive_categories) {
-            inactive_cat_s += std::to_string(i) + " ";
-        }
-        LOG(INFO) << "Unactive patches now: " << inactive_cat_s;
-        LOG(INFO) << "Finished initialising locales";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::PerformDictionaryCheck() {
-        for (const auto& mpair : dictionary_) {
-            auto file = mpair.second;
-            auto file_id = mpair.first;
-            if (CorrectSubfile(file))
-                continue;
-
-            if (current_locale_ == PATCHED && orig_dict_.count(file_id) > 0) {
-                LOG(WARNING) << "Potential incorrect patched version of file " << file_id << ". Switching to original.";
-                dictionary_[file_id] = orig_dict_[file_id];
-            }
-
-            if (!CorrectSubfile(file)) {
-                LOG(ERROR) << "Incorrect file " << file_id << ". It's offset is said as " << file->file_offset()
-                           << ". Erasing it from dictionary.";
-                dictionary_.erase(file_id);
-            }
-        }
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // CLOSE SECTION
-    //------------------------------------------------//
-
-    DatFile::~DatFile() {
-        CloseDatFile();
-    }
-
-    DAT_RESULT DatFile::CloseDatFile() {
-        LOG(INFO) << "Closing DatFile";
-        if (dat_state_ == CLOSED) {
-            LOG(INFO) << "DatFile is already closed. Nothing to do";
-            return SUCCESS;
-        }
-
-        // Committing changes and updating/writing locales and header info
-        io.DeInit();
-        if (!pending_dictionary_.empty() || dat_state_ == UPDATED) {
-            CommitLocales();
-            CommitDirectories();
-            //ModifyFragmentationJournal();
-            //free_dat_size = 128248;
-            //fragmentation_journal_end = 0;
-            //fragmentation_journal_size = 1;
-            //UpdateHeader();
-        }
-
-        current_locale_ = ORIGINAL;
-
-        SubDirectory::visited_subdirectories_.clear();
-
-        free_buffered_size_ = 0;
-
-        filename_ = "none";
-
-        orig_dict_.clear();
-        patch_dict_.clear();
-        pending_patch_.clear();
-        inactive_categories.clear();
-
-        pending_dictionary_.clear();
-        dictionary_.clear();
-
-        dat_state_ = CLOSED;
-
-        dat_id_ = -1;
-
-
-        LOG(INFO) << "File closed successfully.";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::CommitLocales() {
-        LOG(INFO) << "Committing locales...";
-        // 15 bytes for "Hi from Gi1dor"
-        // 4 bytes for LOCALE
-        // 4 bytes for orig_dict.size()
-        // (32 + 4) * orig_dict.size() bytes for orig_dict data
-        // 4 bytes for patch_dict.size()
-        // (32 + 4) * patch_dict.size() bytes for patch_dict data
-        // 4 bytes for inactive_categories list
-        // 4 * inactive_categories.size() bytes for inactive_categories data
-
-        BinaryData binary_data = BinaryData(14 + 15 + 4
-                                            + 4 + (32 + 4) * orig_dict_.size()
-                                            + 4 + (32 + 4) * patch_dict_.size()
-                                            + 4 + 4 * inactive_categories.size());
-
-        size_t current_size = 0;
-        binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
-        current_size += 15;
-
-        binary_data.Append(BinaryData((current_locale_ == ORIGINAL ? "ORIG" : "PATC"), 4), current_size);
-        current_size += 4;
-
-        binary_data.Append(BinaryData::FromNumber<4>(orig_dict_.size()), current_size);
-        current_size += 4;
-
-        for (const auto &file : orig_dict_) {
-            binary_data.Append(file.second->MakeHeaderData(), current_size);
-            current_size += 32;
-            binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
-            current_size += 4;
-        }
-
-        binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
-        current_size += 4;
-
-        for (const auto &file : patch_dict_) {
-            binary_data.Append(file.second->MakeHeaderData(), current_size);
-            current_size += 32;
-            binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
-            current_size += 4;
-        }
-
-        binary_data.Append(BinaryData::FromNumber<4>(inactive_categories.size()), current_size);
-        current_size += 4;
-        for (auto patch_id : inactive_categories) {
-            binary_data.Append(BinaryData::FromNumber<4>(patch_id), current_size);
-            current_size += 4;
-        }
-
-
-        BinaryData dicts_data(4);
-        io.ReadData(dicts_data, 4, 300);
-        long long dict_offset = dicts_data.ToNumber<4>(0);
-        io.ReadData(dicts_data, 4, dict_offset);
-        long long dict_size = dicts_data.ToNumber<4>(0);
-
-        if (binary_data.size() > dict_size || dict_offset == 0) {
-            io.WriteData(BinaryData::FromNumber<4>(io.file_size), 4, 300);
-
-            io.WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 4,
-                         io.file_size);
-            io.WriteData(BinaryData::FromNumber<4>(101), 4, io.file_size + 4);
-            io.WriteData(BinaryData::FromNumber<4>(io.file_size + binary_data.size() + 12 + 20 * 1024 * 1024), 4,
-                         io.file_size + 8); // Writing current file size;
-
-            io.WriteData(binary_data, binary_data.size(), io.file_size + 12);
-            io.file_size += binary_data.size() + 12;
-
-            // Adding space for 25 megabytes locales file in total.
-            BinaryData nulls(unsigned(20 * 1024 * 1024));
-            io.WriteData(nulls, nulls.size(), io.file_size);
-            io.file_size += nulls.size();
-
-        } else {
-            io.WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size(), 20u * 1024u * 1024u)), 4, dict_offset);
-            io.WriteData(BinaryData::FromNumber<4>(101), 4, dict_offset + 4);
-            io.WriteData(BinaryData::FromNumber<4>(io.file_size), 4, dict_offset + 8); // Writing current file size;
-            io.WriteData(binary_data, binary_data.size(), dict_offset + 12);
-        }
-        LOG(INFO) << "Locales commited successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::CommitDirectories() {
-        for (auto file_id : pending_dictionary_) {
-            if (dictionary_[file_id] == nullptr || !CorrectSubfile(dictionary_[file_id]))
-                continue;
-            io.WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
-        }
-        pending_dictionary_.clear();
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ModifyFragmentationJournal() {
-        if (io.fragmentation_journal_size == 0)
-            return SUCCESS;
-        LOG(DEBUG) << "Modifying fragmentation journal";
-        BinaryData data(4);
-        io.ReadData(data, 4, io.fragmentation_journal_offset + 8 * io.fragmentation_journal_size);
-        LOG(INFO) << "FREE_SIZE BLOCK = " << data.ToNumber<4>(0);
-
-        long long free_size = data.ToNumber<4>(0);
-        long long free_offset = io.file_size;
-
-        BinaryData nulldata = BinaryData(unsigned(free_size));
-        io.WriteData(nulldata, nulldata.size(), io.file_size);
-        io.file_size += nulldata.size();
-
-        io.WriteData(BinaryData::FromNumber<4>(free_size), 4,
-                     io.fragmentation_journal_offset + 8 * io.fragmentation_journal_size);
-        io.WriteData(BinaryData::FromNumber<4>(free_offset), 4,
-                     io.fragmentation_journal_offset + 8 * io.fragmentation_journal_size + 4);
-
-        //nulldata = BinaryData(8);
-        //io.WriteData(nulldata, nulldata.size(), fragmentation_journal_offset + 16);
-        LOG(DEBUG) << "Finished modifying fragmentation journal";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::RepairDatFile() {
-        for (const auto& file : dictionary_) {
-            auto subfile = file.second;
-            auto file_id = file.first;
-
-            if (CorrectSubfile(subfile))
-                continue;
-
-            if (orig_dict_.count(file_id) == 0 || subfile->file_offset() == orig_dict_[file_id]->file_offset())
-                return CRITICAL_DAT_ERROR;
-
-            *dictionary_[file_id] = *orig_dict_[file_id];
-            patch_dict_.erase(file_id);
-            orig_dict_.erase(file_id);
-        }
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // DAT INFO SECTION
-    //------------------------------------------------//
-
-    DAT_STATE DatFile::DatFileState() const {
-        return dat_state_;
-    }
-
-    long long DatFile::files_number() const {
-        return dictionary_.size();
-    }
-
-    //------------------------------------------------//
-    // EXTRACT SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::ExtractFile(long long file_id, const std::string &path) {
-        LOG(DEBUG) << "Extracting file " << file_id << " to path " << path;
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
-
-        if (file_data.size() == 0) {
-            LOG(ERROR) << "File data is empty. Aborting extraction.";
-            return NO_FILE_ERROR;
-        }
-
-        SubfileData export_data = dictionary_[file_id]->PrepareForExport(file_data);
-
-        if (export_data.Empty()) {
-            LOG(ERROR) << "Export data is empty. Aborting extraction.";
-            return NO_FILE_ERROR;
-        }
-
-        if (export_data.binary_data.WriteToFile(path + export_data.options["ext"].as<std::string>()) != SUCCESS) {
-            LOG(ERROR) << "Cannot write to file.";
-            return WRITE_TO_FILE_ERROR;
-        }
-        LOG(DEBUG) << "File " << file_id << " extracted successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ExtractFile(long long file_id, Database *db) {
-        LOG(DEBUG) << "Extracting file " << file_id << " to database.";
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
-
-        if (file_data.Empty()) {
-            LOG(WARNING) << "File with id " << dictionary_[file_id]->file_id() << " is empty. Passing it.";
-            return SUCCESS;
-        }
-
-        SubfileData export_data;
-        export_data = dictionary_[file_id]->PrepareForExport(file_data);
-        export_data.options["did"] = dat_id_;
-
-        if (export_data == SubfileData()) {
-            LOG(WARNING) << "File with id " << dictionary_[file_id]->file_id() << " is empty or incorrect.";
-            return SUCCESS;
-        }
 
-        try {
-            db->PushFile(export_data);
-        } catch (std::exception &e) {
-            LOG(ERROR) << "Caught " << e.what() << " exception.";
-            return FAILED;
-        }
-        LOG(DEBUG) << "File " << file_id << " extracted successfully";
-        return SUCCESS;
+        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);
     }
 
-    int DatFile::ExtractAllFilesByType(FILE_TYPE type, std::string path) {
-        LOG(INFO) << "Extracting all files to path " << path;
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        int success = 0;
-        for (const auto& i : dictionary_) {
-            FILE_TYPE file_type = i.second->FileType();
-            if (file_type == type) {
-                success += (ExtractFile(i.second->file_id(), (path + std::to_string(i.second->file_id()))) == SUCCESS
-                            ? 1 : 0);
-            }
-        }
-        LOG(INFO) << "Successfully extracted " << success << " files";
-        return success;
-    }
-
-    int DatFile::ExtractAllFilesByType(FILE_TYPE type, Database *db) {
-        LOG(INFO) << "Extracting all files to database...";
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        int success = 0;
-        for (const auto& i : dictionary_) {
-            FILE_TYPE file_type = i.second->FileType();
-            if (file_type == type) {
-                success += (ExtractFile(i.second->file_id(), db) == SUCCESS ? 1 : 0);
-            }
-        }
-        LOG(INFO) << "Extracted " << success << " files";
-        return success;
-    }
-
-    //------------------------------------------------//
-    // PATCH SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::PatchFile(const SubfileData &data) {
-        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>() << ".";
-
-        if (!dat_without_patches_) {
-            io.file_size = io.GetActualDatSize();
-        }
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        auto file_id = data.options["fid"].as<long long>();
-
-        if (dictionary_.count(file_id) == 0) {
-            LOG(ERROR) << "Cannot patch file - there is no file in dictionary with file_id = " << file_id;
-            return NO_FILE_ERROR;
-        }
-        std::shared_ptr<SubFile> file = dictionary_[file_id];
-
-//        if (!CorrectSubfile(file)) {
-//            if (current_locale_ == PATCHED && patch_dict_.count(file_id) > 0) {
-//                LOG(WARNING) << "Patched subfile header with id = " << file->file_id() << " differs from original version...";
-//            } else {
-//                LOG(ERROR) << "Incorrect subfile with id " << file->file_id()
-//                           << " (headers do not match). Cannot patch it";
-//                return FAILED;
-//            }
-//        }
-
-        // If file has inactive category, then we should set it to patched state in order to commit patch and
-        // then in ApplyFilePatch(), if new category is still inactive, return dictionary to its original state;
-
-        if (inactive_categories.count(file->category) != 0 && patch_dict_.count(file_id) != 0 && file_id != 2013266257) {
-            *dictionary_[file_id] = *patch_dict_[file_id];
-        }
-
-        if (data.options["cat"].IsDefined()) {
-            file->category = data.options["cat"].as<long long>();
-        } else {
-            file->category = 1;
-        }
-
-        BinaryData old_data = GetFileData(orig_dict_.count(file->file_id()) == 0 ? file : orig_dict_[file->file_id_]);
-        if (old_data.Empty()) {
-            LOG(ERROR) << "GetFileData returned empty data. Aborting.";
-            return DAT_PATCH_FILE_ERROR;
-        }
-
-        BinaryData patch_data = file->MakeForImport(old_data, data);
-        DAT_RESULT result = ApplyFilePatch(file, patch_data);
-        if (result != SUCCESS)
-            return result;
-
-        LOG(DEBUG) << "Patched successfully file " << data.options["fid"].as<long long>() << ".";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::PatchAllDatabase(Database *db) {
-        LOG(INFO) << "Patching all database";
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        SubfileData data;
-        data = db->GetNextFile();
-
-        while (!data.Empty()) {
-            DAT_RESULT result = PatchFile(data);
-            if (result != SUCCESS)
-                LOG(ERROR) << "Cannot patch file " << data.options["fid"].as<long long>() << " continuing";
-            data = db->GetNextFile();
-        }
-        LOG(INFO) << "Successfully patched whole database";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::WriteUnorderedDictionary(std::string path) const {
-        LOG(INFO) << "Writing unordered dictionary to " << path << "dict.txt";
-        FILE *f = nullptr;
-        fopen_s(&f, (path + "dict.txt").c_str(), "w");
-
-        if (f == nullptr) {
-            LOG(ERROR) << "Cannot open file " << path + "dict.txt";
-            return WRITE_TO_FILE_ERROR;
-        }
-
-        fprintf(f, "unk1 file_id offset size1 timestamp version size2 unknown2 type\n");
-        for (const auto& i : dictionary_) {
-            fprintf(f, "%lld %lld %lld %lld %lld %lld %lld %lld %s\n", i.second->unknown1(), i.second->file_id(),
-                    i.second->file_offset(), i.second->file_size(), i.second->timestamp(), i.second->version(),
-                    i.second->block_size(), i.second->unknown2(), i.second->Extension().c_str());
-        }
-        fclose(f);
-        LOG(INFO) << "Unordered dictionary was written successfully to " << path << "dict.txt";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data) {
-        LOG(DEBUG) << "Applying " << file->file_id() << " patch.";
-
-//        if (patch_dict_.size() == 0 && pending_dictionary_.size() == 0) {
-//            BinaryData nulls(50 * 1024 * 1024);
-//            io.WriteData(nulls, nulls.size(), file_size);
-//            file_size += 50 * 1024 * 1024;
-//        }
-
-        if (data.Empty()) {
-            LOG(ERROR) << "Error caused during making file for import. Cannot patch file " << file->file_id();
-            return FAILED;
-        }
-
-        auto file_id = file->file_id();
-
-        if (current_locale() != PATCHED && file_id != 2013266257) {
-            LOG(INFO) << "Changing locale to PATCHED(RU) in order to patch file";
-            SetLocale(PATCHED);
-        }
-
-        dat_state_ = UPDATED;
-
-        if (orig_dict_.count(file_id) == 0 && file_id != 2013266257) {
-            orig_dict_[file_id] = std::make_shared<SubFile>(*this, file->MakeHeaderData());
-        }
-
-
-        if ((patch_dict_.count(file_id) == 0 && file_id != 2013266257) || data.size() > file->block_size()
-            || file->file_size() + 8 > file->block_size()) {
-
-            file->file_offset_ = io.file_size;
-            file->block_size_ = std::max((long long)data.size(), file->block_size_);
-
-            free_buffered_size_ = std::max(0ll, free_buffered_size_ - file->block_size_ - 8);
-            AddBufferedSize();
-
-            io.file_size += file->block_size_ + 8;
-        }
-
-        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(ERROR) << "Created data's file_id doesn't match to original! Patch wasn't written to .dat file";
-            return INCORRECT_PATCH_FILE;
-        }
-
-        //data.ProtectData();
-        //BinaryData data1(data.size());
-        io.WriteData(data, data.size(), file->file_offset());
-        //data.DeprotectData();
-
-        patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
-        if (file_id != 2013266257) {
-            patch_dict_[file_id] = std::make_shared<SubFile>(*this, file->MakeHeaderData()); // Создали новое значение
-        }
-
-        // If category is forbidden, then return file header data to original state
-        if (inactive_categories.count(file->category) != 0) {
-            file->file_offset_ = orig_dict_[file_id]->file_offset_;
-            file->file_size_ = orig_dict_[file_id]->file_size_;
-            file->block_size_ = orig_dict_[file_id]->block_size_;
-            file->timestamp_ = orig_dict_[file_id]->timestamp_;
-            file->version_ = orig_dict_[file_id]->version_;
-        }
-
-        if (orig_dict_.count(file_id) != 0 && file_id != 2013266257)
-            orig_dict_[file_id]->category = file->category;
-        if (patch_dict_.count(file_id) != 0 && file_id != 2013266257)
-            patch_dict_[file_id]->category = file->category;
-
-
-        // Applying file info in directory
-        pending_dictionary_.insert(file_id);
-
-        LOG(DEBUG) << "Successfully applied file " << file->file_id() << " patch.";
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // INPUT-OUTPUT SECTION
-    //------------------------------------------------//
-
-    BinaryData DatFile::GetFileData(const std::shared_ptr<SubFile>& file, long long int offset) {
-        LOG(DEBUG) << "Getting file " << file->file_id() << " data";
-
-        BinaryData mfile_id(20);
-        io.ReadData(mfile_id, 20, file->file_offset() + 8);
-        if (mfile_id.Empty()) {
-            LOG(ERROR) << "Error while reading file " << file->file_id() << " header (offset = "
-                       << file->file_offset() << "); Aborting.";
-            return BinaryData(0);
-        }
-
-        if (!mfile_id.CheckCompression() && file->file_id() != mfile_id.ToNumber<4>(0)) {
-            LOG(ERROR) << "Bad DatFile::GetFileData() - file_id in SubFile ("
-                       << file->file_id()
-                       << ") doesn't match to file_id (" << mfile_id.ToNumber<4>(0) << ")in DatFile.";
-            return BinaryData(0);
-        }
-
-        BinaryData data((unsigned)(file->file_size() + (8 - offset)));
-        if (file->block_size() >= file->file_size() + 8) {
-            io.ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
-            return data;
-        }
-
-        BinaryData fragments_count(4);
-        io.ReadData(fragments_count, 4, file->file_offset());
-
-        long long fragments_number = fragments_count.ToNumber<4>(0);
-
-        long long current_block_size = file->block_size() - offset - 8 * fragments_number;
-
-        io.ReadData(data, current_block_size, file->file_offset() + offset);
-
-        BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-        io.ReadData(FragmentsDictionary, 8 * unsigned(fragments_number),
-                 file->file_offset() + file->block_size() - 8 * fragments_number);
-
-
-        for (long long i = 0; i < fragments_number; i++) {
-            long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-            long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-            io.ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset,
-                        current_block_size);
-            current_block_size += fragment_size;
-        }
-        LOG(DEBUG) << "Successfully got file " << file->file_id() << " data";
-        return data;
+    LOTRO_DAT::DatLocaleManager &DatFile::getLocaleManager() {
+        return *localeManager_;
     }
 
-
-    //------------------------------------------------//
-    // LOCALE SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::SetLocale(LOCALE locale) {
-        LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot set locale.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        if (current_locale_ == locale) {
-            return SUCCESS;
-        }
-
-        dat_state_ = UPDATED;
-        auto dict = GetLocaleDictReference(locale);
-        for (const auto& file : dict) {
-            if (file.second == nullptr)
-                continue;
-
-            if (dictionary_.count(file.first) == 0) {
-                LOG(WARNING) << "In locale dictionary there is file with file_id = " << file.first
-                             << "which is not in .dat file! Passing it and removing from locale dictionary";
-                dict.erase(file.first);
-                continue;
-            }
-            if (dictionary_[file.first]->MakeHeaderData().CutData(8, 16) ==
-                file.second->MakeHeaderData().CutData(8, 16) ||
-                inactive_categories.count(orig_dict_[file.first]->category) != 0)
-                continue;
-
-            long long file_id = file.first;
-            std::shared_ptr<SubFile> new_file = file.second;
-
-            *dictionary_[file_id] = *new_file;
-
-            pending_dictionary_.insert(file_id);
-            dat_state_ = UPDATED;
-        }
-
-        current_locale_ = locale;
-        LOG(INFO) << "Locale set successfull";
-        return SUCCESS;
+    DatExporter &DatFile::getExporter() {
+        return *exporter_;
     }
 
-    LOCALE DatFile::current_locale() {
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "dat_file is in incorrect state!";
-            return ORIGINAL;
-        }
-        if (current_locale_ != PATCHED && current_locale_ != ORIGINAL) {
-            LOG(ERROR) << "locale has incorrect value. Setting it to original";
-            current_locale_ = ORIGINAL;
-        }
-        return current_locale_;
+    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
+        return *patcher_;
     }
 
-    std::map<long long, std::shared_ptr<SubFile> > &DatFile::GetLocaleDictReference(LOCALE locale) {
-        switch (locale) {
-            case PATCHED:
-                return patch_dict_;
-            case ORIGINAL:
-                return orig_dict_;
-            default:
-                LOG(ERROR) << "Unknown locale! Returning original";
-                return orig_dict_;
-        }
+    DatBackupManager &DatFile::getBackupManager() {
+        return *backupManager_;
     }
 
-    //------------------------------------------------//
-    // CHECKERS SECTION
-    //------------------------------------------------//
-
-    bool DatFile::CorrectSubfile(std::shared_ptr<SubFile> file) {
-        BinaryData mfile_id(20);
-        io.ReadData(mfile_id, 20, file->file_offset() + 8);
-        if (mfile_id.Empty())
-            return false;
-
-        return (mfile_id.CheckCompression() || file->file_id() == mfile_id.ToNumber<4>(0)) && file->file_size() < 50ll * 1024ll * 1024ll;
+    DatIO &DatFile::getIO() {
+        return *io_;
     }
 
-    bool DatFile::CheckIfUpdatedByGame() {
-//        LOG(INFO) << "Checking if DatFile was updated by LotRO";
-//        if (!pending_patch_.empty())
-//            return true;
-
-//        bool updated = false;
-
-//        for (const auto& i : dictionary_) {
-//            long long file_id = i.first;
-//            std::shared_ptr<SubFile> subfile = i.second;
-//            if (patch_dict_.count(file_id) == 0)
-//                continue;
-//
-//            if (*subfile != *patch_dict_[file_id] && *subfile != *orig_dict_[file_id]) {
-//                //orig_dict_.clear();
-//                //patch_dict_.clear();
-//                LOG(INFO) << "DAT FILE WAS UPDATED!!!! CLEARING PATCH DATA";
-//                pending_patch_.insert(file_id);
-//                io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-//                return true;
-//            }
-//        }
-//        return updated;
-        return false;
-    }
-
-    bool DatFile::CheckIfNotPatched() {
-        LOG(INFO) << "DatFile " << (patch_dict_.empty() ? "HASN'T " : "HAS already")
-                  << " been patched by LEGACY launcher!";
-        return patch_dict_.empty();
-    }
-
-    bool DatFile::CheckIfPatchedByOldLauncher() {
-        LOG(INFO) << "DatFile " << (dictionary_.count(620750000) == 0 ? "HASN'T " : "HAS already")
-                  << " been patched by OLD LAUNCHER!";
-        return dictionary_.count(620750000) > 0;
-    }
-
-    //------------------------------------------------//
-    // CATEGORY SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::EnableCategory(int category) {
-        LOG(INFO) << "Enabling category " << category;
-        if (inactive_categories.count(category) == 0)
-            return SUCCESS;
-
-        inactive_categories.erase(category);
-        dat_state_ = UPDATED;
-
-        for (auto &file : dictionary_) {
-            auto file_id = file.first;
-            if (patch_dict_.count(file_id) > 0 && patch_dict_[file_id]->category == category) {
-                *file.second = *patch_dict_[file_id];
-                pending_dictionary_.insert(file_id);
-            }
-        }
-        LOG(INFO) << "Category " << category << " enabled successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::DisableCategory(int category) {
-        LOG(INFO) << "Disabling category " << category;
-        if (inactive_categories.count(category) != 0)
-            return SUCCESS;
-        inactive_categories.insert(category);
-        dat_state_ = UPDATED;
-
-        for (auto &file : dictionary_) {
-            auto file_id = file.first;
-            if (orig_dict_.count(file_id) && orig_dict_[file_id]->category == category) {
-                *file.second = *orig_dict_[file_id];
-                pending_dictionary_.insert(file_id);
-            }
-        }
-        LOG(INFO) << "Category " << category << " disabled successfully";
-        return SUCCESS;
-    }
-
-    const std::set<long long> &DatFile::GetInactiveCategoriesList() {
-        return inactive_categories;
-    }
-
-    const std::string &DatFile::filename() const {
-        return filename_;
-    }
-
-    void DatFile::AddBufferedSize() {
-        if (free_buffered_size_ >= MIN_BUFFERED_SIZE)
-            return;
-        BinaryData nulls(MAX_BUFFERED_SIZE);
-        io.WriteData(nulls, MAX_BUFFERED_SIZE, io.file_size);
-        free_buffered_size_ = MAX_BUFFERED_SIZE;
-    }
-
-    //------------------------------------------------//
-    // BACKUP SECTION
-    //------------------------------------------------//
-
-    bool DatFile::CheckIfBackupExists(const std::string &backup_datname) {
-        std::ifstream dst("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-        return !dst.fail();
-    }
-
-    DAT_RESULT DatFile::RemoveBackup(const std::string &backup_datname) {
-        if (!CheckIfBackupExists(backup_datname))
-            return SUCCESS;
-        if (remove(("DAT_LIBRARY_BACKUP/" + backup_datname).c_str()) == 0)
-            return SUCCESS;
-        return REMOVE_FILE_ERROR;
-    }
-
-    DAT_RESULT DatFile::CreateBackup(const std::string &backup_datname) {
-        auto filename = filename_;
-        auto dat_id = dat_id_;
-        LOG(INFO) << "Restoring .dat file " << filename << " from backup " << backup_datname;
-        LOG(INFO) << "    Closing DatFile...";
-        CloseDatFile();
-        LOG(INFO) << "    Copying " << filename << " to " << backup_datname;
-        mkdir("DAT_LIBRARY_BACKUP");
-        std::ifstream  src(filename, std::ios::binary);
-        std::ofstream  dst("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-
-        std::istreambuf_iterator<char> begin_source(src);
-        std::istreambuf_iterator<char> end_source;
-        std::ostreambuf_iterator<char> begin_dest(dst);
-        std::copy(begin_source, end_source, begin_dest);
-
-        src.close();
-        dst.close();
-
-        LOG(INFO) << "    Done copying. Initializing restored" << filename << " DatFile...";
-        InitDatFile(filename, dat_id);
-        LOG(INFO) << "Restoring .dat file success!";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::RestoreFromBackup(const std::string &backup_datname) {
-        auto filename = filename_;
-        auto dat_id = dat_id_;
-        LOG(INFO) << "Restoring .dat file " << filename << " from backup " << backup_datname;
-        LOG(INFO) << "    Closing DatFile...";
-        CloseDatFile();
-        LOG(INFO) << "    Copying " << filename << " to " << backup_datname;
-        mkdir("DAT_LIBRARY_BACKUP");
-        std::ifstream  src("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-        std::ofstream  dst(filename, std::ios::binary);
-        if (src.fail()) {
-            LOG(ERROR) << "CANNOT RESTORE FILE FROM BACKUP - no backup specified with name " << backup_datname;
-            return NO_BACKUP_ERROR;
-        }
-
-        std::istreambuf_iterator<char> begin_source(src);
-        std::istreambuf_iterator<char> end_source;
-        std::ostreambuf_iterator<char> begin_dest(dst);
-        std::copy(begin_source, end_source, begin_dest);
-
-        src.close();
-        dst.close();
-
-        LOG(INFO) << "    Done copying. Initializing restored" << filename << " DatFile...";
-        InitDatFile(filename, dat_id);
-        LOG(INFO) << "Restoring .dat file success!";
-        return SUCCESS;
+    DatFileSystem &DatFile::getFileSystem() {
+        return *fileSystem_;
     }
 }
 }

+ 30 - 0
src/DatSubsystems/DatBackupManager.cpp

@@ -0,0 +1,30 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#include "DatSubsystems/DatBackupManager.h"
+#include "EasyLogging++/easylogging++.h"
+
+LOTRO_DAT::DatBackupManager::DatBackupManager(LOTRO_DAT::DatFile *datFilePtr) {
+
+}
+
+void LOTRO_DAT::DatBackupManager::Init() {
+
+}
+
+bool LOTRO_DAT::DatBackupManager::CheckIfBackupExists(const std::string &backup_datname) {
+    return false;
+}
+
+LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::CreateBackup(const std::string &backup_datname) {
+}
+
+LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::RestoreFromBackup(const std::string &backup_datname) {
+}
+
+LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::RemoveBackup(const std::string &backup_datname) {
+}
+
+void LOTRO_DAT::DatBackupManager::DeInit() {
+}

+ 1 - 1
src/DatFileExporter.cpp → src/DatSubsystems/DatExporter.cpp

@@ -2,4 +2,4 @@
 // Created by kikab on 04.06.2018.
 //
 
-#include "DatFileExporter.h"
+#include "DatSubsystems/DatExporter.h"

+ 91 - 0
src/DatSubsystems/DatFileSystem.cpp

@@ -0,0 +1,91 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#include <DatSubsystems/DatFileSystem.h>
+#include <EasyLogging++/easylogging++.h>
+#include <BinaryData.h>
+#include <DatFile.h>
+#include <SubFile.h>
+
+namespace LOTRO_DAT{
+    DatFileSystem::DatFileSystem(DatFile *datFilePtr) : dat(datFilePtr) {
+        LOG(INFO) << "Initialization of empty DatFileSystem";
+    }
+
+    DatOperationResult<BinaryData> DatFileSystem::GetFileData(long long file_id, long long int offset) {
+        if (!dat)
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        if (dictionary_.count(file_id))
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DatFileSystem error: no file found with id = " + std::to_string(file_id));
+
+        auto file = dictionary_[file_id];
+        LOG(DEBUG) << "Getting file " << file->file_id() << " data";
+
+        BinaryData mfile_id(20);
+        auto operation = dat->getIO().ReadData(mfile_id, 20, file->file_offset() + 8);
+        if (operation.result == ERROR) {
+            LOG(ERROR) << "Error while reading file " << file->file_id() << " header (offset = "
+                       << file->file_offset() << "); Message: " << operation.msg << "Aborting.";
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR, std::string("DatFileSystem error: Read ") + std::to_string(file_id) + " error." + operation.msg);
+        }
+
+        if (!mfile_id.CheckCompression() && file->file_id() != mfile_id.ToNumber<4>(0)) {
+            LOG(ERROR) << "Bad DatFile::GetFileData() - file_id in SubFile ("
+                       << file->file_id()
+                       << ") doesn't match to file_id (" << mfile_id.ToNumber<4>(0) << ")in DatFile.";
+            return DatOperationResult<BinaryData>(BinaryData(), ERROR, std::string("DatFileSystem error: Read ") + std::to_string(file_id) + " error: SubFile value differs from value in dict");
+        }
+
+        BinaryData data((unsigned)(file->file_size() + (8 - offset)));
+        if (file->block_size() >= file->file_size() + 8) {
+            dat->getIO().ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
+            return DatOperationResult<BinaryData>(data, SUCCESS);
+        }
+
+        BinaryData fragments_count(4);
+        dat->getIO().ReadData(fragments_count, 4, file->file_offset());
+
+        long long fragments_number = fragments_count.ToNumber<4>(0);
+
+        long long current_block_size = file->block_size() - offset - 8 * fragments_number;
+
+        dat->getIO().ReadData(data, current_block_size, file->file_offset() + offset);
+
+        BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+        dat->getIO().ReadData(FragmentsDictionary, 8 * unsigned(fragments_number),
+                 file->file_offset() + file->block_size() - 8 * fragments_number);
+
+
+        for (long long i = 0; i < fragments_number; i++) {
+            long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
+            long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
+            dat->getIO().ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset,
+                     current_block_size);
+            current_block_size += fragment_size;
+        }
+        LOG(DEBUG) << "Successfully got file " << file->file_id() << " data";
+        return DatOperationResult<BinaryData>(data, SUCCESS);
+    }
+
+    DatOperationResult<SubFile> DatFileSystem::GetFile(long long file_id) {
+
+    }
+
+    DatOperationResult<> DatFileSystem::UpdateFile(const SubFile &file) {
+    }
+
+    DatOperationResult<> DatFileSystem::MakeDirectories() {
+    }
+
+    DatOperationResult<> DatFileSystem::MakeDictionary() {
+    }
+
+    DatOperationResult<> DatFileSystem::CommitDirectories() {
+    }
+
+    DatOperationResult<> DatFileSystem::Init() {}
+
+    DatOperationResult<> DatFileSystem::DeInit() {}
+}

+ 43 - 81
src/DatFileIO.cpp → src/DatSubsystems/DatIO.cpp

@@ -4,7 +4,7 @@
 
 #include "BinaryData.h"
 #include "DatFile.h"
-#include "DatFileIO.h"
+#include "DatSubsystems/DatIO.h"
 #include "EasyLogging++/easylogging++.h"
 #include "SubDirectory.h"
 #include "SubFile.h"
@@ -13,7 +13,7 @@
 #include <iterator>
 #include <locale>
 #include <DatOperationResult.h>
-#include <DatFileIO.h>
+#include <DatSubsystems/DatIO.h>
 
 
 #ifdef WIN32
@@ -25,8 +25,8 @@ extern "C++"
 {
 namespace LOTRO_DAT {
 
-    DatFileIO::DatFileIO(DatFile &dat_ref) : dat_file_ref(dat_ref), file_handler_(nullptr), filename_(),
-                                             root_directory_(nullptr), actual_dat_size_(0) {
+    DatIO::DatIO(DatFile *datFile) : dat(datFile), file_handler_(nullptr), filename_(),
+                                             actual_dat_size_(0) {
     }
 
 
@@ -34,57 +34,49 @@ namespace LOTRO_DAT {
     // INIT SECTION
     //------------------------------------------------//
 
-    DatOperationResult DatFileIO::Init(const std::string &filename) {
+    DatOperationResult<> DatIO::Init(const std::string &filename) {
         LOG(INFO) << "Initializing IO: " << filename;
 
         filename_ = filename;
 
         auto result = OpenDatFile();
-        if (result.result == DatOperationResult::ERROR) {
+        if (result.result == ERROR) {
             LOG(ERROR) << "Error in OpenDatFile: " << result.msg;
             DeInit();
             return result;
         }
 
         result = ReadSuperBlock();
-        if (result.result == DatOperationResult::ERROR) {
+        if (result.result == ERROR) {
             LOG(ERROR) << "Error in ReadSuperBlock: " << result.msg;
             DeInit();
             return result;
         }
 
-        result = MakeDirectories();
-        if (result.result == DatOperationResult::ERROR) {
-            LOG(ERROR) << "Error in MakeDirectories: " << result.msg;
-            DeInit();
-            return result;
-        }
-
         LOG(INFO) << "Successfull initializing IO: " << filename;
-        return DatOperationResult(DatOperationResult::SUCCESS, "DatFileIO initialized successfully");
+        return DatOperationResult<>(SUCCESS, "DatIO initialized successfully");
     }
 
-    DatOperationResult DatFileIO::OpenDatFile() {
-        LOG(DEBUG) << "DatFileIO: Started opening DatFile";
+    DatOperationResult<> DatIO::OpenDatFile() {
+        LOG(DEBUG) << "DatIO: Started opening DatFile";
 
         file_handler_ = fopen(filename_.c_str(), "r+b");
 
         if (file_handler_ == nullptr) {
-            LOG(ERROR) << "DatFileIO: Unable to open file " << filename_ << ". Presumably - no file found...";
-            return DatOperationResult(DatOperationResult::ERROR,
-                                      std::string("Unable to locate and open file " + filename_));
+            LOG(ERROR) << "DatIO: Unable to open file " << filename_ << ". Presumably - no file found...";
+            return DatOperationResult<>(ERROR, std::string("Unable to locate and open file " + filename_));
         }
 
         fseek(file_handler_, 0, SEEK_END);
         actual_dat_size_ = ftell(file_handler_);
         fseek(file_handler_, 0, SEEK_SET);
 
-        LOG(INFO) << "DatFileIO: file opened";
-        return DatOperationResult(DatOperationResult::SUCCESS, std::string("Successfully opened file " + filename_));
+        LOG(INFO) << "DatIO: file opened";
+        return DatOperationResult<>(SUCCESS, std::string("Successfully opened file " + filename_));
     }
 
-    DatOperationResult DatFileIO::ReadSuperBlock() {
-        LOG(INFO) << "DatFileIO: Started reading superblock";
+    DatOperationResult<> DatIO::ReadSuperBlock() {
+        LOG(INFO) << "DatIO: Started reading superblock";
 
         BinaryData data(1024);
         ReadData(data, 1024);
@@ -102,13 +94,11 @@ namespace LOTRO_DAT {
 
         if (constant1 != 0x4C5000) {
             LOG(ERROR) << "Variable at position 0x100 is not equal to .dat file constant!";
-            return DatOperationResult(DatOperationResult::ERROR,
-                                      std::string("Variable at position 0x100 is not equal to .dat file constant!"));
+            return DatOperationResult<>(ERROR, std::string("Variable at position 0x100 is not equal to .dat file constant!"));
         }
         if (constant2 != 0x5442) {
             LOG(ERROR) << "Variable at position 0x140 is not equal to .dat file constant!";
-            return DatOperationResult(DatOperationResult::ERROR,
-                                      std::string("Variable at position 0x140 is not equal to .dat file constant!"));
+            return DatOperationResult<>(ERROR, std::string("Variable at position 0x140 is not equal to .dat file constant!"));
         }
 
         if (file_size != actual_dat_size_) {
@@ -116,34 +106,8 @@ namespace LOTRO_DAT {
             //return CORRUPTED_FILE_WARNING;
         }
 
-        LOG(INFO) << "DatFileIO: Superblock read successfully";
-        return DatOperationResult(DatOperationResult::SUCCESS, std::string("Superblock read successfully."));
-    }
-
-    DatOperationResult DatFileIO::MakeDirectories() {
-        LOG(INFO) << "DatFileIO: Started making directories";
-
-        root_directory_ = std::make_shared<SubDirectory>((unsigned) root_directory_offset, dat_file_ref);
-        SubDirectory::subdir_init_queue_.insert(root_directory_);
-
-        while (!SubDirectory::subdir_init_queue_.empty()) {
-            std::shared_ptr<SubDirectory> dir = *SubDirectory::subdir_init_queue_.begin();
-            SubDirectory::subdir_init_queue_.erase(SubDirectory::subdir_init_queue_.begin());
-            if (dir->MakeSubDirectories())
-                SubDirectory::subfile_init_queue_.insert(dir);
-            else
-                dir->clear();
-        }
-
-        while (!SubDirectory::subfile_init_queue_.empty()) {
-            std::shared_ptr<SubDirectory> dir = *SubDirectory::subfile_init_queue_.begin();
-            SubDirectory::subfile_init_queue_.erase(SubDirectory::subfile_init_queue_.begin());
-            if (!dir->MakeSubFiles())
-                dir->clear();
-        }
-
-        LOG(INFO) << "DatFileIO: Directories made successfully";
-        return DatOperationResult(DatOperationResult::SUCCESS, std::string("Directories initialise successful."));
+        LOG(INFO) << "DatIO: Superblock read successfully";
+        return DatOperationResult<>(SUCCESS, std::string("Superblock read successfully."));
     }
 
 
@@ -151,40 +115,39 @@ namespace LOTRO_DAT {
     // PUBLIC READ/WRITE SECTION
     //------------------------------------------------//
 
-    DatOperationResult
-    DatFileIO::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) const {
+    DatOperationResult<>
+    DatIO::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) const {
         if (file_handler_ == nullptr) {
             LOG(ERROR) << "IOError: file handler is null pointer on reading data.";
             data = BinaryData(0);
-            return DatOperationResult(DatOperationResult::ERROR,
-                                      "IOError: file handler is null pointer on reading data.");
+            return DatOperationResult<>(ERROR, "IOError: file handler is null pointer on reading data.");
         }
 
         if (data_offset + size > data.size()) {
             LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset
                        << " position.";
             data = BinaryData(0);
-            return DatOperationResult(DatOperationResult::ERROR, "IOError: Parameters: offset, size are out of range.");
+            return DatOperationResult<>(ERROR, "IOError: Parameters: offset, size are out of range.");
         }
 
         if (offset + size > actual_dat_size_) {
             LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset
                        << " position.";
             data = BinaryData(0);
-            return DatOperationResult(DatOperationResult::ERROR, "IOError: Reading from end of file.");
+            return DatOperationResult<>(ERROR, "IOError: Reading from end of file.");
         }
 
         if (offset != ftell(file_handler_))
             fseek(file_handler_, offset, SEEK_SET);
         fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
-        return DatOperationResult(DatOperationResult::SUCCESS, "Read data successful.");
+        return DatOperationResult<>(SUCCESS, "Read data successful.");
     }
 
-    DatOperationResult
-    DatFileIO::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
+    DatOperationResult<>
+    DatIO::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
         if (file_handler_ == nullptr) {
             LOG(ERROR) << "IOError: file handler is null pointer on writing data";
-            return DatOperationResult(DatOperationResult::ERROR,
+            return DatOperationResult<>(ERROR,
                                       "IOError: file handler is null pointer on writing data.");
         }
 
@@ -193,7 +156,7 @@ namespace LOTRO_DAT {
 
         if (data_offset + size > data.size()) {
             LOG(ERROR) << "Trying to write more than BinaryData size";
-            return DatOperationResult(DatOperationResult::ERROR, "IOError: writing more than BinaryData size.");
+            return DatOperationResult<>(ERROR, "IOError: writing more than BinaryData size.");
         }
 
         fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
@@ -202,7 +165,7 @@ namespace LOTRO_DAT {
             actual_dat_size_ = offset + size;
         }
 
-        return DatOperationResult(DatOperationResult::SUCCESS, "Data writing successful.");
+        return DatOperationResult<>(SUCCESS, "Data writing successful.");
     }
 
 
@@ -210,14 +173,13 @@ namespace LOTRO_DAT {
     // DEINIT SECTION
     //------------------------------------------------//
 
-    DatOperationResult DatFileIO::DeInit() {
+    DatOperationResult<> DatIO::DeInit() {
         if (file_handler_ != nullptr) {
             fclose(file_handler_);
         }
 
         filename_ = "none";
         file_handler_ = nullptr;
-        root_directory_ = nullptr;
 
         constant1 = 0;
         constant2 = 0;
@@ -229,13 +191,13 @@ namespace LOTRO_DAT {
         root_directory_offset = 0;
         fragmentation_journal_offset = 0;
 
-        return DatOperationResult(DatOperationResult::SUCCESS, "File deinitialisation successfull");
+        return DatOperationResult<>(SUCCESS, "File deinitialisation successfull");
     }
 
-    DatOperationResult DatFileIO::ModifyFragmentationJournal() {
+    DatOperationResult<> DatIO::ModifyFragmentationJournal() {
         if (fragmentation_journal_size == 0)
-            return DatOperationResult(DatOperationResult::SUCCESS,
-                                      "DatFileIO: Fragmentation journal is empty. Nothing to do.");
+            return DatOperationResult<>(SUCCESS,
+                                      "DatIO: Fragmentation journal is empty. Nothing to do.");
         LOG(DEBUG) << "Modifying fragmentation journal";
         BinaryData data(4);
         ReadData(data, 4, fragmentation_journal_offset + 8 * fragmentation_journal_size);
@@ -256,10 +218,10 @@ namespace LOTRO_DAT {
         //nulldata = BinaryData(8);
         //WriteData(nulldata, nulldata.size(), fragmentation_journal_offset + 16);
         LOG(DEBUG) << "Finished modifying fragmentation journal";
-        return DatOperationResult(DatOperationResult::SUCCESS, "Fragmentation journal patched successfully!");
+        return DatOperationResult<>(SUCCESS, "Fragmentation journal patched successfully!");
     }
 
-    DatOperationResult DatFileIO::UpdateHeader() {
+    DatOperationResult<> DatIO::UpdateHeader() {
         LOG(DEBUG) << "Updating header";
         WriteData(BinaryData::FromNumber<4>(constant1), 4, 0x100);
         WriteData(BinaryData::FromNumber<4>(constant2), 4, 0x140);
@@ -273,15 +235,15 @@ namespace LOTRO_DAT {
         WriteData(BinaryData::FromNumber<4>(root_directory_offset), 4, 0x160);
         WriteData(BinaryData::FromNumber<4>(free_dat_size), 4, 0x19C);
         LOG(DEBUG) << "Finished updating header";
-        return DatOperationResult(DatOperationResult::SUCCESS, "File header patched successfully");;
+        return DatOperationResult<>(SUCCESS, "File header patched successfully");;
     }
 
-    std::shared_ptr<SubDirectory> DatFileIO::GetRootDirectory() {
-        return root_directory_;
+    DatOperationResult<long long> DatIO::GetActualDatSize() {
+        return DatOperationResult<long long>(actual_dat_size_, SUCCESS);
     }
 
-    long long DatFileIO::GetActualDatSize() {
-        return actual_dat_size_;
+    DatOperationResult<std::string> DatIO::GetFilename() {
+        return DatOperationResult<std::string>(filename_, SUCCESS);
     }
 }
 }

+ 5 - 0
src/DatSubsystems/DatLocaleManager.cpp

@@ -0,0 +1,5 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#include "DatSubsystems/DatLocaleManager.h"

+ 1 - 1
src/DatFilePatcher.cpp → src/DatSubsystems/DatPatcher.cpp

@@ -2,4 +2,4 @@
 // Created by kikab on 04.06.2018.
 //
 
-#include "DatFilePatcher.h"
+#include "DatSubsystems/DatPatcher.h"

+ 6 - 6
src/SubDirectory.cpp

@@ -42,7 +42,7 @@ namespace LOTRO_DAT {
 
     bool SubDirectory::MakeSubDirectories() {
         BinaryData data(1024);
-        dat_.io.ReadData(data, 63 * 8, offset_);
+        dat_.getIO().ReadData(data, 63 * 8, offset_);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -79,7 +79,7 @@ namespace LOTRO_DAT {
 
     bool SubDirectory::MakeSubFiles() {
         BinaryData data = BinaryData(4);
-        dat_.io.ReadData(data, 4, offset_ + 63 * 8);
+        dat_.getIO().ReadData(data, 4, offset_ + 63 * 8);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -94,7 +94,7 @@ namespace LOTRO_DAT {
 
         subfiles_.resize(unsigned(subfiles_number), nullptr);
         BinaryData headers(32 * unsigned(subfiles_number));
-        dat_.io.ReadData(headers, 32 * subfiles_number, offset_ + 63 * 8 + 4);
+        dat_.getIO().ReadData(headers, 32 * subfiles_number, offset_ + 63 * 8 + 4);
 
         // LOG(INFO) << "============== DIRECTORY offset = " << offset_ <<  "=======================";
 
@@ -147,8 +147,8 @@ namespace LOTRO_DAT {
             if (dict.count(file->file_id() != 0)) {
                 LOG(WARNING) << "Found multiple instances of file " << file->file_id() << " at dictionary offset "
                              << file->dictionary_offset() << ". Base offset = " << dict[file->file_id()]->dictionary_offset();
-                if (!dat_.CorrectSubfile(file) || dat_.CorrectSubfile(dict[file->file_id_]))
-                    continue;
+                //if (!dat_.CorrectSubfile(file) || dat_.CorrectSubfile(dict[file->file_id_]))
+                //    continue;
             }
             dict[file->file_id()] = file;
         }
@@ -194,7 +194,7 @@ namespace LOTRO_DAT {
             return FONT;
 
         BinaryData header(64);
-        dat_.io.ReadData(header, 64, (unsigned) file_offset + 8);
+        dat_.getIO().ReadData(header, 64, (unsigned) file_offset + 8);
 
         if (header.Empty()) {
             LOG(ERROR) << "Unable to read file header. file_id = " << file_id << ", offset = " << offset_;