TextSubfile.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. #include "../SubfileData.h"
  9. namespace LOTRO_DAT {
  10. TextSubfile::TextSubfile() = default;
  11. TextSubfile::TextSubfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1,
  12. long long file_id, long long file_offset, long long file_size,
  13. long long timestamp,
  14. long long version, long long block_size)
  15. : Subfile(dat, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
  16. }
  17. FILE_TYPE TextSubfile::FileType() const {
  18. return TEXT;
  19. }
  20. std::string TextSubfile::Extension() const {
  21. return std::string(".txt");
  22. }
  23. std::vector<SubfileData> TextSubfile::PrepareForExport(const BinaryData &file_data) {
  24. std::vector<SubfileData> result;
  25. if (file_size() <= 10) // File is empty, nothing to do;
  26. return result;
  27. long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
  28. long long text_fragment_num = file_data.ToNumber<1>(offset);
  29. if ((text_fragment_num & 0x80) != 0) {
  30. text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | file_data.ToNumber<1>(offset + 1));
  31. offset += 1;
  32. }
  33. offset += 1;
  34. for (long long i = 0; i < text_fragment_num; i++) {
  35. long long fragment_id = file_data.ToNumber<8>(offset);
  36. offset += 8;
  37. std::vector<std::u16string> text_pieces = MakePieces(file_data, offset);
  38. std::vector<long long> arg_references = MakeArgumentReferences(file_data, offset);
  39. std::vector<std::vector<BinaryData>> arg_strings = MakeArgumentStrings(file_data, offset);
  40. std::u16string text = u"[";
  41. for (size_t j = 0; j + 1 < text_pieces.size(); j++)
  42. text += text_pieces[j] + u"<--DO_NOT_TOUCH!-->";
  43. text += text_pieces[text_pieces.size() - 1] + u"]";
  44. std::string arguments;
  45. for (size_t j = 0; j + 1 < arg_references.size(); j++)
  46. arguments += std::to_string(arg_references[j]) + "-";
  47. if (!arg_references.empty())
  48. arguments += std::to_string(arg_references[arg_references.size() - 1]);
  49. SubfileData subfile;
  50. subfile.text_data = text;
  51. subfile.options["fid"] = file_id();
  52. subfile.options["gid"] = fragment_id;
  53. subfile.options["ext"] = Extension();
  54. if (!arg_references.empty())
  55. subfile.options["args"] = arguments;
  56. result.push_back(subfile);
  57. }
  58. return result;
  59. }
  60. BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
  61. BinaryData new_data;
  62. // Creating map for fast access to patch fragment by it's id
  63. std::unordered_map<long long, long long> fragment_vector_dictionary;
  64. std::cerr << "Fragments for " << file_id() << std::endl;
  65. for (int i = 0; i < FileFragments.size(); i++)
  66. fragment_vector_dictionary[FileFragments[i].options["gid"].as<long long>()] = i;
  67. for (auto i : fragment_vector_dictionary)
  68. std::cerr << i.first << " ";
  69. std::cerr << std::endl;
  70. if (file_size() <= 10 + 8) // File is empty, nothing to do;
  71. return old_data;
  72. long long offset = 9 + 8; // first 8 bytes - file_info. After them:
  73. // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
  74. long long text_fragment_num = old_data.ToNumber<1>(offset);
  75. if ((text_fragment_num & 0x80) != 0) {
  76. text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | old_data.ToNumber<1>(offset + 1));
  77. offset += 1;
  78. }
  79. offset += 1;
  80. new_data = new_data + old_data.CutData(0, offset); // Adding file info
  81. for (long long i = 0; i < text_fragment_num; i++) {
  82. long long fragment_id = old_data.ToNumber<8>(offset);
  83. offset += 8;
  84. new_data = new_data + old_data.CutData(offset - 8, offset);
  85. if (fragment_vector_dictionary.count(fragment_id) == 0) {
  86. std::cerr << "Omg, what..? " << file_id() << " " << fragment_id << " is not in patch? " << std::endl;
  87. new_data = new_data + GetPieceData(old_data, offset); // Retrieving old pieces
  88. new_data = new_data + GetArgumentReferenceData(old_data, offset); // Retrieving old references
  89. new_data = new_data + GetArgumentStringsData(old_data, offset); // Retrieving old ref_strings
  90. } else {
  91. SubfileData fragment_data = FileFragments[fragment_vector_dictionary[fragment_id]];
  92. new_data = new_data + BuildPieces(old_data, fragment_data, offset); // Making and adding new pieces
  93. new_data = new_data + BuildArgumentReferences(old_data, fragment_data, offset); // Making and adding new references
  94. new_data = new_data + BuildArgumentStrings(old_data, fragment_data, offset); // Making and adding new strings
  95. }
  96. }
  97. new_data = new_data + old_data.CutData(offset); // Adding elapsed file data
  98. return new_data;
  99. }
  100. std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
  101. long long num_pieces = data.ToNumber<4>(offset);
  102. offset += 4;
  103. std::vector<std::u16string> text_pieces;
  104. for (long long j = 0; j < num_pieces; j++) {
  105. long long piece_size = data.ToNumber<1>(offset);
  106. if ((piece_size & 128) != 0) {
  107. piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
  108. offset += 1;
  109. }
  110. offset += 1;
  111. BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
  112. std::u16string piece;
  113. for (long long k = 0; k < piece_size; k++) {
  114. char16_t c = char16_t(
  115. ((short(piece_data[2 * unsigned(k) + 1])) << 8) | (short(piece_data[2 * unsigned(k)])));
  116. piece += c;
  117. }
  118. text_pieces.push_back(piece);
  119. offset += piece_size * 2;
  120. }
  121. return text_pieces;
  122. }
  123. std::vector<long long> TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) {
  124. std::vector<long long> arg_references;
  125. long long num_references = data.ToNumber<4>(offset);
  126. offset += 4;
  127. for (long long j = 0; j < num_references; j++) {
  128. arg_references.emplace_back(data.ToNumber<4>(offset));
  129. offset += 4;
  130. }
  131. return arg_references;
  132. }
  133. std::vector<std::vector<BinaryData>> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) {
  134. std::vector<std::vector<BinaryData> > arg_strings;
  135. long long num_arg_strings = data.ToNumber<1>(offset);
  136. offset += 1;
  137. for (long long j = 0; j < num_arg_strings; j++) {
  138. long long num_args = data.ToNumber<4>(offset);
  139. offset += 4;
  140. arg_strings.emplace_back();
  141. for (long long k = 0; k < num_args; k++) {
  142. long long string_size = data.ToNumber<1>(offset);
  143. if ((string_size & 0x80) != 0) {
  144. string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
  145. offset += 1;
  146. }
  147. offset += 1;
  148. arg_strings[unsigned(j)].emplace_back(data.CutData(offset, offset + string_size * 2));
  149. offset += string_size * 2;
  150. }
  151. }
  152. return arg_strings;
  153. }
  154. BinaryData TextSubfile::BuildPieces(const BinaryData &data, const SubfileData &new_data, long long &offset) {
  155. // Moving &offset pointer in &data
  156. GetPieceData(data, offset);
  157. // Deleting '[' and ']' brackets
  158. std::u16string text_data = new_data.text_data.substr(1, new_data.text_data.size() - 2);
  159. std::vector<std::u16string> pieces;
  160. const std::u16string DNT = u"<--DO_NOT_TOUCH!-->";
  161. size_t prev = 0;
  162. size_t next = text_data.find(DNT, prev);
  163. while (next != std::string::npos) {
  164. std::u16string piece = text_data.substr(prev, next - prev);
  165. pieces.push_back(piece);
  166. prev = next + DNT.length();
  167. next = text_data.find(DNT, prev);
  168. }
  169. std::u16string piece = text_data.substr(prev);
  170. pieces.push_back(piece);
  171. // Building BinaryData from pieces
  172. BinaryData result;
  173. BinaryData temp_data(4);
  174. temp_data.FromNumber<4>(pieces.size());
  175. result = result + temp_data;
  176. for (long long i = 0; i < pieces.size(); i++) {
  177. long long piece_size = pieces[i].length();
  178. if (piece_size < 128) {
  179. temp_data.FromNumber<1>(piece_size);
  180. } else {
  181. temp_data.FromNumberRAW<2>((piece_size | 32768));
  182. }
  183. result = result + temp_data;
  184. for (long long j = 0; j < piece_size; j++) {
  185. temp_data.FromNumber<2>(short(pieces[i][j]));
  186. result = result + temp_data;
  187. }
  188. }
  189. return result;
  190. }
  191. BinaryData TextSubfile::BuildArgumentReferences(const BinaryData &data, const SubfileData &new_data,
  192. long long &offset) {
  193. // Moving &offset pointer in &data
  194. GetArgumentReferenceData(data, offset);
  195. // If there are no args - making 4 null-bytes and return;
  196. if (!new_data.options["args"]) {
  197. BinaryData result;
  198. result.FromNumber<4>(0);
  199. return result;
  200. }
  201. // Parsing arguments from list in options["args"]
  202. std::string args_list = new_data.options["args"].as<std::string>();
  203. std::vector<long long> arguments;
  204. size_t prev = 0;
  205. size_t next = args_list.find('-', prev);
  206. while (next != std::string::npos) {
  207. std::string argument = args_list.substr(prev, next - prev);
  208. arguments.push_back(std::stoll(argument));
  209. prev = next + 1;
  210. next = args_list.find('-', prev);
  211. }
  212. std::string argument = args_list.substr(prev);
  213. arguments.push_back(std::stoll(argument));
  214. BinaryData result;
  215. BinaryData temp_data(4);
  216. temp_data.FromNumber<4>(arguments.size());
  217. result = result + temp_data;
  218. for (auto arg_reference : arguments) {
  219. temp_data.FromNumber<4>(arg_reference);
  220. result = result + temp_data;
  221. }
  222. return result;
  223. }
  224. BinaryData TextSubfile::BuildArgumentStrings(const BinaryData &data, const SubfileData &new_data,
  225. long long &offset) {
  226. return GetArgumentStringsData(data, offset);
  227. }
  228. BinaryData TextSubfile::GetPieceData(const BinaryData &data, long long &offset) const {
  229. long long old_offset = offset;
  230. long long num_pieces = data.ToNumber<4>(offset);
  231. offset += 4;
  232. for (long long j = 0; j < num_pieces; j++) {
  233. long long piece_size = data.ToNumber<1>(offset);
  234. if ((piece_size & 128) != 0) {
  235. piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
  236. offset += 1;
  237. }
  238. offset += 1;
  239. offset += piece_size * 2;
  240. }
  241. return data.CutData(old_offset, offset);
  242. }
  243. BinaryData TextSubfile::GetArgumentReferenceData(const BinaryData &data, long long &offset) const {
  244. long long old_offset = offset;
  245. long long num_references = data.ToNumber<4>(offset);
  246. offset += 4;
  247. offset += 4 * num_references;
  248. return data.CutData(old_offset, offset);
  249. }
  250. BinaryData TextSubfile::GetArgumentStringsData(const BinaryData &data, long long &offset) const {
  251. long long old_offset = offset;
  252. long long num_arg_strings = data.ToNumber<1>(offset);
  253. offset += 1;
  254. for (long long j = 0; j < num_arg_strings; j++) {
  255. long long num_args = data.ToNumber<4>(offset);
  256. offset += 4;
  257. for (long long k = 0; k < num_args; k++) {
  258. long long string_size = data.ToNumber<1>(offset);
  259. if ((string_size & 0x80) != 0) {
  260. string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
  261. offset += 1;
  262. }
  263. offset += 1;
  264. offset += string_size * 2;
  265. }
  266. }
  267. return data.CutData(old_offset, offset);
  268. }
  269. };