|
@@ -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);
|
|
|
+ }
|
|
|
+
|
|
|
};
|