|
@@ -7,12 +7,14 @@
|
|
|
#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)");
|
|
@@ -69,23 +71,137 @@ namespace LOTRO_DAT{
|
|
|
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::Init() {}
|
|
|
|
|
|
- DatOperationResult<> DatFileSystem::DeInit() {}
|
|
|
+ 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);
|
|
|
+ }
|
|
|
}
|