TextSubfile.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // Created by Иван_Архипов on 24.11.2017.
  3. //
  4. #include "TextSubfile.h"
  5. #include "../BinaryData.h"
  6. #include "../DatFile.h"
  7. #include "../Common/DatException.h"
  8. namespace LOTRO_DAT {
  9. TextSubfile::TextSubfile() = default;
  10. TextSubfile::TextSubfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1,
  11. long long file_id, long long file_offset, long long file_size,
  12. long long timestamp,
  13. long long version, long long block_size)
  14. : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
  15. }
  16. FILE_TYPE TextSubfile::FileType() const {
  17. return TEXT;
  18. }
  19. std::string TextSubfile::Extension() const {
  20. return std::string(".txt");
  21. }
  22. bool TextSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
  23. std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
  24. export_size = 0;
  25. binary_data.clear();
  26. text_data.clear();
  27. options.clear();
  28. if (file_size() <= 10) // File is empty, nothing to do;
  29. return false;
  30. long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
  31. long long text_fragment_num = file_data.ToNumber<1>(offset);
  32. if ((text_fragment_num & 0x80) != 0) {
  33. text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | file_data.ToNumber<1>(offset + 1));
  34. offset += 1;
  35. }
  36. offset += 1;
  37. for (long long i = 0; i < text_fragment_num; i++) {
  38. long long fragment_id = file_data.ToNumber<8>(offset);
  39. offset += 8;
  40. std::vector<std::u16string> text_pieces = MakePieces(file_data, offset);
  41. std::vector<long long> arg_references = MakeArgumentReferences(file_data, offset);
  42. std::vector<std::vector<BinaryData>> arg_strings = MakeArgumentStrings(file_data, offset);
  43. std::u16string text = u"[";
  44. for (size_t j = 0; j + 1 < text_pieces.size(); j++)
  45. text += text_pieces[j] + u"<--DO_NOT_TOUCH!-->";
  46. text += text_pieces[text_pieces.size() - 1] + u"]";
  47. std::string arguments;
  48. for (size_t j = 0; j + 1 < arg_references.size(); j++)
  49. arguments += std::to_string(arg_references[j]) + "-";
  50. if (!arg_references.empty())
  51. arguments += std::to_string(arg_references[arg_references.size() - 1]);
  52. binary_data.emplace_back(BinaryData());
  53. text_data.emplace_back(text);
  54. options.emplace_back(YAML::Node());
  55. options[unsigned(export_size)]["fid"] = file_id();
  56. options[unsigned(export_size)]["gid"] = fragment_id;
  57. options[unsigned(export_size)]["ext"] = Extension();
  58. if (!arg_references.empty())
  59. options[unsigned(export_size)]["args"] = arguments;
  60. ++export_size;
  61. }
  62. return true;
  63. }
  64. BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
  65. const YAML::Node &options) {
  66. return Subfile::MakeForImport(old_data, binary_data, text_data, options);
  67. }
  68. std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
  69. long long num_pieces = data.ToNumber<4>(offset);
  70. offset += 4;
  71. std::vector<std::u16string> text_pieces;
  72. for (long long j = 0; j < num_pieces; j++) {
  73. long long piece_size = data.ToNumber<1>(offset);
  74. if ((piece_size & 128) != 0) {
  75. piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
  76. offset += 1;
  77. }
  78. offset += 1;
  79. BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
  80. std::u16string piece;
  81. for (long long k = 0; k < piece_size; k++) {
  82. char16_t c = char16_t(
  83. ((short(piece_data[2 * unsigned(k) + 1])) << 8) | (short(piece_data[2 * unsigned(k)])));
  84. piece += c;
  85. }
  86. text_pieces.push_back(piece);
  87. offset += piece_size * 2;
  88. }
  89. return text_pieces;
  90. }
  91. std::vector<long long> TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) {
  92. std::vector<long long> arg_references;
  93. long long num_references = data.ToNumber<4>(offset);
  94. offset += 4;
  95. for (long long j = 0; j < num_references; j++) {
  96. arg_references.emplace_back(data.ToNumber<4>(offset));
  97. offset += 4;
  98. }
  99. return arg_references;
  100. }
  101. std::vector<std::vector<BinaryData>> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) {
  102. std::vector<std::vector<BinaryData> > arg_strings;
  103. long long num_arg_strings = data.ToNumber<1>(offset);
  104. offset += 1;
  105. for (long long j = 0; j < num_arg_strings; j++) {
  106. long long num_args = data.ToNumber<4>(offset);
  107. offset += 4;
  108. arg_strings.emplace_back();
  109. for (long long k = 0; k < num_args; k++) {
  110. long long string_size = data.ToNumber<1>(offset);
  111. if ((string_size & 0x80) != 0) {
  112. string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
  113. offset += 1;
  114. }
  115. offset += 1;
  116. arg_strings[unsigned(j)].emplace_back(data.CutData(offset, offset + string_size * 2));
  117. offset += string_size * 2;
  118. }
  119. }
  120. return arg_strings;
  121. }
  122. };