123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- //
- // Created by kikab on 04.06.2018.
- //
- #include "BinaryData.h"
- #include "DatFile.h"
- #include "DatFileIO.h"
- #include "EasyLogging++/easylogging++.h"
- #include "SubDirectory.h"
- #include "SubFile.h"
- #include <algorithm>
- #include <iterator>
- #include <locale>
- #include <DatOperationResult.h>
- #include <DatFileIO.h>
- #ifdef WIN32
- #define fseek _fseeki64
- #define ftell _ftelli64
- #endif
- extern "C++"
- {
- namespace LOTRO_DAT {
- DatFileIO::DatFileIO(DatFile &dat_ref) : dat_file_ref(dat_ref), file_handler_(nullptr), filename_(),
- root_directory_(nullptr), actual_dat_size_(0) {
- }
- //------------------------------------------------//
- // INIT SECTION
- //------------------------------------------------//
- DatOperationResult DatFileIO::Init(const std::string &filename) {
- LOG(INFO) << "Initializing IO: " << filename;
- filename_ = filename;
- auto result = OpenDatFile();
- if (result.result == DatOperationResult::ERROR) {
- LOG(ERROR) << "Error in OpenDatFile: " << result.msg;
- DeInit();
- return result;
- }
- result = ReadSuperBlock();
- if (result.result == DatOperationResult::ERROR) {
- LOG(ERROR) << "Error in ReadSuperBlock: " << result.msg;
- DeInit();
- return result;
- }
- result = MakeDirectories();
- if (result.result == DatOperationResult::ERROR) {
- LOG(ERROR) << "Error in MakeDirectories: " << result.msg;
- DeInit();
- return result;
- }
- LOG(INFO) << "Successfull initializing IO: " << filename;
- return DatOperationResult(DatOperationResult::SUCCESS, "DatFileIO initialized successfully");
- }
- DatOperationResult DatFileIO::OpenDatFile() {
- LOG(DEBUG) << "DatFileIO: Started opening DatFile";
- file_handler_ = fopen(filename_.c_str(), "r+b");
- if (file_handler_ == nullptr) {
- LOG(ERROR) << "DatFileIO: Unable to open file " << filename_ << ". Presumably - no file found...";
- return DatOperationResult(DatOperationResult::ERROR,
- std::string("Unable to locate and open file " + filename_));
- }
- fseek(file_handler_, 0, SEEK_END);
- actual_dat_size_ = ftell(file_handler_);
- fseek(file_handler_, 0, SEEK_SET);
- LOG(INFO) << "DatFileIO: file opened";
- return DatOperationResult(DatOperationResult::SUCCESS, std::string("Successfully opened file " + filename_));
- }
- DatOperationResult DatFileIO::ReadSuperBlock() {
- LOG(INFO) << "DatFileIO: Started reading superblock";
- BinaryData data(1024);
- ReadData(data, 1024);
- constant1 = data.ToNumber<4>(0x100);
- constant2 = data.ToNumber<4>(0x140);
- version1 = data.ToNumber<4>(0x14C);
- file_size = data.ToNumber<4>(0x148);
- version2 = data.ToNumber<4>(0x150);
- fragmentation_journal_offset = data.ToNumber<4>(0x154);
- fragmentation_journal_end = data.ToNumber<4>(0x158);
- fragmentation_journal_size = data.ToNumber<4>(0x15C);
- root_directory_offset = data.ToNumber<4>(0x160);
- free_dat_size = data.ToNumber<4>(0x19C);
- if (constant1 != 0x4C5000) {
- LOG(ERROR) << "Variable at position 0x100 is not equal to .dat file constant!";
- return DatOperationResult(DatOperationResult::ERROR,
- std::string("Variable at position 0x100 is not equal to .dat file constant!"));;
- }
- if (constant2 != 0x5442) {
- LOG(ERROR) << "Variable at position 0x140 is not equal to .dat file constant!";
- return DatOperationResult(DatOperationResult::ERROR,
- std::string("Variable at position 0x140 is not equal to .dat file constant!"));;
- }
- if (file_size != actual_dat_size_) {
- LOG(INFO) << "Variable at 0x148 position is not equal to .dat file size!";
- //return CORRUPTED_FILE_WARNING;
- }
- LOG(INFO) << "DatFileIO: Superblock read successfully";
- return DatOperationResult(DatOperationResult::SUCCESS, std::string("Superblock read successfully."));;
- }
- DatOperationResult DatFileIO::MakeDirectories() {
- LOG(INFO) << "DatFileIO: Started making directories";
- root_directory_ = std::make_shared<SubDirectory>((unsigned) root_directory_offset, dat_file_ref);
- SubDirectory::subdir_init_queue_.insert(root_directory_);
- while (!SubDirectory::subdir_init_queue_.empty()) {
- std::shared_ptr<SubDirectory> dir = *SubDirectory::subdir_init_queue_.begin();
- SubDirectory::subdir_init_queue_.erase(SubDirectory::subdir_init_queue_.begin());
- if (dir->MakeSubDirectories())
- SubDirectory::subfile_init_queue_.insert(dir);
- else
- dir->clear();
- }
- while (!SubDirectory::subfile_init_queue_.empty()) {
- std::shared_ptr<SubDirectory> dir = *SubDirectory::subfile_init_queue_.begin();
- SubDirectory::subfile_init_queue_.erase(SubDirectory::subfile_init_queue_.begin());
- if (!dir->MakeSubFiles())
- dir->clear();
- }
- LOG(INFO) << "DatFileIO: Directories made successfully";
- return DatOperationResult(DatOperationResult::SUCCESS, std::string("Directories initialise successful."));
- }
- //------------------------------------------------//
- // PUBLIC READ/WRITE SECTION
- //------------------------------------------------//
- DatOperationResult
- DatFileIO::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) const {
- if (file_handler_ == nullptr) {
- LOG(ERROR) << "IOError: file handler is null pointer on reading data.";
- data = BinaryData(0);
- return DatOperationResult(DatOperationResult::ERROR,
- "IOError: file handler is null pointer on reading data.");
- }
- if (data_offset + size > data.size()) {
- LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset
- << " position.";
- data = BinaryData(0);
- return DatOperationResult(DatOperationResult::ERROR, "IOError: Parameters: offset, size are out of range.");
- }
- if (offset + size > actual_dat_size_) {
- LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset
- << " position.";
- data = BinaryData(0);
- return DatOperationResult(DatOperationResult::ERROR, "IOError: Reading from end of file.");
- }
- if (offset != ftell(file_handler_))
- fseek(file_handler_, offset, SEEK_SET);
- fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
- return DatOperationResult(DatOperationResult::SUCCESS, "Read data successful.");
- }
- DatOperationResult
- DatFileIO::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
- if (file_handler_ == nullptr) {
- LOG(ERROR) << "IOError: file handler is null pointer on writing data";
- return DatOperationResult(DatOperationResult::ERROR,
- "IOError: file handler is null pointer on writing data.");
- }
- if (offset != ftell(file_handler_))
- fseek(file_handler_, offset, SEEK_SET);
- if (data_offset + size > data.size()) {
- LOG(ERROR) << "Trying to write more than BinaryData size";
- return DatOperationResult(DatOperationResult::ERROR, "IOError: writing more than BinaryData size.");
- }
- fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
- if (offset + size > actual_dat_size_) {
- actual_dat_size_ = offset + size;
- }
- return DatOperationResult(DatOperationResult::SUCCESS, "Data writing successful.");
- }
- //------------------------------------------------//
- // DEINIT SECTION
- //------------------------------------------------//
- DatOperationResult DatFileIO::DeInit() {
- UpdateHeader();
- if (file_handler_ != nullptr) {
- fclose(file_handler_);
- }
- filename_ = "none";
- file_handler_ = nullptr;
- root_directory_ = nullptr;
- constant1 = 0;
- constant2 = 0;
- file_size = 0;
- version1 = 0;
- version2 = 0;
- fragmentation_journal_size = 0;
- fragmentation_journal_end = 0;
- root_directory_offset = 0;
- fragmentation_journal_offset = 0;
- return DatOperationResult(DatOperationResult::SUCCESS, "File deinitialisation successfull");
- }
- DatOperationResult DatFileIO::ModifyFragmentationJournal() {
- if (fragmentation_journal_size == 0)
- return DatOperationResult(DatOperationResult::SUCCESS,
- "DatFileIO: Fragmentation journal is empty. Nothing to do.");
- LOG(DEBUG) << "Modifying fragmentation journal";
- BinaryData data(4);
- ReadData(data, 4, fragmentation_journal_offset + 8 * fragmentation_journal_size);
- LOG(INFO) << "FREE_SIZE BLOCK = " << data.ToNumber<4>(0);
- long long free_size = data.ToNumber<4>(0);
- long long free_offset = file_size;
- BinaryData nulldata = BinaryData(unsigned(free_size));
- WriteData(nulldata, nulldata.size(), file_size);
- file_size += nulldata.size();
- WriteData(BinaryData::FromNumber<4>(free_size), 4,
- fragmentation_journal_offset + 8 * fragmentation_journal_size);
- WriteData(BinaryData::FromNumber<4>(free_offset), 4,
- fragmentation_journal_offset + 8 * fragmentation_journal_size + 4);
- //nulldata = BinaryData(8);
- //WriteData(nulldata, nulldata.size(), fragmentation_journal_offset + 16);
- LOG(DEBUG) << "Finished modifying fragmentation journal";
- return DatOperationResult(DatOperationResult::SUCCESS, "Fragmentation journal patched successfully!");
- }
- DatOperationResult DatFileIO::UpdateHeader() {
- LOG(DEBUG) << "Updating header";
- WriteData(BinaryData::FromNumber<4>(constant1), 4, 0x100);
- WriteData(BinaryData::FromNumber<4>(constant2), 4, 0x140);
- //WriteData(BinaryData::FromNumber<4>( 0 ), 4, 0x144);
- WriteData(BinaryData::FromNumber<4>(file_size), 4, 0x148);
- WriteData(BinaryData::FromNumber<4>(version1), 4, 0x14C);
- WriteData(BinaryData::FromNumber<4>(version2), 4, 0x150);
- WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset), 4, 0x154);
- WriteData(BinaryData::FromNumber<4>(fragmentation_journal_end), 4, 0x158);
- WriteData(BinaryData::FromNumber<4>(fragmentation_journal_size), 4, 0x15C);
- WriteData(BinaryData::FromNumber<4>(root_directory_offset), 4, 0x160);
- WriteData(BinaryData::FromNumber<4>(free_dat_size), 4, 0x19C);
- LOG(DEBUG) << "Finished updating header";
- return DatOperationResult(DatOperationResult::SUCCESS, "File header patched successfully");;
- }
- std::shared_ptr<SubDirectory> DatFileIO::GetRootDirectory() {
- return root_directory_;
- }
- long long DatFileIO::GetActualDatSize() {
- return actual_dat_size_;
- }
- }
- }
|