Browse Source

Added minor functions for patch processing

Added functions for working with directory structure while patching the
file. Discovered dictionary named as "Fragmentation journal" where some
free (unused) pieces of DatFile are described. Added basic
implementation, due to which new files if they are bigger will be added
to free space after the file, ignoring fragmentation journal
Ivan Arkhipov 7 years ago
parent
commit
26b699fce8

+ 72 - 1
Source/DatFile.cpp

@@ -16,11 +16,13 @@ extern "C++"
 namespace LOTRO_DAT {
     DatFile::DatFile() {
         dat_state_ = CLOSED;
+        patched_ = false;
     }
 
     DatFile::DatFile(const char *filename, int dat_id) {
         dat_id_ = dat_id;
         dat_state_ = CLOSED;
+        patched_ = false;
         OpenDatFile(filename);
         ReadSuperBlock();
         MakeDirectories();
@@ -39,6 +41,12 @@ namespace LOTRO_DAT {
     }
 
     DatFile::~DatFile() {
+        if (patched_) {
+            std::cout << "There are some updated files. Rewriting dictionary..." << std::endl << std::flush;
+            UpdateHeader();
+            UpdateSubdirectories();
+        }
+
         if (file_handler_ != nullptr)
 		    fclose(file_handler_);
         delete file_handler_;
@@ -79,7 +87,7 @@ namespace LOTRO_DAT {
         }
 
         for (int i = 0; i < export_size; ++i) {
-            binary_data[i].WriteToFile(path + "_" + std::to_string(i) + options[i]["extension"].as<std::string>());
+            binary_data[i].WriteToFile(path + "_" + std::to_string(i) + options[i]["ext"].as<std::string>());
         }
         return true;
     }
@@ -231,6 +239,7 @@ namespace LOTRO_DAT {
         return data;
     }
 
+
     /// DatFile constants' getters.
 
     long long DatFile::constant1() const {
@@ -287,6 +296,7 @@ namespace LOTRO_DAT {
         constant2_ = data.ToNumber<4>(0x140);
         version1_ = data.ToNumber<4>(0x14C);
         version2_ = data.ToNumber<4>(0x150);
+        fragmentation_journal_offset_ = data.ToNumber<4>(0x154);
         root_directory_offset_ = data.ToNumber<4>(0x160);
         auto size1 = data.ToNumber<4>(0x148);
 
@@ -360,5 +370,66 @@ namespace LOTRO_DAT {
 
         fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
     }
+
+    /// Special functions used by patch process.
+    /// Shouldn't be used by any external class.
+
+    void DatFile::ApplyFilePatch(const Subfile *file, const BinaryData &data) {
+        auto journal = GetFragmentationJournal();
+
+        // TODO: write content
+
+        UpdateFragmentationJournal(journal);
+        patched_ = true;
+    }
+
+    void DatFile::UpdateSubdirectories() {
+        root_directory_ -> UpdateDirectories();
+        return;
+    }
+
+    std::vector<std::pair<long long, long long> > DatFile::GetFragmentationJournal() {
+        BinaryData data(8);
+        ReadData(data, 8, fragmentation_journal_offset_ + 8);
+        std::vector<std::pair<long long, long long> > result;
+        result.emplace_back(std::make_pair(data.ToNumber<4>(0), data.ToNumber<4>(4)));
+        return result;
+    }
+
+    void DatFile::UpdateHeader() {
+        BinaryData data(4);
+
+        data.FromNumber<4>(constant1_);
+        WriteData(data, 4, 0x100);
+
+        data.FromNumber<4>(constant2_);
+        WriteData(data, 4, 0x140);
+
+        data.FromNumber<4>(version1_);
+        WriteData(data, 4, 0x14C);
+
+        data.FromNumber<4>(version2_);
+        WriteData(data, 4, 0x150);
+
+        data.FromNumber<4>(fragmentation_journal_offset_);
+        WriteData(data, 4, 0x150);
+
+        data.FromNumber<4>(root_directory_offset_);
+        WriteData(data, 4, 0x150);
+    }
+
+    void DatFile::UpdateFragmentationJournal(const std::vector<std::pair<long long, long long> > &journal) {
+        for (int i = 0; i < journal.size(); i++) {
+            long long size = journal[i].first;
+            long long offset = journal[i].second;
+
+            BinaryData data(4);
+            data.FromNumber<4>(size);
+            WriteData(data, 4, fragmentation_journal_offset_ + 8 * (i + 1));
+
+            data.FromNumber<4>(offset);
+            WriteData(data, 4, fragmentation_journal_offset_ + 8 * (i + 1) + 4);
+        }
+    }
 }
 }

+ 11 - 0
Source/DatFile.h

@@ -15,6 +15,7 @@
 #include <map>
 #include <unordered_map>
 #include <set>
+#include <vector>
 #include "Database.h"
 
 // Dat file names definitions
@@ -91,15 +92,25 @@ namespace LOTRO_DAT
         void ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
         void WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
 
+        void ApplyFilePatch(const Subfile* file, const BinaryData &data);
+        void UpdateSubdirectories();
+        std::vector<std::pair<long long, long long> > GetFragmentationJournal();
+        void UpdateHeader();
+        void UpdateFragmentationJournal(const std::vector<std::pair<long long, long long> > &journal);
+
         long long constant1_;
         long long constant2_;
         long long file_size_;
         long long version1_;
         long long version2_;
         long long root_directory_offset_;
+        long long fragmentation_journal_offset_;
 
         DAT_STATE dat_state_;
+
         int dat_id_;
+        bool patched_;
+
     };
 }
 }

+ 8 - 0
Source/SubDirectory.cpp

@@ -104,6 +104,14 @@ namespace LOTRO_DAT {
             i.MakeDictionary(dict);
     }
 
+    void SubDirectory::UpdateDirectories() {
+        for (unsigned i = 0; i < subfiles_.size(); i++) {
+            dat_->WriteData(subfiles_[i]->MakeHeaderData(), 32, offset_ + 63ll * 8ll + i * 32);
+        }
+        for (unsigned i = 0; i < subdirs_.size(); i++)
+            subdirs_[i].UpdateDirectories();
+    }
+
     Subfile *SubDirectory::MakeSubfile(long long fragments_count, 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) {

+ 1 - 0
Source/SubDirectory.h

@@ -25,6 +25,7 @@ namespace LOTRO_DAT
         SubDirectory();
         SubDirectory(long long offset, DatFile *dat, long long max_subdirs = 63);
         void MakeDictionary(std::unordered_map<long long, Subfile*> &dict);
+        void UpdateDirectories();
 
     private:
         void MakeSubDirectories();

+ 22 - 1
Source/Subfile.cpp

@@ -107,4 +107,25 @@ namespace LOTRO_DAT {
         throw DatException("Bad Subfile::MakeForImport() - function is not implemented for this type.", IMPORT_EXCEPTION);
     }
 
- };
+    BinaryData Subfile::MakeHeaderData() {
+        BinaryData header(32);
+        BinaryData data(4);
+        data.FromNumber<4>(fragments_count_);
+        header = header + data;
+        data.FromNumber<4>(unknown1_);
+        header = header + data;
+        data.FromNumber<4>(file_id_);
+        header = header + data;
+        data.FromNumber<4>(file_offset_);
+        header = header + data;
+        data.FromNumber<4>(file_size_);
+        header = header + data;
+        data.FromNumber<4>(timestamp_);
+        header = header + data;
+        data.FromNumber<4>(version_);
+        header = header + data;
+        data.FromNumber<4>(block_size_);
+        header = header + data;
+    }
+
+};

+ 2 - 0
Source/Subfile.h

@@ -34,6 +34,8 @@ namespace LOTRO_DAT
         virtual BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
                                 const std::u16string &text_data, const YAML::Node &options);
 
+		BinaryData MakeHeaderData();
+
         long long fragments_count() const;
         long long unknown1() const;
         long long file_id() const;

+ 2 - 1
Source/Subfiles/DdsSubfile.cpp

@@ -151,8 +151,9 @@ namespace LOTRO_DAT {
             !options["fid"] || options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
+
         if (old_data.CheckCompression())
-            return old_data.CutData(0, 12) + (old_data.CutData(12, 16) + binary_data.CutData(128)).CompressData();
+            return old_data.CutData(0, 12) + (old_data.DecompressData(12).CutData(12, 16) + binary_data.CutData(128)).CompressData();
         else
             return old_data.CutData(0, 16) + binary_data.CutData(128);
     }

+ 7 - 7
Source/Tests/extract_test.cpp

@@ -23,16 +23,16 @@ const std::string filename = "client_local_English.dat";
 const bool exportImagesToFiles = false;
 const bool exportFontsToFiles = false;
 const bool exportSoundsToFiles = false;
-const bool exportTexturesToFiles = false;
+const bool exportTexturesToFiles = true;
 const bool exportUnknownToFiles = false;
 
 // Change these variables to true if you want export catecory to databases.
-const bool exportTextsToDb = true;
-const bool exportImagesToDb = true;
-const bool exportFontsToDb = true;
-const bool exportSoundsToDb = true;
-const bool exportTexturesToDb = true;
-const bool exportUnknownToDb = true;
+const bool exportTextsToDb = false;
+const bool exportImagesToDb = false;
+const bool exportFontsToDb = false;
+const bool exportSoundsToDb = false;
+const bool exportTexturesToDb = false;
+const bool exportUnknownToDb = false;
 // There is no need to change anything else
 
 int main() {