瀏覽代碼

Added functionality for patching text_file

Ivan Arkhipov 7 年之前
父節點
當前提交
b16afc99a3
共有 2 個文件被更改,包括 200 次插入1 次删除
  1. 188 1
      Source/Subfiles/TextSubfile.cpp
  2. 12 0
      Source/Subfiles/TextSubfile.h

+ 188 - 1
Source/Subfiles/TextSubfile.cpp

@@ -74,7 +74,54 @@ namespace LOTRO_DAT {
     }
 
     BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        return Subfile::MakeForImport(old_data, data);
+        BinaryData new_data;
+
+        // Creating map for fast access to patch fragment by it's id
+        std::unordered_map<long long, long long> fragment_vector_dictionary;
+
+        std::cerr << "Fragments for " << file_id() << std::endl;
+        for (int i = 0; i < FileFragments.size(); i++)
+            fragment_vector_dictionary[FileFragments[i].options["gid"].as<long long>()] = i;
+
+        for (auto i : fragment_vector_dictionary)
+            std::cerr << i.first << " ";
+        std::cerr << std::endl;
+
+        if (file_size() <= 10 + 8) // File is empty, nothing to do;
+            return old_data;
+
+        long long offset = 9 + 8; // first 8 bytes - file_info. After them:
+        // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+        long long text_fragment_num = old_data.ToNumber<1>(offset);
+        if ((text_fragment_num & 0x80) != 0) {
+            text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | old_data.ToNumber<1>(offset + 1));
+            offset += 1;
+        }
+        offset += 1;
+
+        new_data = new_data + old_data.CutData(0, offset); // Adding file info
+
+        for (long long i = 0; i < text_fragment_num; i++) {
+            long long fragment_id = old_data.ToNumber<8>(offset);
+            offset += 8;
+
+            new_data = new_data + old_data.CutData(offset - 8, offset);
+
+            if (fragment_vector_dictionary.count(fragment_id) == 0) {
+                std::cerr << "Omg, what..? " << file_id() << " " << fragment_id << " is not in patch? " << std::endl;
+                new_data = new_data + GetPieceData(old_data, offset); // Retrieving old pieces
+                new_data = new_data + GetArgumentReferenceData(old_data, offset); // Retrieving old references
+                new_data = new_data + GetArgumentStringsData(old_data, offset); // Retrieving old ref_strings
+            } else {
+                SubfileData fragment_data = FileFragments[fragment_vector_dictionary[fragment_id]];
+                new_data = new_data + BuildPieces(old_data, fragment_data, offset); // Making and adding new pieces
+                new_data = new_data + BuildArgumentReferences(old_data, fragment_data, offset); // Making and adding new references
+                new_data = new_data + BuildArgumentStrings(old_data, fragment_data, offset); // Making and adding new strings
+            }
+        }
+        new_data = new_data + old_data.CutData(offset); // Adding elapsed file data
+        return new_data;
     }
 
     std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
@@ -144,4 +191,144 @@ namespace LOTRO_DAT {
         }
         return arg_strings;
     }
+
+
+
+    BinaryData TextSubfile::BuildPieces(const BinaryData &data, const SubfileData &new_data, long long &offset) {
+        // Moving &offset pointer in &data
+        GetPieceData(data, offset);
+
+        // Deleting '[' and ']' brackets
+        std::u16string text_data = new_data.text_data.substr(1, new_data.text_data.size() - 2);
+        std::vector<std::u16string> pieces;
+
+        const std::u16string DNT = u"<--DO_NOT_TOUCH!-->";
+        size_t prev = 0;
+        size_t next = text_data.find(DNT, prev);
+
+        while (next != std::string::npos) {
+            std::u16string piece = text_data.substr(prev, next - prev);
+            pieces.push_back(piece);
+            prev = next + DNT.length();
+            next = text_data.find(DNT, prev);
+        }
+        std::u16string piece = text_data.substr(prev);
+        pieces.push_back(piece);
+
+        // Building BinaryData from pieces
+        BinaryData result;
+        BinaryData temp_data(4);
+
+        temp_data.FromNumber<4>(pieces.size());
+        result = result + temp_data;
+
+        for (long long i = 0; i < pieces.size(); i++) {
+            long long piece_size = pieces[i].length();
+            if (piece_size < 128) {
+                temp_data.FromNumber<1>(piece_size);
+            } else {
+                temp_data.FromNumberRAW<2>((piece_size | 32768));
+            }
+            result = result + temp_data;
+
+            for (long long j = 0; j < piece_size; j++) {
+                temp_data.FromNumber<2>(short(pieces[i][j]));
+                result = result + temp_data;
+            }
+        }
+        return result;
+    }
+
+    BinaryData TextSubfile::BuildArgumentReferences(const BinaryData &data, const SubfileData &new_data,
+                                                    long long &offset) {
+        // Moving &offset pointer in &data
+        GetArgumentReferenceData(data, offset);
+
+        // If there are no args - making 4 null-bytes and return;
+        if (!new_data.options["args"]) {
+            BinaryData result;
+            result.FromNumber<4>(0);
+            return result;
+        }
+
+        // Parsing arguments from list in options["args"]
+        std::string args_list = new_data.options["args"].as<std::string>();
+        std::vector<long long> arguments;
+
+        size_t prev = 0;
+        size_t next = args_list.find('-', prev);
+        while (next != std::string::npos) {
+            std::string argument = args_list.substr(prev, next - prev);
+            arguments.push_back(std::stoll(argument));
+            prev = next + 1;
+            next = args_list.find('-', prev);
+        }
+        std::string argument = args_list.substr(prev);
+        arguments.push_back(std::stoll(argument));
+
+        BinaryData result;
+        BinaryData temp_data(4);
+        temp_data.FromNumber<4>(arguments.size());
+        result = result + temp_data;
+        for (auto arg_reference : arguments) {
+            temp_data.FromNumber<4>(arg_reference);
+            result = result + temp_data;
+        }
+        return result;
+    }
+
+    BinaryData TextSubfile::BuildArgumentStrings(const BinaryData &data, const SubfileData &new_data,
+                                                 long long &offset) {
+        return GetArgumentStringsData(data, offset);
+    }
+
+    BinaryData TextSubfile::GetPieceData(const BinaryData &data, long long &offset) const {
+        long long old_offset = offset;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        for (long long j = 0; j < num_pieces; j++) {
+            long long piece_size = data.ToNumber<1>(offset);
+            if ((piece_size & 128) != 0) {
+                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
+                offset += 1;
+            }
+            offset += 1;
+            offset += piece_size * 2;
+        }
+        return data.CutData(old_offset, offset);
+    }
+
+    BinaryData TextSubfile::GetArgumentReferenceData(const BinaryData &data, long long &offset) const {
+        long long old_offset = offset;
+        long long num_references = data.ToNumber<4>(offset);
+        offset += 4;
+        offset += 4 * num_references;
+        return data.CutData(old_offset, offset);
+    }
+
+    BinaryData TextSubfile::GetArgumentStringsData(const BinaryData &data, long long &offset) const {
+        long long old_offset = offset;
+
+        long long num_arg_strings = data.ToNumber<1>(offset);
+        offset += 1;
+
+        for (long long j = 0; j < num_arg_strings; j++) {
+            long long num_args = data.ToNumber<4>(offset);
+            offset += 4;
+
+            for (long long k = 0; k < num_args; k++) {
+                long long string_size = data.ToNumber<1>(offset);
+                if ((string_size & 0x80) != 0) {
+                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+                    offset += 1;
+                }
+                offset += 1;
+                offset += string_size * 2;
+            }
+        }
+        return data.CutData(old_offset, offset);
+    }
+
 };

+ 12 - 0
Source/Subfiles/TextSubfile.h

@@ -31,6 +31,18 @@ namespace LOTRO_DAT {
         std::vector<long long> MakeArgumentReferences(const BinaryData &data, long long &offset);
 
         std::vector<std::vector<BinaryData>> MakeArgumentStrings(const BinaryData &data, long long &offset);
+
+        BinaryData BuildPieces(const BinaryData &data, const SubfileData &new_data, long long &offset);
+
+        BinaryData BuildArgumentReferences(const BinaryData &data, const SubfileData &new_data, long long &offset);
+
+        BinaryData BuildArgumentStrings(const BinaryData &data, const SubfileData &new_data, long long &offset);
+
+        BinaryData GetPieceData(const BinaryData &data, long long &offset) const;
+
+        BinaryData GetArgumentReferenceData(const BinaryData &data, long long &offset) const;
+
+        BinaryData GetArgumentStringsData(const BinaryData &data, long long &offset) const;
     };
 };