// // Created by Иван_Архипов on 24.11.2017. // #include "TextSubfile.h" #include "../BinaryData.h" #include "../DatFile.h" #include "../Common/DatException.h" namespace LOTRO_DAT { TextSubfile::TextSubfile() = default; TextSubfile::TextSubfile(DatFile *dat, 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, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) { } FILE_TYPE TextSubfile::FileType() const { return TEXT; } bool TextSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector &binary_data, std::vector &text_data, std::vector &options) { export_size = 0; binary_data.clear(); text_data.clear(); options.clear(); if (file_size() <= 10) // File is empty, nothing to do; return false; long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown long long text_fragment_num = file_data.ToNumber<1>(offset); if ((text_fragment_num & 0x80) != 0) { text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | file_data.ToNumber<1>(offset + 1)); offset += 1; } offset += 1; for (long long i = 0; i < text_fragment_num; i++) { long long fragment_id = file_data.ToNumber<8>(offset); offset += 8; std::vector text_pieces = MakePieces(file_data, offset); std::vector arg_references = MakeArgumentReferences(file_data, offset); std::vector> arg_strings = MakeArgumentStrings(file_data, offset); std::u16string text = u"["; for (int j = 0; j + 1 < text_pieces.size(); j++) text += text_pieces[j] + u"<--DO_NOT_TOUCH!-->"; text += text_pieces[text_pieces.size() - 1] + u"]"; std::string arguments; for (int j = 0; j + 1 < arg_references.size(); j++) arguments += std::to_string(arg_references[j]) + "-"; 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()); options[export_size]["file_id"] = file_id(); options[export_size]["gossip_id"] = fragment_id; options[export_size]["extension"] = Extension(); options[export_size]["arguments"] = arguments; ++export_size; } return true; } 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); } std::vector TextSubfile::MakePieces(const BinaryData &data, long long &offset) { long long num_pieces = data.ToNumber<4>(offset); offset += 4; std::vector text_pieces; 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; BinaryData piece_data = data.CutData(offset, offset + piece_size * 2); std::u16string piece; for (long long k = 0; k < piece_size; k++) { char16_t c = char16_t(((short(piece_data[2 * k + 1])) << 8) | (short(piece_data[2 * k]))); piece += c; } text_pieces.push_back(piece); offset += piece_size * 2; } return text_pieces; } std::vector TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) { std::vector arg_references; long long num_references = data.ToNumber<4>(offset); offset += 4; for (long long j = 0; j < num_references; j++) { arg_references.emplace_back(data.ToNumber<4>(offset)); offset += 4; } return arg_references; } std::vector> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) { std::vector > arg_strings; 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; arg_strings.emplace_back(); 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; arg_strings[j].emplace_back(data.CutData(offset, offset + string_size * 2)); offset += string_size * 2; } } return arg_strings; } };