DatIO.cpp 9.3 KB

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