瀏覽代碼

Added structure SubfileData, refactored code

Structure SubfileData contains Subfile data information in format, used
in database and patch applying.
Ivan Arkhipov 6 年之前
父節點
當前提交
e484a35b08

+ 1 - 1
CMakeLists.txt

@@ -63,7 +63,7 @@ set(SOURCE_FILES
 
         ${CMAKE_SOURCE_DIR}/Subfiles/UnknownSubfile.cpp
         ${CMAKE_SOURCE_DIR}/Subfiles/UnknownSubfile.h
-        )
+        Source/SubfileData.h)
 
 set(CompilerFlags
         CMAKE_CXX_FLAGS

+ 19 - 26
Source/DatFile.cpp

@@ -8,6 +8,7 @@
 #include "Common/DatException.h"
 #include "SubDirectory.h"
 #include "Subfile.h"
+#include "SubfileData.h"
 
 #include <locale>
 
@@ -86,13 +87,10 @@ namespace LOTRO_DAT {
             return false;
         }
 
-        long long export_size = 0;
-        std::vector<BinaryData> binary_data;
-        std::vector<std::u16string> text_data;
-        std::vector<YAML::Node> options;
+        std::vector<SubfileData> export_data;
 
         try {
-            dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
+            export_data = dictionary_[file_id]->PrepareForExport(file_data);
         } catch (std::exception &e) {
             fprintf(stderr, "Caught %s exception.", e.what());
 
@@ -100,8 +98,8 @@ namespace LOTRO_DAT {
             return false;
         }
 
-        for (int i = 0; i < export_size; ++i) {
-            binary_data[i].WriteToFile(path + "_" + std::to_string(i) + options[i]["ext"].as<std::string>());
+        for (int i = 0; i < export_data.size(); ++i) {
+            export_data[i].binary_data.WriteToFile(path + "_" + std::to_string(i) + export_data[i].options["ext"].as<std::string>());
         }
         return true;
     }
@@ -129,13 +127,10 @@ namespace LOTRO_DAT {
             return false;
         }
 
-        long long export_size = 0;
-        std::vector<BinaryData> binary_data;
-        std::vector<std::u16string> text_data;
-        std::vector<YAML::Node> options;
+        std::vector<SubfileData> export_data;
 
         try {
-            dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
+            export_data = dictionary_[file_id]->PrepareForExport(file_data);
         } catch (std::exception &e) {
             fprintf(stderr, "Caught %s exception.", e.what());
 
@@ -143,11 +138,9 @@ namespace LOTRO_DAT {
             return false;
         }
 
-        for (int i = 0; i < export_size; ++i) {
-            std::stringstream option;
-            option << options[i];
+        for (int i = 0; i < export_data.size(); ++i) {
             try {
-                db->PushFile(binary_data[i], text_data[i], option.str());
+                db->PushFile(export_data[i]);
             } catch (std::exception &e) {
                 fprintf(stderr, "Caught %s exception.", e.what());
                 printf("Caught %s exception.", e.what());
@@ -202,8 +195,8 @@ namespace LOTRO_DAT {
     }
 
     /// TODO: Write description and make asserts
-    bool DatFile::PatchFile(const char *filename, YAML::Node options, long long dat_id) {
-        if (dat_id != dat_id_)
+    bool DatFile::PatchFile(const char *filename, YAML::Node options) {
+        if (options["did"].IsDefined() && options["did"].as<int>() != dat_id_)
             return false;
 
         BinaryData data;
@@ -211,7 +204,7 @@ namespace LOTRO_DAT {
 
         auto file_id = options["fid"].as<long long>();
         BinaryData old_data = GetFileData(dictionary_[file_id]);
-        data = dictionary_[file_id]->MakeForImport(old_data, data, u"", options);
+        data = dictionary_[file_id]->MakeForImport(old_data, SubfileData(data, u"", options));
 
         try {
             ApplyFilePatch(dictionary_[file_id], data);
@@ -229,18 +222,18 @@ namespace LOTRO_DAT {
         return true;
     }
 
-    /// TODO: Write description and make asserts
-    bool DatFile::PatchFile(const BinaryData &binary_data, const std::u16string &text_data, YAML::Node &options) {
-        auto file_id = options["fid"].as<long long>();
+    // TODO: Write description and make asserts
+    bool DatFile::PatchFile(const SubfileData &data) {
+        auto file_id = data.options["fid"].as<long long>();
         Subfile *file = dictionary_[file_id];
         BinaryData old_data = GetFileData(file);
-        BinaryData data = file->MakeForImport(old_data, binary_data, text_data, options);
-        ApplyFilePatch(file, data);
+        BinaryData patch_data = file->MakeForImport(old_data, data);
+        ApplyFilePatch(file, patch_data);
         return true;
     }
 
-    /// TODO: Write description and make asserts
-    bool DatFile::PatchDatabase(Database *db) {
+    // TODO: Write description and make asserts and IMPLEMENT
+    bool DatFile::PatchAllDatabase(Database *db) {
         return false;
     }
 

+ 9 - 9
Source/DatFile.h

@@ -35,6 +35,7 @@ namespace LOTRO_DAT
     class DatException;
     class SubDirectory;
     class Subfile;
+    class SubfileData;
 
     enum FILE_TYPE : int{
         TEXT,
@@ -55,8 +56,7 @@ namespace LOTRO_DAT
         READY
     };
 
-    class DatFile
-    {
+    class DatFile {
         friend class SubDirectory;
     public:
         DatFile();
@@ -69,9 +69,9 @@ namespace LOTRO_DAT
         int ExtractAllFilesByType(FILE_TYPE type, std::string path = "");
         int ExtractAllFilesByType(FILE_TYPE type, Database *db);
 
-        bool PatchFile(const char *filename, YAML::Node options, long long dat_id);
-        bool PatchFile(const BinaryData &binary_data, const std::u16string &text_data, YAML::Node &options);
-        bool PatchDatabase(Database *db);
+        bool PatchFile(const char *filename, YAML::Node options);
+        bool PatchFile(const SubfileData &data);
+        bool PatchAllDatabase(Database *db);
 
         void WriteUnorderedDictionary(std::string path) const;
 
@@ -88,10 +88,6 @@ namespace LOTRO_DAT
         void UpdateSubdirectories();
 
     private:
-        FILE *file_handler_;
-        SubDirectory *root_directory_;
-        std::unordered_map<long long, Subfile*> dictionary_;
-
         void OpenDatFile(const char* dat_name);
         void ReadSuperBlock();
         void MakeDirectories();
@@ -105,6 +101,10 @@ namespace LOTRO_DAT
         void UpdateHeader();
         void UpdateFragmentationJournal(const std::vector<std::pair<long long, long long> > &journal);
 
+    private:
+        FILE *file_handler_;
+        SubDirectory *root_directory_;
+        std::unordered_map<long long, Subfile*> dictionary_;
         std::unordered_map<long long, BinaryData *> patched_list;
 
         long long constant1_;

+ 16 - 10
Source/Database.cpp

@@ -8,8 +8,10 @@
 #include "Common/DatException.h"
 #include "BinaryData.h"
 #include "Common/CommonFunctions.h"
+#include "SubfileData.h"
 
 #include <cstring>
+#include <sstream>
 
 namespace LOTRO_DAT {
     Database::Database() {
@@ -62,13 +64,16 @@ namespace LOTRO_DAT {
 		}
 	}
 
-    void Database::PushFile(const BinaryData &binary_data, const std::u16string &text_data, const std::string &options) {
+    void Database::PushFile(const SubfileData &data) {
         if (db_ == nullptr)
             throw DatException("Bad Database::PushFile() - database hasn't been opened!", DATABASE_EXCEPTION);
 
-        sqlite3_bind_blob(insert_request_, 1, binary_data.data(), binary_data.size(), SQLITE_TRANSIENT);
-        sqlite3_bind_text16(insert_request_, 2, text_data.c_str(), -1, SQLITE_TRANSIENT);
-        sqlite3_bind_text(insert_request_, 3, options.c_str(), -1, SQLITE_TRANSIENT);
+        std::stringstream options_;
+        options_ << data.options;
+
+        sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
+        sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
+        sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT);
 
         if (sqlite3_step(insert_request_) != SQLITE_DONE) {
             fprintf(stderr, "SQLite3 error: %s\n", sqlite3_errmsg(db_));
@@ -79,26 +84,27 @@ namespace LOTRO_DAT {
         sqlite3_reset(insert_request_);
     }
 
-    bool Database::GetNextFile(BinaryData &binary_data, std::u16string &text_data, YAML::Node &options) {
+    SubfileData Database::GetNextFile() {
+        SubfileData data;
         if (db_ == nullptr)
             throw DatException("Bad Database::GetNexFile() - database hasn't been opened!", DATABASE_EXCEPTION);
 
         int result = sqlite3_step(fetch_one_request_);
 
         if (result == SQLITE_ROW) {
-            binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
+            data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
                                      unsigned(sqlite3_column_bytes(fetch_one_request_, 0)));
 
-            text_data = std::u16string((char16_t *)sqlite3_column_text16(fetch_one_request_, 1));
+            data.text_data = std::u16string((char16_t *)sqlite3_column_text16(fetch_one_request_, 1));
 
             std::string _options = std::string((char *)sqlite3_column_text(fetch_one_request_, 2),
                                                unsigned(sqlite3_column_bytes(fetch_one_request_, 2)));
-            options = YAML::Load(_options);
-            return true;
+            data.options = YAML::Load(_options);
+            return data;
         }
 
         if (result == SQLITE_DONE) {
-            return false;
+            return data;
         }
 
         fprintf(stderr, "SQLite3 fetch_one request returned %d code. SQLite message is: %s", result, sqlite3_errmsg(db_));

+ 3 - 2
Source/Database.h

@@ -14,6 +14,7 @@ extern  "C++"
 namespace LOTRO_DAT
 {
     class BinaryData;
+    class SubfileData;
 
     class Database {
     public:
@@ -25,9 +26,9 @@ namespace LOTRO_DAT
 
         void InitDatabase(const std::string &filename);
 
-        void PushFile(const BinaryData &binary_data, const std::u16string &text_data, const std::string &options);
+        void PushFile(const SubfileData &data);
 
-        bool GetNextFile(BinaryData &binary_data, std::u16string &text_data, YAML::Node &options);
+        SubfileData GetNextFile();
 
         void RemoveDatabase();
 

+ 2 - 1
Source/LotroDatPatcher.h

@@ -4,6 +4,7 @@
 
 #include "DatFile.h"
 #include "Database.h"
-#include "BinaryData.h"
+#include "SubfileData.h"
+
 #include <yaml-cpp/yaml.h>
 #include "Common\ZLib\zlib.h"

+ 2 - 4
Source/Subfile.cpp

@@ -94,8 +94,7 @@ namespace LOTRO_DAT {
     ///  3) field options - YAML field, which consists of some parameters of file such as file_id, extension and so on.
     /// Returns true if preparation was success. Otherwise returns false;
 
-    bool Subfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                        std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+    std::vector<SubfileData> Subfile::PrepareForExport(const BinaryData &file_data) {
         throw DatException("Bad Subfile::PrepareForExport() - function is not implemented for this type.", EXPORT_EXCEPTION);
     }
 
@@ -108,8 +107,7 @@ namespace LOTRO_DAT {
     ///  3) const field options - YAML field, which consists of some parameters of file such as file_id, extension and so on.
     /// Returns BinaryData - bytes array, prepared for writing in .dat file
 
-    BinaryData Subfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                           const YAML::Node &options) {
+    BinaryData Subfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
         throw DatException("Bad Subfile::MakeForImport() - function is not implemented for this type.", IMPORT_EXCEPTION);
     }
 

+ 7 - 7
Source/Subfile.h

@@ -16,6 +16,8 @@ namespace LOTRO_DAT
     class DatFile;
 	class BinaryData;
     class Database;
+    class SubfileData;
+
     enum FILE_TYPE : int;
 
     class Subfile
@@ -23,18 +25,16 @@ namespace LOTRO_DAT
         friend class DatFile;
     public:
         Subfile();
-        Subfile(DatFile *dat, long long dictionary_offset, 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);
-		virtual ~Subfile() {};
+        Subfile(DatFile *dat, long long dictionary_offset, 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);
 
         virtual FILE_TYPE FileType() const;
         virtual std::string Extension() const;
 
-        virtual bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                             std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options);
+        virtual std::vector<SubfileData> PrepareForExport(const BinaryData &file_data);
 
-        virtual BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                const std::u16string &text_data, const YAML::Node &options);
+        virtual BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data);
 
 		BinaryData MakeHeaderData() const;
 

+ 42 - 0
Source/SubfileData.h

@@ -0,0 +1,42 @@
+//
+// Created by Иван_Архипов on 06.12.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_SUBFILEDATA_H
+#define LOTRO_DAT_LIBRARY_SUBFILEDATA_H
+
+#include <string>
+#include <yaml-cpp/yaml.h>
+#include "BinaryData.h"
+
+namespace LOTRO_DAT {
+    struct SubfileData {
+    public:
+        SubfileData() {
+            binary_data = BinaryData();
+            text_data = std::u16string();
+            options = YAML::Node();
+        }
+
+        SubfileData(const BinaryData &binary_data_, const std::u16string &text_data_, const YAML::Node options_) {
+            binary_data = binary_data_;
+            text_data = text_data_;
+            options = options_;
+        }
+
+        bool operator == (const SubfileData &other) {
+            return binary_data == other.binary_data && text_data == other.text_data;
+        }
+
+        bool operator != (const SubfileData &other) {
+            return !(*this == other);
+        }
+
+    public:
+        BinaryData binary_data;
+        std::u16string text_data;
+        YAML::Node options;
+    };
+}
+
+#endif //LOTRO_DAT_LIBRARY_SUBFILEDATA_H

+ 19 - 22
Source/Subfiles/DdsSubfile.cpp

@@ -7,16 +7,16 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
-    DdsSubfile::DdsSubfile() {}
+    DdsSubfile::DdsSubfile() = default;
 
     DdsSubfile::DdsSubfile(DatFile *dat, long long dictionary_offset, 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)
-            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
-
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp, long long version, long long block_size)
+            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size,
+                      timestamp, version, block_size) {
     }
 
     FILE_TYPE DdsSubfile::FileType() const {
@@ -27,8 +27,7 @@ namespace LOTRO_DAT {
         return ".dds";
     }
 
-    bool DdsSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+    std::vector<SubfileData> DdsSubfile::PrepareForExport(const BinaryData &file_data) {
         BinaryData data = file_data;
         if (data.CheckCompression())
             data = data.DecompressData(4);
@@ -136,26 +135,24 @@ namespace LOTRO_DAT {
                 throw DatException("Bad DdsSubfile::PrepareAsBinary() - unknown header format.", EXPORT_EXCEPTION);
         }
 
-        export_size = 1;
-        binary_data.emplace_back(ddsData);
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+        std::vector<SubfileData> output(1);
+        output[0].binary_data = (ddsData);
+        output[0].text_data = (u"");
+        output[0].options["fid"] = file_id();
+        output[0].options["ext"] = Extension();
+        return output;
     }
 
-    BinaryData DdsSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                              const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData DdsSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.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.DecompressData(12).CutData(12, 16) + binary_data.CutData(128)).CompressData();
+            return old_data.CutData(0, 4) +
+                   (old_data.DecompressData(12).CutData(12, 16) + data.binary_data.CutData(128)).CompressData();
         else
-            return old_data.CutData(0, 16) + binary_data.CutData(128);
+            return old_data.CutData(0, 8) + data.binary_data.CutData(128);
     }
 };

+ 6 - 8
Source/Subfiles/DdsSubfile.h

@@ -11,20 +11,18 @@ namespace LOTRO_DAT {
     class DdsSubfile : public Subfile {
     public:
         DdsSubfile();
+
         DdsSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~DdsSubfile() override {};
+                   long long file_id, long long file_offset, long long file_size, long long timestamp,
+                   long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
+
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
     };
 };
 

+ 17 - 19
Source/Subfiles/FontSubfile.cpp

@@ -6,15 +6,16 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
-    FontSubfile::FontSubfile() {}
+    FontSubfile::FontSubfile() = default;
 
     FontSubfile::FontSubfile(DatFile *dat, long long dictionary_offset, 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)
-            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+                             long long file_id, long long file_offset, long long file_size, long long timestamp,
+                             long long version, long long block_size)
+            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp,
+                      version, block_size) {
     }
 
     FILE_TYPE FontSubfile::FileType() const {
@@ -25,23 +26,20 @@ namespace LOTRO_DAT {
         return ".fontbin";
     }
 
-    bool FontSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                       std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 1;
-        binary_data.emplace_back(file_data);
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+    std::vector<SubfileData> FontSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> output(1);
+        output[0].binary_data = file_data;
+        output[0].text_data = u"";
+        output[0].options["fid"] = file_id();
+        output[0].options["ext"] = Extension();
+        return output;
     }
 
-    BinaryData FontSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                               const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData FontSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-        return old_data.CutData(0, 16) + binary_data;
+        return old_data.CutData(0, 8) + data.binary_data;
     }
 };

+ 6 - 7
Source/Subfiles/FontSubfile.h

@@ -12,18 +12,17 @@ namespace LOTRO_DAT {
     class FontSubfile : public Subfile {
     public:
         FontSubfile();
-        FontSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~FontSubfile() override {};
+        FontSubfile(DatFile *dat, long long dictionary_offset, 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);
 
         FILE_TYPE FileType() const override;
+
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                         const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
 
     };
 };

+ 16 - 18
Source/Subfiles/JpgSubfile.cpp

@@ -6,15 +6,16 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
     JpgSubfile::JpgSubfile() = default;
 
     JpgSubfile::JpgSubfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1,
-                             long long file_id, long long file_offset, long long file_size,
-                             long long timestamp,
+                             long long file_id, long long file_offset, long long file_size, long long timestamp,
                              long long version, long long block_size)
-            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp,
+                      version, block_size) {
     }
 
     FILE_TYPE JpgSubfile::FileType() const {
@@ -25,25 +26,22 @@ namespace LOTRO_DAT {
         return std::string(".jpg");
     }
 
-    bool JpgSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 1;
-        binary_data.emplace_back(file_data.CutData(24));
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+    std::vector<SubfileData> JpgSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> output(1);
+        output[0].binary_data = file_data.CutData(24);
+        output[0].text_data = u"";
+        output[0].options["fid"] = file_id();
+        output[0].options["ext"] = Extension();
+        return output;
     }
 
-    BinaryData JpgSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                              const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData JpgSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
         BinaryData file_size;
-        file_size.FromNumber<4>(binary_data.size());
-        return old_data.CutData(0, 28) + file_size + binary_data;
+        file_size.FromNumber<4>(data.binary_data.size());
+        return old_data.CutData(0, 28) + file_size + data.binary_data;
     }
 };

+ 8 - 7
Source/Subfiles/JpgSubfile.h

@@ -12,18 +12,19 @@ namespace LOTRO_DAT {
     class JpgSubfile : public Subfile {
     public:
         JpgSubfile();
-        JpgSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~JpgSubfile() override {};
+
+        JpgSubfile(DatFile *dat, long long dictionary_offset, 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);
+
 
         FILE_TYPE FileType() const override;
+
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
     };
 };
 

+ 12 - 15
Source/Subfiles/OggSubfile.cpp

@@ -6,9 +6,10 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
-    OggSubfile::OggSubfile() {}
+    OggSubfile::OggSubfile() = default;
 
     OggSubfile::OggSubfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1,
                            long long file_id, long long file_offset, long long file_size,
@@ -25,23 +26,19 @@ namespace LOTRO_DAT {
         return ".ogg";
     }
 
-    bool OggSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 1;
-        binary_data.emplace_back(file_data.CutData(8));
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+    std::vector<SubfileData> OggSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> output(1);
+        output[0].binary_data = file_data.CutData(8);
+        output[0].options["fid"] = file_id();
+        output[0].options["ext"] = Extension();
+        return output;
     }
 
-    BinaryData OggSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                              const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData OggSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-        return old_data.CutData(0, 24) + binary_data;
+        return old_data.CutData(0, 24) + data.binary_data;
     }
 };

+ 6 - 7
Source/Subfiles/OggSubfile.h

@@ -11,18 +11,17 @@ namespace LOTRO_DAT {
     class OggSubfile : public Subfile {
     public:
         OggSubfile();
-        OggSubfile(DatFile *dat, long long dictionary_offset,  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);
-        ~OggSubfile() override {};
+
+        OggSubfile(DatFile *dat, long long dictionary_offset,  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);
 
         FILE_TYPE FileType() const override;
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
     };
 };
 

+ 14 - 20
Source/Subfiles/TextSubfile.cpp

@@ -6,6 +6,7 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
     TextSubfile::TextSubfile() = default;
@@ -25,15 +26,10 @@ namespace LOTRO_DAT {
         return std::string(".txt");
     }
 
-    bool TextSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                       std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 0;
-        binary_data.clear();
-        text_data.clear();
-        options.clear();
-
+    std::vector<SubfileData> TextSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> result;
         if (file_size() <= 10) // File is empty, nothing to do;
-            return false;
+            return result;
 
         long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
 
@@ -63,24 +59,22 @@ namespace LOTRO_DAT {
             if (!arg_references.empty())
                 arguments += std::to_string(arg_references[arg_references.size() - 1]);
 
-            binary_data.emplace_back(BinaryData());
-            text_data.emplace_back(text);
-            options.emplace_back(YAML::Node());
+            SubfileData subfile;
 
-            options[unsigned(export_size)]["fid"] = file_id();
-            options[unsigned(export_size)]["gid"] = fragment_id;
-            options[unsigned(export_size)]["ext"] = Extension();
+            subfile.text_data = text;
+            subfile.options["fid"] = file_id();
+            subfile.options["gid"] = fragment_id;
+            subfile.options["ext"] = Extension();
             if (!arg_references.empty())
-                options[unsigned(export_size)]["args"] = arguments;
+                subfile.options["args"] = arguments;
 
-            ++export_size;
+            result.push_back(subfile);
         }
-        return true;
+        return result;
     }
 
-    BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                               const YAML::Node &options) {
-        return Subfile::MakeForImport(old_data, binary_data, text_data, options);
+    BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        return Subfile::MakeForImport(old_data, data);
     }
 
     std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {

+ 7 - 8
Source/Subfiles/TextSubfile.h

@@ -13,19 +13,18 @@ namespace LOTRO_DAT {
     public:
         TextSubfile();
 
-        TextSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~TextSubfile() override {};
+        TextSubfile(DatFile *dat, long long dictionary_offset, 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);
 
         FILE_TYPE FileType() const override;
+
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
+
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
     private:
         std::vector<std::u16string> MakePieces(const BinaryData &data, long long &offset);
 

+ 16 - 19
Source/Subfiles/UnknownSubfile.cpp

@@ -6,15 +6,16 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
-    UnknownSubfile::UnknownSubfile() {}
+    UnknownSubfile::UnknownSubfile() = default;
 
     UnknownSubfile::UnknownSubfile(DatFile *dat, long long dictionary_offset, 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)
-            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+                                   long long file_id, long long file_offset, long long file_size, long long timestamp,
+                                   long long version, long long block_size)
+            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp,
+                      version, block_size) {
     }
 
     FILE_TYPE UnknownSubfile::FileType() const {
@@ -25,23 +26,19 @@ namespace LOTRO_DAT {
         return std::string(".unknown");
     }
 
-    bool UnknownSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                          std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 1;
-        binary_data.emplace_back(file_data);
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+    std::vector<SubfileData> UnknownSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> result(1);
+        result[0].binary_data = file_data;
+        result[0].options["fid"] = file_id();
+        result[0].options["ext"] = Extension();
+        return result;
     }
 
-    BinaryData UnknownSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                             const std::u16string &text_data, const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData UnknownSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-        return old_data.CutData(0, 16) + binary_data;
+        return old_data.CutData(0, 16) + data.binary_data;
     }
 };

+ 6 - 7
Source/Subfiles/UnknownSubfile.h

@@ -11,18 +11,17 @@ namespace LOTRO_DAT {
     class UnknownSubfile : public Subfile {
     public:
         UnknownSubfile();
-        UnknownSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~UnknownSubfile() override {};
+
+        UnknownSubfile(DatFile *dat, long long dictionary_offset, 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);
 
         FILE_TYPE FileType() const override;
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
 
     };
 };

+ 14 - 17
Source/Subfiles/WavSubfile.cpp

@@ -6,15 +6,16 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
+#include "../SubfileData.h"
 
 namespace LOTRO_DAT {
     WavSubfile::WavSubfile() = default;
 
     WavSubfile::WavSubfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1,
-                           long long file_id, long long file_offset, long long file_size,
-                           long long timestamp,
+                           long long file_id, long long file_offset, long long file_size, long long timestamp,
                            long long version, long long block_size)
-            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+            : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp,
+                      version, block_size) {
     }
 
     FILE_TYPE WavSubfile::FileType() const {
@@ -25,23 +26,19 @@ namespace LOTRO_DAT {
         return ".wav";
     }
 
-    bool WavSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
-        export_size = 1;
-        binary_data.emplace_back(file_data.CutData(8));
-        text_data.emplace_back(u"");
-        options.emplace_back(YAML::Node());
-        options[0]["fid"] = file_id();
-        options[0]["ext"] = Extension();
-        return true;
+    std::vector<SubfileData> WavSubfile::PrepareForExport(const BinaryData &file_data) {
+        std::vector<SubfileData> result(1);
+        result[0].binary_data = file_data.CutData(8);
+        result[0].options["fid"] = file_id();
+        result[0].options["ext"] = Extension();
+        return result;
     }
 
-    BinaryData WavSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
-                              const YAML::Node &options) {
-        if (!options["ext"] || options["ext"].as<std::string>() != Extension() ||
-            !options["fid"] || options["fid"].as<long long>() != file_id()) {
+    BinaryData WavSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
+            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-        return old_data.CutData(0, 24) + binary_data;
+        return old_data.CutData(0, 24) + data.binary_data;
     }
 };

+ 8 - 7
Source/Subfiles/WavSubfile.h

@@ -11,18 +11,19 @@ namespace LOTRO_DAT {
     class WavSubfile : public Subfile {
     public:
         WavSubfile();
-        WavSubfile(DatFile *dat, long long dictionary_offset, 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);
-        ~WavSubfile() override {};
+
+        WavSubfile(DatFile *dat, long long dictionary_offset, 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);
+
 
         FILE_TYPE FileType() const override;
+
         std::string Extension() const override;
 
-        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
-                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+        std::vector<SubfileData> PrepareForExport(const BinaryData &file_data) override;
 
-        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
-                                 const std::u16string &text_data, const YAML::Node &options) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const SubfileData &data) override;
 
     };
 };

+ 4 - 7
Source/Tests/patch_test.cpp

@@ -30,10 +30,6 @@ int main() {
     Database db;
     db.InitDatabase("images.db");
 
-    BinaryData binary_data;
-    std::u16string text_data;
-    YAML::Node options;
-
     DatFile *a;
 
     try {
@@ -42,13 +38,14 @@ int main() {
         std::cout << "Files number: " << a->files_number() << std::endl;
         a->WriteUnorderedDictionary("");
 
-       while (db.GetNextFile(binary_data, text_data, options)) {
+        SubfileData data = db.GetNextFile();
+        while (data != SubfileData()) {
 
             //binary_data.ReadFromFile("1090552107.jpg");
             //options["fid"] = "1090552107";
             //options["ext"] = ".jpg";
-
-            a->PatchFile(binary_data, text_data, options);
+            a->PatchFile(data);
+            data = db.GetNextFile();
             //delete a;
         }
     } catch (std::exception &e) {