DatFileIO.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //
  2. // Created by kikab on 04.06.2018.
  3. //
  4. #include "BinaryData.h"
  5. #include "DatFile.h"
  6. #include "DatFileIO.h"
  7. #include "EasyLogging++/easylogging++.h"
  8. #include "SubDirectory.h"
  9. #include "SubFile.h"
  10. #include <algorithm>
  11. #include <iterator>
  12. #include <locale>
  13. #include <DatOperationResult.h>
  14. #include <DatFileIO.h>
  15. #ifdef WIN32
  16. #define fseek _fseeki64
  17. #define ftell _ftelli64
  18. #endif
  19. extern "C++"
  20. {
  21. namespace LOTRO_DAT {
  22. DatFileIO::DatFileIO(DatFile &dat_ref) : dat_file_ref(dat_ref), file_handler_(nullptr), filename_(),
  23. root_directory_(nullptr), actual_dat_size_(0) {
  24. }
  25. //------------------------------------------------//
  26. // INIT SECTION
  27. //------------------------------------------------//
  28. DatOperationResult DatFileIO::Init(const std::string &filename) {
  29. LOG(INFO) << "Initializing IO: " << filename;
  30. filename_ = filename;
  31. auto result = OpenDatFile();
  32. if (result.result == DatOperationResult::ERROR) {
  33. LOG(ERROR) << "Error in OpenDatFile: " << result.msg;
  34. DeInit();
  35. return result;
  36. }
  37. result = ReadSuperBlock();
  38. if (result.result == DatOperationResult::ERROR) {
  39. LOG(ERROR) << "Error in ReadSuperBlock: " << result.msg;
  40. DeInit();
  41. return result;
  42. }
  43. result = MakeDirectories();
  44. if (result.result == DatOperationResult::ERROR) {
  45. LOG(ERROR) << "Error in MakeDirectories: " << result.msg;
  46. DeInit();
  47. return result;
  48. }
  49. LOG(INFO) << "Successfull initializing IO: " << filename;
  50. return DatOperationResult(DatOperationResult::SUCCESS, "DatFileIO initialized successfully");
  51. }
  52. DatOperationResult DatFileIO::OpenDatFile() {
  53. LOG(DEBUG) << "DatFileIO: Started opening DatFile";
  54. file_handler_ = fopen(filename_.c_str(), "r+b");
  55. if (file_handler_ == nullptr) {
  56. LOG(ERROR) << "DatFileIO: Unable to open file " << filename_ << ". Presumably - no file found...";
  57. return DatOperationResult(DatOperationResult::ERROR,
  58. std::string("Unable to locate and open file " + filename_));
  59. }
  60. fseek(file_handler_, 0, SEEK_END);
  61. actual_dat_size_ = ftell(file_handler_);
  62. fseek(file_handler_, 0, SEEK_SET);
  63. LOG(INFO) << "DatFileIO: file opened";
  64. return DatOperationResult(DatOperationResult::SUCCESS, std::string("Successfully opened file " + filename_));
  65. }
  66. DatOperationResult DatFileIO::ReadSuperBlock() {
  67. LOG(INFO) << "DatFileIO: Started reading superblock";
  68. BinaryData data(1024);
  69. ReadData(data, 1024);
  70. constant1 = data.ToNumber<4>(0x100);
  71. constant2 = data.ToNumber<4>(0x140);
  72. version1 = data.ToNumber<4>(0x14C);
  73. file_size = data.ToNumber<4>(0x148);
  74. version2 = data.ToNumber<4>(0x150);
  75. fragmentation_journal_offset = data.ToNumber<4>(0x154);
  76. fragmentation_journal_end = data.ToNumber<4>(0x158);
  77. fragmentation_journal_size = data.ToNumber<4>(0x15C);
  78. root_directory_offset = data.ToNumber<4>(0x160);
  79. free_dat_size = data.ToNumber<4>(0x19C);
  80. if (constant1 != 0x4C5000) {
  81. LOG(ERROR) << "Variable at position 0x100 is not equal to .dat file constant!";
  82. return DatOperationResult(DatOperationResult::ERROR,
  83. std::string("Variable at position 0x100 is not equal to .dat file constant!"));
  84. }
  85. if (constant2 != 0x5442) {
  86. LOG(ERROR) << "Variable at position 0x140 is not equal to .dat file constant!";
  87. return DatOperationResult(DatOperationResult::ERROR,
  88. std::string("Variable at position 0x140 is not equal to .dat file constant!"));
  89. }
  90. if (file_size != actual_dat_size_) {
  91. LOG(INFO) << "Variable at 0x148 position is not equal to .dat file size!";
  92. //return CORRUPTED_FILE_WARNING;
  93. }
  94. LOG(INFO) << "DatFileIO: Superblock read successfully";
  95. return DatOperationResult(DatOperationResult::SUCCESS, std::string("Superblock read successfully."));
  96. }
  97. DatOperationResult DatFileIO::MakeDirectories() {
  98. LOG(INFO) << "DatFileIO: Started making directories";
  99. root_directory_ = std::make_shared<SubDirectory>((unsigned) root_directory_offset, dat_file_ref);
  100. SubDirectory::subdir_init_queue_.insert(root_directory_);
  101. while (!SubDirectory::subdir_init_queue_.empty()) {
  102. std::shared_ptr<SubDirectory> dir = *SubDirectory::subdir_init_queue_.begin();
  103. SubDirectory::subdir_init_queue_.erase(SubDirectory::subdir_init_queue_.begin());
  104. if (dir->MakeSubDirectories())
  105. SubDirectory::subfile_init_queue_.insert(dir);
  106. else
  107. dir->clear();
  108. }
  109. while (!SubDirectory::subfile_init_queue_.empty()) {
  110. std::shared_ptr<SubDirectory> dir = *SubDirectory::subfile_init_queue_.begin();
  111. SubDirectory::subfile_init_queue_.erase(SubDirectory::subfile_init_queue_.begin());
  112. if (!dir->MakeSubFiles())
  113. dir->clear();
  114. }
  115. LOG(INFO) << "DatFileIO: Directories made successfully";
  116. return DatOperationResult(DatOperationResult::SUCCESS, std::string("Directories initialise successful."));
  117. }
  118. //------------------------------------------------//
  119. // PUBLIC READ/WRITE SECTION
  120. //------------------------------------------------//
  121. DatOperationResult
  122. DatFileIO::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) const {
  123. if (file_handler_ == nullptr) {
  124. LOG(ERROR) << "IOError: file handler is null pointer on reading data.";
  125. data = BinaryData(0);
  126. return DatOperationResult(DatOperationResult::ERROR,
  127. "IOError: file handler is null pointer on reading data.");
  128. }
  129. if (data_offset + size > data.size()) {
  130. LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset
  131. << " position.";
  132. data = BinaryData(0);
  133. return DatOperationResult(DatOperationResult::ERROR, "IOError: Parameters: offset, size are out of range.");
  134. }
  135. if (offset + size > actual_dat_size_) {
  136. LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset
  137. << " position.";
  138. data = BinaryData(0);
  139. return DatOperationResult(DatOperationResult::ERROR, "IOError: Reading from end of file.");
  140. }
  141. if (offset != ftell(file_handler_))
  142. fseek(file_handler_, offset, SEEK_SET);
  143. fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
  144. return DatOperationResult(DatOperationResult::SUCCESS, "Read data successful.");
  145. }
  146. DatOperationResult
  147. DatFileIO::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
  148. if (file_handler_ == nullptr) {
  149. LOG(ERROR) << "IOError: file handler is null pointer on writing data";
  150. return DatOperationResult(DatOperationResult::ERROR,
  151. "IOError: file handler is null pointer on writing data.");
  152. }
  153. if (offset != ftell(file_handler_))
  154. fseek(file_handler_, offset, SEEK_SET);
  155. if (data_offset + size > data.size()) {
  156. LOG(ERROR) << "Trying to write more than BinaryData size";
  157. return DatOperationResult(DatOperationResult::ERROR, "IOError: writing more than BinaryData size.");
  158. }
  159. fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
  160. if (offset + size > actual_dat_size_) {
  161. actual_dat_size_ = offset + size;
  162. }
  163. return DatOperationResult(DatOperationResult::SUCCESS, "Data writing successful.");
  164. }
  165. //------------------------------------------------//
  166. // DEINIT SECTION
  167. //------------------------------------------------//
  168. DatOperationResult DatFileIO::DeInit() {
  169. if (file_handler_ != nullptr) {
  170. fclose(file_handler_);
  171. }
  172. filename_ = "none";
  173. file_handler_ = nullptr;
  174. root_directory_ = nullptr;
  175. constant1 = 0;
  176. constant2 = 0;
  177. file_size = 0;
  178. version1 = 0;
  179. version2 = 0;
  180. fragmentation_journal_size = 0;
  181. fragmentation_journal_end = 0;
  182. root_directory_offset = 0;
  183. fragmentation_journal_offset = 0;
  184. return DatOperationResult(DatOperationResult::SUCCESS, "File deinitialisation successfull");
  185. }
  186. DatOperationResult DatFileIO::ModifyFragmentationJournal() {
  187. if (fragmentation_journal_size == 0)
  188. return DatOperationResult(DatOperationResult::SUCCESS,
  189. "DatFileIO: Fragmentation journal is empty. Nothing to do.");
  190. LOG(DEBUG) << "Modifying fragmentation journal";
  191. BinaryData data(4);
  192. ReadData(data, 4, fragmentation_journal_offset + 8 * fragmentation_journal_size);
  193. LOG(INFO) << "FREE_SIZE BLOCK = " << data.ToNumber<4>(0);
  194. long long free_size = data.ToNumber<4>(0);
  195. long long free_offset = file_size;
  196. BinaryData nulldata = BinaryData(unsigned(free_size));
  197. WriteData(nulldata, nulldata.size(), file_size);
  198. file_size += nulldata.size();
  199. WriteData(BinaryData::FromNumber<4>(free_size), 4,
  200. fragmentation_journal_offset + 8 * fragmentation_journal_size);
  201. WriteData(BinaryData::FromNumber<4>(free_offset), 4,
  202. fragmentation_journal_offset + 8 * fragmentation_journal_size + 4);
  203. //nulldata = BinaryData(8);
  204. //WriteData(nulldata, nulldata.size(), fragmentation_journal_offset + 16);
  205. LOG(DEBUG) << "Finished modifying fragmentation journal";
  206. return DatOperationResult(DatOperationResult::SUCCESS, "Fragmentation journal patched successfully!");
  207. }
  208. DatOperationResult DatFileIO::UpdateHeader() {
  209. LOG(DEBUG) << "Updating header";
  210. WriteData(BinaryData::FromNumber<4>(constant1), 4, 0x100);
  211. WriteData(BinaryData::FromNumber<4>(constant2), 4, 0x140);
  212. //WriteData(BinaryData::FromNumber<4>( 0 ), 4, 0x144);
  213. WriteData(BinaryData::FromNumber<4>(file_size), 4, 0x148);
  214. WriteData(BinaryData::FromNumber<4>(version1), 4, 0x14C);
  215. WriteData(BinaryData::FromNumber<4>(version2), 4, 0x150);
  216. WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset), 4, 0x154);
  217. WriteData(BinaryData::FromNumber<4>(fragmentation_journal_end), 4, 0x158);
  218. WriteData(BinaryData::FromNumber<4>(fragmentation_journal_size), 4, 0x15C);
  219. WriteData(BinaryData::FromNumber<4>(root_directory_offset), 4, 0x160);
  220. WriteData(BinaryData::FromNumber<4>(free_dat_size), 4, 0x19C);
  221. LOG(DEBUG) << "Finished updating header";
  222. return DatOperationResult(DatOperationResult::SUCCESS, "File header patched successfully");;
  223. }
  224. std::shared_ptr<SubDirectory> DatFileIO::GetRootDirectory() {
  225. return root_directory_;
  226. }
  227. long long DatFileIO::GetActualDatSize() {
  228. return actual_dat_size_;
  229. }
  230. }
  231. }