123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- //
- // Created by kikab on 04.06.2018.
- //
- #include <DatSubsystems/DatFileSystem.h>
- #include <EasyLogging++/easylogging++.h>
- #include <BinaryData.h>
- #include <DatFile.h>
- #include <SubFile.h>
- #include <SubDirectory.h>
- namespace LOTRO_DAT{
- DatFileSystem::DatFileSystem(DatFile *datFilePtr) : dat(datFilePtr) {
- LOG(INFO) << "Initialization of empty DatFileSystem";
- }
- DatOperationResult<BinaryData> DatFileSystem::GetFileData(long long file_id, long long int offset) {
- if (!dat)
- return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- if (dictionary_.count(file_id))
- return DatOperationResult<BinaryData>(BinaryData(), ERROR, "DatFileSystem error: no file found with id = " + std::to_string(file_id));
- auto file = dictionary_[file_id];
- LOG(DEBUG) << "Getting file " << file->file_id() << " data";
- BinaryData mfile_id(20);
- auto operation = dat->getIO().ReadData(mfile_id, 20, file->file_offset() + 8);
- if (operation.result == ERROR) {
- LOG(ERROR) << "Error while reading file " << file->file_id() << " header (offset = "
- << file->file_offset() << "); Message: " << operation.msg << "Aborting.";
- return DatOperationResult<BinaryData>(BinaryData(), ERROR, std::string("DatFileSystem error: Read ") + std::to_string(file_id) + " error." + operation.msg);
- }
- if (!mfile_id.CheckCompression() && file->file_id() != mfile_id.ToNumber<4>(0)) {
- LOG(ERROR) << "Bad DatFile::GetFileData() - file_id in SubFile ("
- << file->file_id()
- << ") doesn't match to file_id (" << mfile_id.ToNumber<4>(0) << ")in DatFile.";
- return DatOperationResult<BinaryData>(BinaryData(), ERROR, std::string("DatFileSystem error: Read ") + std::to_string(file_id) + " error: SubFile value differs from value in dict");
- }
- BinaryData data((unsigned)(file->file_size() + (8 - offset)));
- if (file->block_size() >= file->file_size() + 8) {
- dat->getIO().ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
- return DatOperationResult<BinaryData>(data, SUCCESS);
- }
- BinaryData fragments_count(4);
- dat->getIO().ReadData(fragments_count, 4, file->file_offset());
- long long fragments_number = fragments_count.ToNumber<4>(0);
- long long current_block_size = file->block_size() - offset - 8 * fragments_number;
- dat->getIO().ReadData(data, current_block_size, file->file_offset() + offset);
- BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
- dat->getIO().ReadData(FragmentsDictionary, 8 * unsigned(fragments_number),
- file->file_offset() + file->block_size() - 8 * fragments_number);
- for (long long i = 0; i < fragments_number; i++) {
- long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
- long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
- dat->getIO().ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset,
- current_block_size);
- current_block_size += fragment_size;
- }
- LOG(DEBUG) << "Successfully got file " << file->file_id() << " data";
- return DatOperationResult<BinaryData>(data, SUCCESS);
- }
- DatOperationResult<SubFile> DatFileSystem::GetFile(long long file_id) {
- if (!dat)
- return DatOperationResult<SubFile>(SubFile(), ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- if (dictionary_.count(file_id) == 0)
- return DatOperationResult<SubFile>(SubFile(), ERROR, "No file with id = " + std::to_string(file_id) + " found in dictionary");
- return DatOperationResult<SubFile>(*dictionary_[file_id].get(), SUCCESS);
- }
- DatOperationResult<> DatFileSystem::UpdateFile(const SubFile &file) {
- if (!dat)
- return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- if (dictionary_.count(file.file_id()) == 0)
- return DatOperationResult<>(ERROR, "No file with id = " + std::to_string(file.file_id()) + " found in dictionary. Cannot update file");
- *dictionary_[file.file_id()] = file;
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<> DatFileSystem::MakeDirectories() {
- LOG(DEBUG) << "Started making directories";
- if (!dat)
- return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- root_directory_ = std::make_shared<SubDirectory>((unsigned)dat->getIO().root_directory_offset, *dat);
- 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(DEBUG) << "Directories made successfully";
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<> DatFileSystem::MakeDictionary() {
- LOG(DEBUG) << "Started making dictionary";
- if (!dat)
- return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- if (root_directory_ == nullptr) {
- return DatOperationResult<>(ERROR, "DatFileSystem error: making dictionary from nullptr root directory");
- }
- root_directory_->MakeDictionary(dictionary_);
- LOG(DEBUG) << "Dictionary made successfull";
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<> DatFileSystem::CommitDirectories() {
- if (!dat)
- return DatOperationResult<>(ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- for (auto file_id : subfile_pending_update) {
- if (dictionary_[file_id] == nullptr)
- continue;
- auto operation = CheckCorrectSubfile(*dictionary_[file_id].get());
- if (operation.result == ERROR) {
- LOG(ERROR) << "Check subfile correctness failed. Error message: " << operation.msg;
- continue;
- }
- if (!operation.value) {
- LOG(DEBUG) << "Incorrect SubFile " << file_id << " data: doesn't match";
- continue;
- }
- auto operation1 = dat->getIO().WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
- if (operation1.result == ERROR) {
- LOG(ERROR) << "Unable to write data to dictionary for file " << file_id << ". Returned message: " << operation.msg;
- }
- }
- subfile_pending_update.clear();
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<bool> DatFileSystem::CheckCorrectSubfile(const SubFile &file) {
- if (!dat)
- return DatOperationResult<bool>(false, ERROR, "DatFileSystem error: no connection with Dat (dat is nullptr)");
- BinaryData mfile_id(20);
- dat->getIO().ReadData(mfile_id, 20, file.file_offset() + 8);
- if (mfile_id.Empty())
- return DatOperationResult<bool>(false, SUCCESS);
- return DatOperationResult<bool>((mfile_id.CheckCompression() || file.file_id() == mfile_id.ToNumber<4>(0)) && file.file_size() < 50ll * 1024ll * 1024ll, SUCCESS);
- }
- DatOperationResult<> DatFileSystem::Init() {
- auto operation = MakeDirectories();
- if (operation.result == ERROR) {
- LOG(ERROR) << "Unable to make direcories. Error msg: " << operation.msg;
- return DatOperationResult<>(ERROR, "Unable to init Dat file system due to fail while making directories");
- }
- operation = MakeDictionary();
- if (operation.result == ERROR) {
- LOG(ERROR) << "Unable to make dictionary. Error msg: " << operation.msg;
- return DatOperationResult<>(ERROR, "Unable to init Dat file system due to fail while making dictionary");
- }
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<> DatFileSystem::DeInit() {
- auto operation = CommitDirectories();
- if (operation.result == ERROR) {
- LOG(ERROR) << "Unable to commit direcories. Error msg: " << operation.msg;
- return DatOperationResult<>(ERROR, "Unable to deinit Dat file system due to fail while making directories");
- }
- return DatOperationResult<>(SUCCESS);
- }
- }
|