فهرست منبع

Implemented DatOperationResult, DatFileSystem classes

Ivan Arkhipov 6 سال پیش
والد
کامیت
054eb5e928
6فایلهای تغییر یافته به همراه147 افزوده شده و 25 حذف شده
  1. 4 1
      include/DatOperationResult.h
  2. 5 0
      include/DatSubsystems/DatFileSystem.h
  3. 4 4
      include/SubFile.h
  4. BIN
      lib/libLotroDat_static.a
  5. 118 2
      src/DatSubsystems/DatFileSystem.cpp
  6. 16 18
      src/SubFile.cpp

+ 4 - 1
include/DatOperationResult.h

@@ -43,7 +43,8 @@ namespace LOTRO_DAT {
     public:
 
         DatOperationResult() : __DatOperationResult_base() {}
-        DatOperationResult(RESULT result_, std::string msg_) : __DatOperationResult_base(result_, msg_) {}
+        explicit DatOperationResult(RESULT result_) : __DatOperationResult_base(result_, "No message") {}
+        DatOperationResult(RESULT result_, std::string msg_) : __DatOperationResult_base(result_, std::move(msg_)) {}
     };
 
 
@@ -60,6 +61,8 @@ namespace LOTRO_DAT {
         template <typename OutputRef>
         DatOperationResult(OutputRef&& output_, RESULT result_, const std::string& msg_ = std::string("No message provided")) : __DatOperationResult_base(result_, msg_), value(std::forward<Output>(output_)) {}
 
+        operator Output() const {return value;}
+
         Output value;
     };
 

+ 5 - 0
include/DatSubsystems/DatFileSystem.h

@@ -15,6 +15,7 @@ extern "C++" {
 namespace LOTRO_DAT {
     class DatFile;
     class BinaryData;
+    class SubDirectory;
     class SubFile;
 
     class DatFileSystem {
@@ -32,6 +33,8 @@ namespace LOTRO_DAT {
 
         DatOperationResult<SubFile> GetFile(long long file_id);
 
+        DatOperationResult<bool> CheckCorrectSubfile(const SubFile &file);
+
         DatOperationResult<> UpdateFile(const SubFile& file);
 
         DatOperationResult<> DeInit();
@@ -53,6 +56,8 @@ namespace LOTRO_DAT {
 
     private:
         DatFile *dat;
+        std::shared_ptr<SubDirectory> root_directory_;
+
         std::set<long long> subfile_pending_update;
         std::map<long long, std::shared_ptr<SubFile> > dictionary_;
     };

+ 4 - 4
include/SubFile.h

@@ -25,9 +25,9 @@ namespace LOTRO_DAT
         friend class DatFile;
 		friend class SubDirectory;
     public:
-        SubFile() = delete;
-        explicit SubFile(const SubFile &other) = delete;
-		SubFile &operator =(const SubFile &other);
+        SubFile();
+        SubFile(const SubFile &other) = default;
+		SubFile &operator =(const SubFile &other) = default;
 
         SubFile(DatFile &dat, const BinaryData &header);
 		SubFile(DatFile &dat, long long dictionary_offset, long long fragments_count, long long unknown1,
@@ -60,7 +60,7 @@ namespace LOTRO_DAT
         long long category;
 
 	protected:
-		DatFile &dat_;
+		DatFile *dat_;
         long long dictionary_offset_;
 
         long long unknown1_;

BIN
lib/libLotroDat_static.a


+ 118 - 2
src/DatSubsystems/DatFileSystem.cpp

@@ -7,12 +7,14 @@
 #include <BinaryData.h>
 #include <DatFile.h>
 #include <SubFile.h>
+#include <SubDirectory.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)");
@@ -69,23 +71,137 @@ namespace LOTRO_DAT{
         return DatOperationResult<BinaryData>(data, SUCCESS);
     }
 
+
     DatOperationResult<SubFile> DatFileSystem::GetFile(long long file_id) {
+        if (!dat)
+            return DatOperationResult<SubFile>(SubFile(), ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
 
+        if (dictionary_.count(file_id) == 0)
+            return DatOperationResult<SubFile>(SubFile(), ERROR, "No file with id = " + std::to_string(file_id) + " found in dictionary");
+
+        return DatOperationResult<SubFile>(*dictionary_[file_id].get(), SUCCESS);
     }
 
+
     DatOperationResult<> DatFileSystem::UpdateFile(const SubFile &file) {
+        if (!dat)
+            return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        if (dictionary_.count(file.file_id()) == 0)
+            return DatOperationResult<>(ERROR, "No file with id = " + std::to_string(file.file_id()) + " found in dictionary. Cannot update file");
+
+        *dictionary_[file.file_id()] = file;
+        return DatOperationResult<>(SUCCESS);
     }
 
+
     DatOperationResult<> DatFileSystem::MakeDirectories() {
+        LOG(DEBUG) << "Started making directories";
+        if (!dat)
+            return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        root_directory_ = std::make_shared<SubDirectory>((unsigned)dat->getIO().root_directory_offset, *dat);
+        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(DEBUG) << "Directories made successfully";
+        return DatOperationResult<>(SUCCESS);
     }
 
+
     DatOperationResult<> DatFileSystem::MakeDictionary() {
+        LOG(DEBUG) << "Started making dictionary";
+        if (!dat)
+            return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        if (root_directory_ == nullptr) {
+            return DatOperationResult<>(ERROR, "DatFileSystem error: making dictionary from nullptr root directory");
+        }
+
+        root_directory_->MakeDictionary(dictionary_);
+        LOG(DEBUG) << "Dictionary made successfull";
+        return DatOperationResult<>(SUCCESS);
     }
 
+
     DatOperationResult<> DatFileSystem::CommitDirectories() {
+        if (!dat)
+            return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        for (auto file_id : subfile_pending_update) {
+            if (dictionary_[file_id] == nullptr)
+                continue;
+            auto operation = CheckCorrectSubfile(*dictionary_[file_id].get());
+            if (operation.result == ERROR) {
+                LOG(ERROR) << "Check subfile correctness failed. Error message: " << operation.msg;
+                continue;
+            }
+            if (!operation.value) {
+                LOG(DEBUG) << "Incorrect SubFile " << file_id << " data: doesn't match";
+                continue;
+            }
+
+
+            auto operation1 = dat->getIO().WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
+            if (operation1.result == ERROR) {
+                LOG(ERROR) << "Unable to write data to dictionary for file " << file_id << ". Returned message: " << operation.msg;
+            }
+        }
+        subfile_pending_update.clear();
+        return DatOperationResult<>(SUCCESS);
+    }
+
+    DatOperationResult<bool> DatFileSystem::CheckCorrectSubfile(const SubFile &file) {
+        if (!dat)
+            return DatOperationResult<bool>(false, ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
+
+        BinaryData mfile_id(20);
+        dat->getIO().ReadData(mfile_id, 20, file.file_offset() + 8);
+        if (mfile_id.Empty())
+            return DatOperationResult<bool>(false, SUCCESS);
+
+        return DatOperationResult<bool>((mfile_id.CheckCompression() || file.file_id() == mfile_id.ToNumber<4>(0)) && file.file_size() < 50ll * 1024ll * 1024ll, SUCCESS);
+    }
+
+
+    DatOperationResult<> DatFileSystem::Init() {
+        auto operation = MakeDirectories();
+        if (operation.result == ERROR) {
+            LOG(ERROR) << "Unable to make direcories. Error msg: " << operation.msg;
+            return DatOperationResult<>(ERROR, "Unable to init Dat file system due to fail while making directories");
+        }
+
+        operation = MakeDictionary();
+        if (operation.result == ERROR) {
+            LOG(ERROR) << "Unable to make dictionary. Error msg: " << operation.msg;
+            return DatOperationResult<>(ERROR, "Unable to init Dat file system due to fail while making dictionary");
+        }
+
+        return DatOperationResult<>(SUCCESS);
     }
 
-    DatOperationResult<> DatFileSystem::Init() {}
 
-    DatOperationResult<> DatFileSystem::DeInit() {}
+    DatOperationResult<> DatFileSystem::DeInit() {
+        auto operation = CommitDirectories();
+        if (operation.result == ERROR) {
+            LOG(ERROR) << "Unable to commit direcories. Error msg: " << operation.msg;
+            return DatOperationResult<>(ERROR, "Unable to deinit Dat file system due to fail while making directories");
+        }
+        return DatOperationResult<>(SUCCESS);
+    }
 }

+ 16 - 18
src/SubFile.cpp

@@ -9,14 +9,28 @@
 #include "EasyLogging++/easylogging++.h"
 
 #include <algorithm>
+#include <SubFile.h>
+
 
 const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
                                                   // will be recognized as incorrect and passed.
                                                   // This should be done because of not completely correct implementation
                                                   // of Subfiles and Subdirectories search in DatFile.
 namespace LOTRO_DAT {
+    SubFile::SubFile() : dat_(nullptr) {
+        category = 0;
+
+        unknown1_ = 0;
+        file_id_ = 0;
+        file_offset_ = 0;
+        file_size_ = 0;
+        timestamp_ = 0;
+        version_ = 0;
+        block_size_ = 0;
+        unknown2_ = 0;
+    }
 
-    SubFile::SubFile(DatFile &dat, const BinaryData &header) : dat_(dat) {
+    SubFile::SubFile(DatFile &dat, const BinaryData &header) : dat_(&dat) {
         category = 0;
 
         unknown1_ = header.ToNumber<4>(0); // unknown1
@@ -40,7 +54,7 @@ namespace LOTRO_DAT {
     SubFile::SubFile(DatFile &dat, long long dictionary_offset, long long unknown1, long long file_id,
                                 long long file_offset,
                                 long long file_size, long long timestamp, long long version, long long block_size, long long unknown2) :
-            category(0), dat_(dat), dictionary_offset_(dictionary_offset), unknown1_(unknown1), file_id_(file_id),
+            category(0), dat_(&dat), dictionary_offset_(dictionary_offset), unknown1_(unknown1), file_id_(file_id),
             file_offset_(file_offset),
             file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size), unknown2_(unknown2) {
 
@@ -164,20 +178,4 @@ namespace LOTRO_DAT {
     bool SubFile::operator!=(const SubFile &b) const {
         return !(*this == b);
     }
-
-    SubFile &SubFile::operator=(const SubFile &b) {
-        if (*this == b || &dat_ != &b.dat_)
-            return *this;
-
-        category = b.category;
-        unknown1_ = b.unknown1_; // unknown1
-        file_id_ = b.file_id_; // file_id
-        file_offset_ = b.file_offset_; // file_offset
-        file_size_ = b.file_size_; // block_size
-        timestamp_ = b.timestamp_; // timestamp
-        version_ = b.version_; // version
-        block_size_ = b.block_size_; // block_size
-        unknown2_ = b.unknown2_; // unknown2
-        return *this;
-    }
 };