瀏覽代碼

Divided DatFile class. Implemented DatFileIO, which is responcible for read/write operations

Ivan Arkhipov 6 年之前
父節點
當前提交
ea40c3fd50

+ 2 - 2
CMakeLists.txt

@@ -40,7 +40,7 @@ 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)
 
 set(SOURCE_FILES
         ${CMAKE_SOURCE_DIR}/src/DatFile.cpp
@@ -59,7 +59,7 @@ 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)
 
 set(CompilerFlags
         CMAKE_CXX_FLAGS

二進制
bin/LotRO_dat_patcher.exe


+ 5 - 33
include/DatFile.h

@@ -18,7 +18,9 @@
 #include <vector>
 #include <yaml-cpp/node/node.h>
 #include <unordered_set>
+
 #include "Database.h"
+#include "DatFileIO.h"
 
 // Dat file names definitions
 
@@ -99,6 +101,8 @@ namespace LOTRO_DAT {
 
         DAT_RESULT PerformDictionaryCheck();
 
+        DAT_RESULT ModifyFragmentationJournal();
+
         ~DatFile();
 
         // EXTRACT BASE SECTION
@@ -129,23 +133,8 @@ namespace LOTRO_DAT {
         DAT_RESULT CloseDatFile();
 
     private:
-        // INIT SECTION
-        DAT_RESULT OpenDatFile(const char *dat_name);
-
-        DAT_RESULT ReadSuperBlock();
-
-        DAT_RESULT MakeDirectories();
-
         DAT_RESULT MakeDictionary();
 
-        DAT_RESULT ModifyFragmentationJournal();
-
-        // READ-WRITE SECTION
-
-        DAT_RESULT ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
-
-        DAT_RESULT WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
-
         // PATCH SECTION
 
         DAT_RESULT ApplyFilePatch(std::shared_ptr<SubFile> file, BinaryData &data);
@@ -158,9 +147,6 @@ namespace LOTRO_DAT {
 
         void AddBufferedSize();
 
-        // COMMIT UPDATE SECTION
-
-        DAT_RESULT UpdateHeader();
 
         // LOCALE MANAGING SECTION
     private:
@@ -218,25 +204,11 @@ namespace LOTRO_DAT {
         std::set<long long> inactive_categories;
 
     private:
-        FILE *file_handler_;
-
-        std::shared_ptr<SubDirectory> root_directory_;
+        DatFileIO io;
 
         std::set<long long> pending_dictionary_;
         std::map<long long, std::shared_ptr<SubFile> > dictionary_;
 
-        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_;
-
-        long long actual_dat_size_;
         DAT_STATE dat_state_;
 
         int dat_id_;

+ 14 - 0
include/DatFileExporter.h

@@ -0,0 +1,14 @@
+//
+// 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

+ 95 - 0
include/DatFileIO.h

@@ -0,0 +1,95 @@
+//
+// 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
+

+ 14 - 0
include/DatFilePatcher.h

@@ -0,0 +1,14 @@
+//
+// 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

+ 35 - 0
include/DatOperationResult.h

@@ -0,0 +1,35 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H
+#define LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H
+
+#include <string>
+#include <utility>
+
+extern "C++"
+{
+namespace LOTRO_DAT {
+    class DatOperationResult {
+    public:
+        enum RESULT {
+            SUCCESS = 1,
+            ERROR = 0
+        };
+
+        DatOperationResult(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {}
+
+        DatOperationResult &operator=(const DatOperationResult &other) {
+            result = other.result;
+            msg = other.msg;
+            return *this;
+        }
+
+        RESULT result;
+        std::string msg;
+    };
+}
+}
+
+#endif //LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H

+ 1 - 0
include/LotroDat.h

@@ -5,6 +5,7 @@
 #include "DatFile.h"
 #include "Database.h"
 #include "SubfileData.h"
+#include "DatOperationResult.h"
 
 #include "yaml-cpp/yaml.h"
 #include "ZLib/zlib.h"

+ 66 - 264
src/DatFile.cpp

@@ -8,6 +8,7 @@
 #include "SubDirectory.h"
 #include "SubFile.h"
 #include "SubfileData.h"
+#include "DatOperationResult.h"
 
 #include <EasyLogging++/easylogging++.h>
 //#include <unistd.h>
@@ -31,10 +32,8 @@ namespace LOTRO_DAT {
     // INIT SECTION
     //------------------------------------------------//
 
-    DatFile::DatFile() {
+    DatFile::DatFile() : io(*this) {
         dat_state_ = CLOSED;
-        root_directory_ = nullptr;
-        file_handler_ = nullptr;
         free_buffered_size_ = 0;
 
         orig_dict_.clear();
@@ -78,43 +77,18 @@ namespace LOTRO_DAT {
         dat_id_ = dat_id;
         dat_state_ = CLOSED;
         current_locale_ = ORIGINAL;
-        root_directory_ = nullptr;
-        file_handler_ = nullptr;
         free_buffered_size_ = 0;
         filename_ = "none";
 
         DAT_RESULT result;
         DAT_RESULT return_value = SUCCESS;
 
-        LOG(INFO) << "Opening .dat file " << filename;
-        result = OpenDatFile(filename.c_str());
-        if (result != SUCCESS) {
-            LOG(ERROR) << "Unable to perform opening file. Aborting.";
+        auto res = io.Init(filename);
+        if (res.result == DatOperationResult::ERROR) {
+            LOG(ERROR) << "ERROR! Unable to initialize input-output!";
             CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        LOG(INFO) << "Starting ReadSuperBlock";
-
-        result = ReadSuperBlock();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to read super block. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        LOG(INFO) << "Starting MakeDirectories";
-
-        result = MakeDirectories();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to make directories. Aborting.";
-            CloseDatFile();
-            return result;
+            return NO_FILE_ERROR;
         }
-        return_value = std::max(return_value, result);
-
         LOG(INFO) << "Starting MakeDictionary";
 
         result = MakeDictionary();
@@ -163,100 +137,6 @@ namespace LOTRO_DAT {
         return return_value;
     }
 
-    DAT_RESULT DatFile::OpenDatFile(const char *dat_name) {
-        LOG(DEBUG) << "Started opening DatFile";
-        if (dat_state_ != CLOSED) {
-            CloseDatFile();
-        }
-
-        file_handler_ = fopen(dat_name, "r+b");
-
-        if (file_handler_ == nullptr) {
-            LOG(ERROR) << "Unable to open file " << dat_name;
-            return NO_FILE_ERROR;
-        }
-
-        fseek(file_handler_, 0, SEEK_END);
-        actual_dat_size_ = ftell(file_handler_);
-        fseek(file_handler_, 0, SEEK_SET);
-
-        dat_state_ = SUCCESS_OPENED;
-        LOG(DEBUG) << "Successfully opened DatFile";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ReadSuperBlock() {
-        LOG(DEBUG) << "Started reading superblock";
-        if (dat_state_ != SUCCESS_OPENED) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_OPENED. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        BinaryData data(1024);
-        ReadData(data, 1024);
-
-        constant1_ = data.ToNumber<4>(0x100);
-        constant2_ = data.ToNumber<4>(0x140);
-        version1_ = data.ToNumber<4>(0x14C);
-        file_size_ = data.ToNumber<4>(0x148);
-        version2_ = data.ToNumber<4>(0x150);
-        fragmentation_journal_offset_ = data.ToNumber<4>(0x154);
-        fragmentation_journal_end_ = data.ToNumber<4>(0x158);
-        fragmentation_journal_size_ = data.ToNumber<4>(0x15C);
-        root_directory_offset_ = data.ToNumber<4>(0x160);
-        free_dat_size_ = data.ToNumber<4>(0x19C);
-
-        if (constant1_ != 0x4C5000) {
-            LOG(ERROR) << "variable at position 0x100 is not equal to .dat file constant!";
-            return INCORRECT_SUPERBLOCK_ERROR;
-        }
-        if (constant2_ != 0x5442) {
-            LOG(ERROR) << "variable at position 0x140 is not equal to .dat file constant!";
-            return INCORRECT_SUPERBLOCK_ERROR;
-        }
-
-        if (file_size_ != actual_dat_size_) {
-            LOG(ERROR) << "variable at 0x148 position is not equal to .dat file size!";
-            //return CORRUPTED_FILE_WARNING;
-        }
-
-        dat_state_ = SUCCESS_SUPERBLOCK;
-        LOG(DEBUG) << "Superblock read successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::MakeDirectories() {
-        LOG(DEBUG) << "Started making directories";
-        if (dat_state_ != SUCCESS_SUPERBLOCK) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_SUPERBLOCK. Cannot make directories.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        root_directory_ = std::make_shared<SubDirectory>((unsigned) root_directory_offset_, *this);
-        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();
-        }
-
-        dat_state_ = SUCCESS_DIRECTORIES;
-
-        LOG(DEBUG) << "Directories made successfully";
-        return SUCCESS;
-    }
-
     DAT_RESULT DatFile::MakeDictionary() {
         LOG(DEBUG) << "Started making dictionary";
         if (dat_state_ != SUCCESS_DIRECTORIES) {
@@ -264,12 +144,12 @@ namespace LOTRO_DAT {
             return INCORRECT_STATE_ERROR;
         }
 
-        if (root_directory_ == nullptr) {
+        if (io.GetRootDirectory() == nullptr) {
             LOG(ERROR) << "root_directory is nullptr!!";
             return INIT_ERROR;
         }
 
-        root_directory_->MakeDictionary(dictionary_);
+        io.GetRootDirectory()->MakeDictionary(dictionary_);
         dat_state_ = SUCCESS_DICTIONARY;
         LOG(DEBUG) << "Dictionary made successfull";
         return SUCCESS;
@@ -279,43 +159,44 @@ namespace LOTRO_DAT {
         LOG(INFO) << "Initialising locales...";
         BinaryData dicts_data(4);
 
-        ReadData(dicts_data, 4, 300);
+        io.ReadData(dicts_data, 4, 300);
         long long dict_offset = dicts_data.ToNumber<4>(0);
 
-        if (dict_offset == 0 || dict_offset + 8 >= actual_dat_size_) {
+        if (dict_offset == 0 || dict_offset + 8 >= io.GetActualDatSize()) {
             LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
             return SUCCESS;
         }
 
-        ReadData(dicts_data, 4, dict_offset);
+        io.ReadData(dicts_data, 4, dict_offset);
         long long dict_size = dicts_data.ToNumber<4>(0);
 
-        ReadData(dicts_data, 4, dict_offset + 4);
+        io.ReadData(dicts_data, 4, dict_offset + 4);
         long long dict_version = dicts_data.ToNumber<4>(0);
 
-        ReadData(dicts_data, 4, dict_offset + 8);
-        file_size_ = 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 = " << file_size_;
+        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();
-            WriteData(BinaryData::FromNumber<4>(0), 4, 300);
+            io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
             dat_state_ = UPDATED;
             dat_without_patches_ = true;
             return SUCCESS;
         }
 
         dicts_data = BinaryData((unsigned)dict_size);
-        ReadData(dicts_data, dict_size, dict_offset + 12);
+        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();
-            WriteData(BinaryData::FromNumber<4>(0), 4, 300);
+            io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
             dat_state_ = UPDATED;
             dat_without_patches_ = true;
             return SUCCESS;
@@ -434,24 +315,20 @@ namespace LOTRO_DAT {
         }
 
         // 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;
+            //free_dat_size = 128248;
+            //fragmentation_journal_end = 0;
+            //fragmentation_journal_size = 1;
             //UpdateHeader();
         }
 
         current_locale_ = ORIGINAL;
 
-        if (file_handler_ != nullptr) {
-            fclose(file_handler_);
-        }
         SubDirectory::visited_subdirectories_.clear();
-        //truncate64(filename_.c_str(), file_size_);
 
         free_buffered_size_ = 0;
 
@@ -462,23 +339,9 @@ namespace LOTRO_DAT {
         pending_patch_.clear();
         inactive_categories.clear();
 
-        file_handler_ = nullptr;
-        root_directory_ = nullptr;
-
-
         pending_dictionary_.clear();
         dictionary_.clear();
 
-        constant1_ = 0;
-        constant2_ = 0;
-        file_size_ = 0;
-        version1_ = 0;
-        version2_ = 0;
-        fragmentation_journal_size_ = 0;
-        fragmentation_journal_end_ = 0;
-        root_directory_offset_ = 0;
-        fragmentation_journal_offset_ = 0;
-
         dat_state_ = CLOSED;
 
         dat_id_ = -1;
@@ -540,31 +403,33 @@ namespace LOTRO_DAT {
 
 
         BinaryData dicts_data(4);
-        ReadData(dicts_data, 4, 300);
+        io.ReadData(dicts_data, 4, 300);
         long long dict_offset = dicts_data.ToNumber<4>(0);
-        ReadData(dicts_data, 4, dict_offset);
+        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) {
-            WriteData(BinaryData::FromNumber<4>(file_size_), 4, 300);
+            io.WriteData(BinaryData::FromNumber<4>(io.file_size), 4, 300);
 
-            WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 4, file_size_);
-            WriteData(BinaryData::FromNumber<4>(101), 4, file_size_ + 4);
-            WriteData(BinaryData::FromNumber<4>(file_size_ + binary_data.size() + 12 + 20 * 1024 * 1024), 4, file_size_ + 8); // Writing current file size;
+            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;
 
-            WriteData(binary_data, binary_data.size(), file_size_ + 12);
-            file_size_ += binary_data.size() + 12;
+            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));
-            WriteData(nulls, nulls.size(), file_size_);
-            file_size_ += nulls.size();
+            io.WriteData(nulls, nulls.size(), io.file_size);
+            io.file_size += nulls.size();
 
         } else {
-            WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size(), 20u * 1024u * 1024u)), 4, dict_offset);
-            WriteData(BinaryData::FromNumber<4>(101), 4, dict_offset + 4);
-            WriteData(BinaryData::FromNumber<4>(file_size_), 4, dict_offset + 8); // Writing current file size;
-            WriteData(binary_data, binary_data.size(), dict_offset + 12);
+            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;
@@ -574,53 +439,38 @@ namespace LOTRO_DAT {
         for (auto file_id : pending_dictionary_) {
             if (dictionary_[file_id] == nullptr || !CorrectSubfile(dictionary_[file_id]))
                 continue;
-            WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
+            io.WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
         }
         pending_dictionary_.clear();
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::ModifyFragmentationJournal() {
-        if (fragmentation_journal_size_ == 0)
+        if (io.fragmentation_journal_size == 0)
             return SUCCESS;
         LOG(DEBUG) << "Modifying fragmentation journal";
         BinaryData data(4);
-        ReadData(data, 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_);
+        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 = file_size_;
+        long long free_offset = io.file_size;
 
         BinaryData nulldata = BinaryData(unsigned(free_size));
-        WriteData(nulldata, nulldata.size(), file_size_);
-        file_size_ += nulldata.size();
+        io.WriteData(nulldata, nulldata.size(), io.file_size);
+        io.file_size += nulldata.size();
 
-        WriteData(BinaryData::FromNumber<4>(free_size), 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_);
-        WriteData(BinaryData::FromNumber<4>(free_offset), 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_ + 4);
+        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);
-        //WriteData(nulldata, nulldata.size(), fragmentation_journal_offset_ + 16);
+        //io.WriteData(nulldata, nulldata.size(), fragmentation_journal_offset + 16);
         LOG(DEBUG) << "Finished modifying fragmentation journal";
         return SUCCESS;
     }
 
-    DAT_RESULT DatFile::UpdateHeader() {
-        LOG(DEBUG) << "Updating header";
-        WriteData(BinaryData::FromNumber<4>(constant1_), 4, 0x100);
-        WriteData(BinaryData::FromNumber<4>(constant2_), 4, 0x140);
-        //WriteData(BinaryData::FromNumber<4>(    0     ), 4, 0x144);
-        WriteData(BinaryData::FromNumber<4>(file_size_), 4, 0x148);
-        WriteData(BinaryData::FromNumber<4>(version1_ ), 4, 0x14C);
-        WriteData(BinaryData::FromNumber<4>(version2_ ), 4, 0x150);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset_), 4, 0x154);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_end_), 4, 0x158);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_size_), 4, 0x15C);
-        WriteData(BinaryData::FromNumber<4>(root_directory_offset_), 4, 0x160);
-        WriteData(BinaryData::FromNumber<4>(free_dat_size_), 4, 0x19C);
-        LOG(DEBUG) << "Finished updating header";
-        return SUCCESS;
-    }
-
     DAT_RESULT DatFile::RepairDatFile() {
         for (const auto& file : dictionary_) {
             auto subfile = file.second;
@@ -761,10 +611,9 @@ namespace LOTRO_DAT {
 
     DAT_RESULT DatFile::PatchFile(const SubfileData &data) {
         LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>() << ".";
-        actual_dat_size_ = std::max(file_size_, actual_dat_size_);
 
         if (!dat_without_patches_) {
-            file_size_ = actual_dat_size_;
+            io.file_size = io.GetActualDatSize();
         }
 
         if (dat_state_ < READY) {
@@ -864,8 +713,8 @@ namespace LOTRO_DAT {
 
 //        if (patch_dict_.size() == 0 && pending_dictionary_.size() == 0) {
 //            BinaryData nulls(50 * 1024 * 1024);
-//            WriteData(nulls, nulls.size(), file_size_);
-//            file_size_ += 50 * 1024 * 1024;
+//            io.WriteData(nulls, nulls.size(), file_size);
+//            file_size += 50 * 1024 * 1024;
 //        }
 
         if (data.Empty()) {
@@ -890,13 +739,13 @@ namespace LOTRO_DAT {
         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_ = file_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();
 
-            this->file_size_ += file->block_size_ + 8;
+            io.file_size += file->block_size_ + 8;
         }
 
         file->file_size_ = data.size() - 8;
@@ -910,7 +759,7 @@ namespace LOTRO_DAT {
 
         //data.ProtectData();
         //BinaryData data1(data.size());
-        WriteData(data, data.size(), file->file_offset());
+        io.WriteData(data, data.size(), file->file_offset());
         //data.DeprotectData();
 
         patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
@@ -948,7 +797,7 @@ namespace LOTRO_DAT {
         LOG(DEBUG) << "Getting file " << file->file_id() << " data";
 
         BinaryData mfile_id(20);
-        ReadData(mfile_id, 20, file->file_offset() + 8);
+        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.";
@@ -964,82 +813,35 @@ namespace LOTRO_DAT {
 
         BinaryData data((unsigned)(file->file_size() + (8 - offset)));
         if (file->block_size() >= file->file_size() + 8) {
-            ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
+            io.ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
             return data;
         }
 
         BinaryData fragments_count(4);
-        ReadData(fragments_count, 4, file->file_offset());
+        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;
 
-        ReadData(data, current_block_size, file->file_offset() + offset);
+        io.ReadData(data, current_block_size, file->file_offset() + offset);
 
         BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-        ReadData(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);
-            ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset,
-                     current_block_size);
+            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;
     }
 
-    DAT_RESULT DatFile::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (dat_state_ == CLOSED) {
-            LOG(ERROR) << "Dat state is CLOSED. Cannot read data.";
-            data = BinaryData(0);
-            return INIT_ERROR;
-        }
-
-        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 DAT_READ_ERROR;
-        }
-
-
-
-        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 DAT_READ_ERROR;
-        }
-
-        if (offset != ftell(file_handler_))
-            fseek(file_handler_, offset, SEEK_SET);
-        fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (dat_state_ < SUCCESS_DICTIONARY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot write data.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        if (offset != ftell(file_handler_))
-            fseek(file_handler_, offset, SEEK_SET);
-
-        if (data_offset + size > data.size()) {
-            LOG(ERROR) << "Trying to write more than BinaryData size";
-            return DAT_WRITE_ERROR;
-        }
-
-        fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
-        actual_dat_size_ = std::max(file_size_, actual_dat_size_);
-        return SUCCESS;
-    }
 
     //------------------------------------------------//
     // LOCALE SECTION
@@ -1117,7 +919,7 @@ namespace LOTRO_DAT {
 
     bool DatFile::CorrectSubfile(std::shared_ptr<SubFile> file) {
         BinaryData mfile_id(20);
-        ReadData(mfile_id, 20, file->file_offset() + 8);
+        io.ReadData(mfile_id, 20, file->file_offset() + 8);
         if (mfile_id.Empty())
             return false;
 
@@ -1142,7 +944,7 @@ namespace LOTRO_DAT {
 //                //patch_dict_.clear();
 //                LOG(INFO) << "DAT FILE WAS UPDATED!!!! CLEARING PATCH DATA";
 //                pending_patch_.insert(file_id);
-//                WriteData(BinaryData::FromNumber<4>(0), 4, 300);
+//                io.WriteData(BinaryData::FromNumber<4>(0), 4, 300);
 //                return true;
 //            }
 //        }
@@ -1215,7 +1017,7 @@ namespace LOTRO_DAT {
         if (free_buffered_size_ >= MIN_BUFFERED_SIZE)
             return;
         BinaryData nulls(MAX_BUFFERED_SIZE);
-        WriteData(nulls, MAX_BUFFERED_SIZE, file_size_);
+        io.WriteData(nulls, MAX_BUFFERED_SIZE, io.file_size);
         free_buffered_size_ = MAX_BUFFERED_SIZE;
     }
 

+ 5 - 0
src/DatFileExporter.cpp

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

+ 290 - 0
src/DatFileIO.cpp

@@ -0,0 +1,290 @@
+//
+// Created by kikab on 04.06.2018.
+//
+
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "DatFileIO.h"
+#include "EasyLogging++/easylogging++.h"
+#include "SubDirectory.h"
+#include "SubFile.h"
+
+#include <algorithm>
+#include <iterator>
+#include <locale>
+#include <DatOperationResult.h>
+#include <DatFileIO.h>
+
+
+#ifdef WIN32
+#define fseek _fseeki64
+#define ftell _ftelli64
+#endif
+
+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) {
+    }
+
+    //------------------------------------------------//
+    // INIT SECTION
+    //------------------------------------------------//
+
+
+    DatOperationResult DatFileIO::Init(const std::string &filename) {
+        LOG(INFO) << "Initializing IO: " << filename;
+
+        filename_ = filename;
+
+        auto result = OpenDatFile();
+        if (result.result == DatOperationResult::ERROR) {
+            LOG(ERROR) << "Error in OpenDatFile: " << result.msg;
+            DeInit();
+            return result;
+        }
+
+        result = ReadSuperBlock();
+        if (result.result == DatOperationResult::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");
+    }
+
+    DatOperationResult DatFileIO::OpenDatFile() {
+        LOG(DEBUG) << "DatFileIO: 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_));
+        }
+
+        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_));
+    }
+
+    DatOperationResult DatFileIO::ReadSuperBlock() {
+        LOG(INFO) << "DatFileIO: Started reading superblock";
+
+        BinaryData data(1024);
+        ReadData(data, 1024);
+
+        constant1 = data.ToNumber<4>(0x100);
+        constant2 = data.ToNumber<4>(0x140);
+        version1 = data.ToNumber<4>(0x14C);
+        file_size = data.ToNumber<4>(0x148);
+        version2 = data.ToNumber<4>(0x150);
+        fragmentation_journal_offset = data.ToNumber<4>(0x154);
+        fragmentation_journal_end = data.ToNumber<4>(0x158);
+        fragmentation_journal_size = data.ToNumber<4>(0x15C);
+        root_directory_offset = data.ToNumber<4>(0x160);
+        free_dat_size = data.ToNumber<4>(0x19C);
+
+        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!"));;
+        }
+        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!"));;
+        }
+
+        if (file_size != actual_dat_size_) {
+            LOG(INFO) << "Variable at 0x148 position is not equal to .dat file size!";
+            //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."));
+    }
+
+
+    //------------------------------------------------//
+    // PUBLIC READ/WRITE SECTION
+    //------------------------------------------------//
+
+    DatOperationResult
+    DatFileIO::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.");
+        }
+
+        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.");
+        }
+
+        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.");
+        }
+
+        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.");
+    }
+
+    DatOperationResult
+    DatFileIO::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,
+                                      "IOError: file handler is null pointer on writing data.");
+        }
+
+        if (offset != ftell(file_handler_))
+            fseek(file_handler_, offset, SEEK_SET);
+
+        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.");
+        }
+
+        fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
+
+        if (offset + size > actual_dat_size_) {
+            actual_dat_size_ = offset + size;
+        }
+
+        return DatOperationResult(DatOperationResult::SUCCESS, "Data writing successful.");
+    }
+
+    //------------------------------------------------//
+    // DEINIT SECTION
+    //------------------------------------------------//
+
+    DatOperationResult DatFileIO::DeInit() {
+        UpdateHeader();
+
+        if (file_handler_ != nullptr) {
+            fclose(file_handler_);
+        }
+
+        filename_ = "none";
+        file_handler_ = nullptr;
+        root_directory_ = nullptr;
+
+        constant1 = 0;
+        constant2 = 0;
+        file_size = 0;
+        version1 = 0;
+        version2 = 0;
+        fragmentation_journal_size = 0;
+        fragmentation_journal_end = 0;
+        root_directory_offset = 0;
+        fragmentation_journal_offset = 0;
+
+        return DatOperationResult(DatOperationResult::SUCCESS, "File deinitialisation successfull");
+    }
+
+
+    DatOperationResult DatFileIO::ModifyFragmentationJournal() {
+        if (fragmentation_journal_size == 0)
+            return DatOperationResult(DatOperationResult::SUCCESS,
+                                      "DatFileIO: 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);
+        LOG(INFO) << "FREE_SIZE BLOCK = " << data.ToNumber<4>(0);
+
+        long long free_size = data.ToNumber<4>(0);
+        long long free_offset = file_size;
+
+        BinaryData nulldata = BinaryData(unsigned(free_size));
+        WriteData(nulldata, nulldata.size(), file_size);
+        file_size += nulldata.size();
+
+        WriteData(BinaryData::FromNumber<4>(free_size), 4,
+                  fragmentation_journal_offset + 8 * fragmentation_journal_size);
+        WriteData(BinaryData::FromNumber<4>(free_offset), 4,
+                  fragmentation_journal_offset + 8 * fragmentation_journal_size + 4);
+
+        //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!");
+    }
+
+
+    DatOperationResult DatFileIO::UpdateHeader() {
+        LOG(DEBUG) << "Updating header";
+        WriteData(BinaryData::FromNumber<4>(constant1), 4, 0x100);
+        WriteData(BinaryData::FromNumber<4>(constant2), 4, 0x140);
+        //WriteData(BinaryData::FromNumber<4>(    0     ), 4, 0x144);
+        WriteData(BinaryData::FromNumber<4>(file_size), 4, 0x148);
+        WriteData(BinaryData::FromNumber<4>(version1), 4, 0x14C);
+        WriteData(BinaryData::FromNumber<4>(version2), 4, 0x150);
+        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset), 4, 0x154);
+        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_end), 4, 0x158);
+        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_size), 4, 0x15C);
+        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");;
+    }
+
+    std::shared_ptr<SubDirectory> DatFileIO::GetRootDirectory() {
+        return root_directory_;
+    }
+
+    long long DatFileIO::GetActualDatSize() {
+        return actual_dat_size_;
+    }
+}
+}

+ 5 - 0
src/DatFilePatcher.cpp

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

+ 5 - 4
src/SubDirectory.cpp

@@ -8,6 +8,7 @@
 #include "BinaryData.h"
 #include "SubfileData.h"
 #include "EasyLogging++/easylogging++.h"
+#include "DatOperationResult.h"
 
 #include "Subfiles/TextSubFile.h"
 #include "Subfiles/DdsSubFile.h"
@@ -41,7 +42,7 @@ namespace LOTRO_DAT {
 
     bool SubDirectory::MakeSubDirectories() {
         BinaryData data(1024);
-        dat_.ReadData(data, 63 * 8, offset_);
+        dat_.io.ReadData(data, 63 * 8, offset_);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -78,7 +79,7 @@ namespace LOTRO_DAT {
 
     bool SubDirectory::MakeSubFiles() {
         BinaryData data = BinaryData(4);
-        dat_.ReadData(data, 4, offset_ + 63 * 8);
+        dat_.io.ReadData(data, 4, offset_ + 63 * 8);
 
         if (data.Empty()) {
             LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
@@ -93,7 +94,7 @@ namespace LOTRO_DAT {
 
         subfiles_.resize(unsigned(subfiles_number), nullptr);
         BinaryData headers(32 * unsigned(subfiles_number));
-        dat_.ReadData(headers, 32 * subfiles_number, offset_ + 63 * 8 + 4);
+        dat_.io.ReadData(headers, 32 * subfiles_number, offset_ + 63 * 8 + 4);
 
         // LOG(INFO) << "============== DIRECTORY offset = " << offset_ <<  "=======================";
 
@@ -193,7 +194,7 @@ namespace LOTRO_DAT {
             return FONT;
 
         BinaryData header(64);
-        dat_.ReadData(header, 64, (unsigned) file_offset + 8);
+        dat_.io.ReadData(header, 64, (unsigned) file_offset + 8);
 
         if (header.Empty()) {
             LOG(ERROR) << "Unable to read file header. file_id = " << file_id << ", offset = " << offset_;