DatFile.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. //
  2. // Created by Иван_Архипов on 31.10.2017.
  3. //
  4. #include "DatFile.h"
  5. #include "BinaryData.h"
  6. #include "Common/DatException.h"
  7. #include "SubDirectory.h"
  8. #include "Subfile.h"
  9. #include <locale>
  10. extern "C++"
  11. {
  12. namespace LOTRO_DAT {
  13. DatFile::DatFile() {
  14. dat_state_ = CLOSED;
  15. }
  16. DatFile::DatFile(const char *filename, int dat_id) {
  17. dat_id_ = dat_id;
  18. dat_state_ = CLOSED;
  19. printf("state1\n");
  20. OpenDatFile(filename);
  21. printf("state2\n");
  22. ReadSuperBlock();
  23. printf("state3\n");
  24. MakeDirectories();
  25. printf("end\n");
  26. try {
  27. MakeDictionary();
  28. } catch (...) {
  29. fprintf(stderr, "Unable to make dictionary!! Unable to init DatFile!!!");
  30. return;
  31. }
  32. if (dat_state_ == SUCCESS_DICTIONARY)
  33. dat_state_ = READY;
  34. else
  35. throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
  36. INIT_EXCEPTION);
  37. }
  38. DatFile::~DatFile() {
  39. if (file_handler_ != nullptr)
  40. fclose(file_handler_);
  41. delete file_handler_;
  42. delete root_directory_;
  43. }
  44. /// Extracts file with file_id.
  45. /// If path is undefined then it will be recognised as current working directory
  46. /// Output file path consists of "path + file_id + file_extension";
  47. /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
  48. /// Otherwise DatException() will be thrown.
  49. /// Returns true, if file was successfully extracted;
  50. /// Throws DatException() if undefined behaviour happened
  51. bool DatFile::ExtractFile(long long file_id, const std::string path) {
  52. if (dat_state_ != READY) {
  53. throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
  54. }
  55. return dictionary_[file_id]->ExportFile(path.c_str());
  56. }
  57. /// Extracts file with file_id to database "db".
  58. /// DATABASE SHOULD BE ALREADY CREATED; Otherwise DatException will be called.
  59. /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
  60. /// Otherwise DatException() will be thrown.
  61. /// Returns true, if file was successfully extracted;
  62. /// Throws DatException() if undefined behaviour happened
  63. bool DatFile::ExtractFile(long long file_id, Database *db) {
  64. if (dat_state_ != READY) {
  65. throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
  66. }
  67. return dictionary_[file_id]->ExportFile(db);
  68. }
  69. /// Extracts all files with specific type to "path + type + file_id + extension" files;
  70. /// If path is undefined then it will be recognised as current working directory
  71. /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
  72. /// Otherwise DatException() will be thrown.
  73. /// Returns number of successfully extracted files
  74. /// Throws DatException() if undefined behaviour happened
  75. int DatFile::ExtractAllFilesByType(FILE_TYPE type, std::string path) {
  76. if (dat_state_ != READY) {
  77. throw DatException("Bad DatFile::ExtractAllFilesByType() - invalid DatFile state!", EXPORT_EXCEPTION);
  78. }
  79. int success = 0;
  80. for (auto i : dictionary_) {
  81. FILE_TYPE ext = i.second->ext();
  82. if (ext == type) {
  83. success += i.second->ExportFile((path + std::to_string(i.second->file_id())).c_str());
  84. }
  85. }
  86. return success;
  87. }
  88. /// Extracts all files with specific type to database "db";
  89. /// DATABASE SHOULD BE ALREADY CREATED; Otherwise DatException will be called.
  90. /// Returns number of successfully extracted files
  91. /// Throws DatException() if undefined behaviour happened
  92. int DatFile::ExtractAllFilesByType(FILE_TYPE type, Database *db) {
  93. if (dat_state_ != READY) {
  94. throw DatException("Bad DatFile::ExtractAllFilesByType() - invalid DatFile state!", EXPORT_EXCEPTION);
  95. }
  96. int success = 0;
  97. for (auto i : dictionary_) {
  98. FILE_TYPE ext = i.second->ext();
  99. if (ext == type) {
  100. success += i.second->ExportFile(db);
  101. }
  102. }
  103. return success;
  104. }
  105. /// Patches .dat with text file with specific file_id, gossip_id and values, equal to values in text database.
  106. /// std::string text contains of text data, surrounded by '[' and ']', where <--DO_NOT_TOUCH!--> represents
  107. /// position of variables in order, described in args_order.
  108. /// std::string args_order contains of numbers, divided by '-'. Ex. "1-2-3-4". There should be not less numbers, than
  109. /// <--DO_NOT_TOUCH!--> pieces in text variable/
  110. /// std::string args contains of numbers, divided by ' '. These numbers are references to variables. There should
  111. /// be not less references, than the biggest number in args_order
  112. /// Returns true if text was succesfully patched.
  113. /// Throws DatException() if undefined behaviour happened;
  114. bool DatFile::PatchTextFile(long long file_id, long long gossip_id, std::string text, std::string args_order,
  115. std::string args) {
  116. return false;
  117. }
  118. /// Patches .dat with text file with specific file_id and gossip_id.
  119. /// All text file data is got from database.
  120. /// Returns true if text file was successfully patched.
  121. /// Throws DatException() if undefined behaviour happened;
  122. bool DatFile::PatchTextFile(long long file_id, long long gossip_id, Database *db) {
  123. return false;
  124. }
  125. /// Patches .dat with binary file with specific file_id.
  126. /// All file data is got from file in "file_path".
  127. /// Returns true if file was successfully patched.
  128. /// Throws DatException() if undefined behaviour happened;
  129. bool DatFile::PatchBinaryFile(long long file_id, std::string file_path) {
  130. return false;
  131. }
  132. /// Patches .dat with binary file with specific file_id.
  133. /// All file data is got from Database "db".
  134. /// Returns true if file was successfully patched.
  135. /// Throws DatException() if undefined behaviour happened;
  136. bool DatFile::PatchBinaryFile(long long file_id, Database *db) {
  137. return false;
  138. }
  139. void DatFile::OpenDatFile(const char *dat_name) {
  140. if (dat_state_ != CLOSED)
  141. throw DatException("Bad initialisation of DatFile - current DatFile isn't in correct state!",
  142. INIT_EXCEPTION);
  143. fopen_s(&file_handler_, dat_name, "r+b");
  144. if (file_handler_ == nullptr) {
  145. std::string err = "Bad DatFile::OpenDatFile. Unable to open file ";
  146. err += dat_name;
  147. throw DatException(err.c_str(), INIT_EXCEPTION);
  148. }
  149. fseek(file_handler_, 0, SEEK_END);
  150. file_size_ = ftell(file_handler_);
  151. fseek(file_handler_, 0, SEEK_SET);
  152. dat_state_ = SUCCESS_OPENED;
  153. }
  154. void DatFile::ReadSuperBlock() {
  155. if (dat_state_ != SUCCESS_OPENED)
  156. throw DatException("Bad DatFile::ReadSuperBlock() - DatFile isn't in valid state!", INIT_EXCEPTION);
  157. BinaryData data(1024);
  158. ReadData(data, 1024);
  159. constant1_ = data.ToNumber<4>(0x100);
  160. constant2_ = data.ToNumber<4>(0x140);
  161. version1_ = data.ToNumber<4>(0x14C);
  162. version2_ = data.ToNumber<4>(0x150);
  163. root_directory_offset_ = data.ToNumber<4>(0x160);
  164. auto size1 = data.ToNumber<4>(0x148);
  165. if (constant1_ != 0x4C5000)
  166. throw DatException(
  167. "Bad DatFile::ReadSuperBlock - variable at position 0x100 is not equal to .dat file constant!",
  168. INIT_EXCEPTION);
  169. if (constant2_ != 0x5442)
  170. throw DatException(
  171. "Bad DatFile::ReadSuperBlock - variable at position 0x140 is not equal to .dat file constant!",
  172. INIT_EXCEPTION);
  173. if (file_size_ != size1)
  174. throw DatException(
  175. "Bad DatFile::ReadSuperBlock - variable at 0x148 position is not equal to .dat file size!",
  176. INIT_EXCEPTION);
  177. dat_state_ = SUCCESS_SUPERBLOCK;
  178. }
  179. void DatFile::MakeDirectories() {
  180. if (dat_state_ != SUCCESS_SUPERBLOCK)
  181. throw DatException("Bad DatFile::MakeDirectories() - DatFile isn't in valid state!", INIT_EXCEPTION);
  182. root_directory_ = new SubDirectory((unsigned) root_directory_offset_, this);
  183. dat_state_ = SUCCESS_DIRECTORIES;
  184. }
  185. void DatFile::MakeDictionary() {
  186. if (dat_state_ != SUCCESS_DIRECTORIES)
  187. throw DatException("Bad DatFile::MakeDictionary() - DatFile isn't in valid state!", INIT_EXCEPTION);
  188. try {
  189. root_directory_->MakeDictionary(dictionary_);
  190. } catch (...) {
  191. fprintf(stderr, "Bad DatFile::MakeDictionary() - File is corrupted?\n");
  192. return;
  193. }
  194. dat_state_ = SUCCESS_DICTIONARY;
  195. }
  196. void DatFile::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) {
  197. if (dat_state_ == CLOSED)
  198. throw DatException("Bad DatFile::ReadData() - DatFile isn't in valid state!", READ_EXCEPTION);
  199. if (data_offset + size > data.size()) {
  200. std::string err = "Bad DatFile::ReadData - trying to read more than BinaryData size\n";
  201. err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
  202. + std::to_string(offset) + std::string(" position in dat file.");
  203. throw DatException(err.c_str(), READ_EXCEPTION);
  204. }
  205. if (offset + size > file_size()) {
  206. std::string err = "Bad DatFile::ReadData - trying to read more than DatFile size elapsed\n";
  207. err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
  208. + std::to_string(offset) + std::string(" position in dat file.");
  209. throw DatException(err.c_str(), READ_EXCEPTION);
  210. }
  211. _fseeki64(file_handler_, offset, SEEK_SET);
  212. fread(data.data() + data_offset, size, 1, file_handler_);
  213. data.CheckCompression();
  214. }
  215. void DatFile::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
  216. if (dat_state_ != READY)
  217. throw DatException("Bad DatFile::WriteData() - DatFile isn't in valid state!", WRITE_EXCEPTION);
  218. _fseeki64(file_handler_, offset, SEEK_SET);
  219. if (data_offset + size > data.size())
  220. throw DatException("Bad DatFile::WriteData - trying to write more than BinaryData size", WRITE_EXCEPTION);
  221. fwrite(data.data() + data_offset, size, 1, file_handler_);
  222. }
  223. long long DatFile::constant1() const {
  224. return constant1_;
  225. }
  226. long long DatFile::constant2() const {
  227. return constant2_;
  228. }
  229. long long DatFile::file_size() const {
  230. return file_size_;
  231. }
  232. long long DatFile::version1() const {
  233. return version1_;
  234. }
  235. long long DatFile::version2() const {
  236. return version2_;
  237. }
  238. void DatFile::WriteUnorderedDictionary(std::string path) const {
  239. FILE *f;
  240. fopen_s(&f, (path + "dict.txt").c_str(), "w");
  241. fprintf(f, "file_id offset size size2 extension\n");
  242. for (auto i : dictionary_) {
  243. std::string extension = "unk";
  244. FILE_TYPE ext = i.second->ext();
  245. if (ext == TEXT) extension = "txt";
  246. if (ext == JPG) extension = "jpg";
  247. if (ext == DDS) extension = "dds";
  248. if (ext == WAV) extension = "wav";
  249. if (ext == OGG) extension = "ogg";
  250. if (ext == FONT) extension = "font";
  251. fprintf(f, "%lld %lld %lld %lld %s\n", i.second->file_id(), i.second->file_offset(), i.second->file_size(),
  252. i.second->block_size(), extension.c_str());
  253. }
  254. fclose(f);
  255. }
  256. long long DatFile::files_number() const {
  257. return dictionary_.size();
  258. }
  259. }
  260. }