Browse Source

25.06.2020 Improved version and iteration usage while patching files && added minor fixes

Ivan Arkhipov 3 years ago
parent
commit
4850196c43
6 changed files with 79 additions and 30 deletions
  1. 1 1
      CMakeLists.txt
  2. 11 6
      include/datfile.h
  3. 11 0
      src/database.cpp
  4. 54 10
      src/datfile.cpp
  5. 0 11
      src/utils/inserter.cpp
  6. 2 2
      src/utils/single_file_import_export.cpp

+ 1 - 1
CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.8)
 project(LotroDat)
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 8.0.0)
 # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -Wall -Wextra -O2")

+ 11 - 6
include/datfile.h

@@ -9,9 +9,9 @@
 namespace LOTRO_DAT {
 
 struct SubfileInfo {
-	int file_id;
-	int size;
-	int iteration;
+	int file_id = -1;
+	int size = -1;
+	int iteration = -1;
 
 	friend bool operator<(const SubfileInfo& info1, const SubfileInfo& info2) {
 		return info1.file_id < info2.file_id;
@@ -32,11 +32,13 @@ class DatFile {
 
 	bool Initialized() const;
 	const std::string& GetFilename() const;
+	SubfileInfo getSubfileInfo(int file_id) const;
+
 	size_t GetFilesNumInDatFile();
 
   	size_t PatchAllFilesFromDatabase(Database& db);
-	void PatchFile(SubfileData file_data);
-  	void PatchFile(int file_id, FILE_TYPE type, std::string path_to_file);
+	void PatchFile(SubfileData file_data, int version = -1, int iteration = -1);
+  	void PatchFile(int file_id, FILE_TYPE type, std::string path_to_file, int version = -1, int iteration = -1);
 
 	FILE_TYPE GetExistingFileType(int file_id);
 	void PerformOperationOnAllSubfiles(const SubfileOperation& operation);
@@ -47,11 +49,14 @@ class DatFile {
   	void ExportFileById(int file_id, Database& db);
 	void ExportFileById(int file_id, std::string target_file_path);
 
+	int GetFileVersion(int file_id);
+	SubfileData GetFile(int file_id);
+
   private:
   	static DatExportApi api_;
   	int file_handle_;
   	bool initialized_;
-	std::set<SubfileInfo> files_info_;
+	std::map<int, SubfileInfo> files_info_;
 	std::string filename_;
 
   	BinaryData export_data_buf_;

+ 11 - 0
src/database.cpp

@@ -6,6 +6,13 @@
 #include <SQLite/lotrodat_sqlite3.h>
 #include <yaml-cpp/yaml.h>
 
+#ifdef _WIN32
+   #include <io.h> 
+   #define access    _access_s
+#else
+   #include <unistd.h>
+#endif
+
 
 namespace LOTRO_DAT {
 Database::Database() {
@@ -38,6 +45,10 @@ Database::~Database() {
 
 bool Database::InitDatabase(const std::string &filename) {
   LOG(DEBUG) << "Initializing database " << filename;
+  if (access(filename.c_str(), 0 ) != 0) {
+    LOG(ERROR) << "Cannot init database: file with name " << filename << " does not exist!";
+    return false;
+  }
 
   CloseDatabase();
   if (lotrodat_sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {

+ 54 - 10
src/datfile.cpp

@@ -45,9 +45,14 @@ DatFile::~DatFile() {
 }
 
 bool DatFile::Init(const std::string& filename) {
+    if (initialized_) {
+        Deinit();
+    }
+
     if (api_.OpenDatFile(file_handle_, filename.c_str(), 130) == file_handle_) {
         initialized_ = true;
         filename_ = filename;
+        LoadAllFilesInfo();
         return true;  
     }
 
@@ -59,13 +64,14 @@ void DatFile::LoadAllFilesInfo() {
     for (int i = 0; i < subfiles_num; ++i) {
         SubfileInfo file_info;
         api_.GetSubfileSizes(file_handle_, &file_info.file_id, &file_info.size, &file_info.iteration, i, 1);
-        files_info_.insert(file_info);
+        files_info_[file_info.file_id] = file_info;
     }
 }
 
 void DatFile::Deinit() {
     if (initialized_) {
         api_.CloseDatFile(file_handle_);
+        files_info_.clear();
         initialized_ = false;
     }
 }
@@ -78,6 +84,13 @@ const std::string& DatFile::GetFilename() const {
     return filename_;
 }
 
+SubfileInfo DatFile::getSubfileInfo(int file_id) const {
+    if (files_info_.count(file_id) == 0) {
+        return SubfileInfo();
+    } else {
+        return files_info_.at(file_id);
+    }
+}
 
 size_t DatFile::GetFilesNumInDatFile() {
     return api_.GetNumSubfiles(file_handle_);
@@ -107,21 +120,41 @@ size_t DatFile::PatchAllFilesFromDatabase(Database& db) {
     return patched_files_num;
 }
 
-void DatFile::PatchFile(SubfileData file_data) {
+void DatFile::PatchFile(SubfileData file_data, int version, int iteration) {
+    if (!file_data.options["fid"]) {
+        LOG(ERROR) << "Trying to patch file, but file id is not specified, skipping!";
+        return;
+    }
     int file_id = file_data.options["fid"].as<int>();
-    int version = 0;
-    int size = api_.GetSubfileData(file_handle_, file_id, export_data_buf_.data(), version);
+
+    if (files_info_.count(file_id) == 0) {
+        LOG(ERROR) << "Trying to patch file, not existing in files_info. File id = " << file_id;
+        return;
+    }
+    const SubfileInfo& file_info = files_info_[file_id];
+
+    int existing_file_version = 0; // will be evaluated with api_.GetSubfileData
+    int size = api_.GetSubfileData(file_handle_, file_id, export_data_buf_.data(), existing_file_version);
     if (size <= 0) {
         LOG(ERROR) << "Trying to patch file, not existing in .dat file. File id = " << file_id;
         return;
     }
     BinaryData old_data = export_data_buf_.CutData(0, size);  
-
+    
     BinaryData file = BuildForImport(old_data, file_data);
-    api_.PutSubfileData(file_handle_, file_id, file.data(), 0, file.size(), 10, 99999);
+
+    if (version == -1) {
+        version = existing_file_version;
+    }
+
+    if (iteration == -1) {
+        iteration = file_info.iteration;
+    }
+
+    api_.PutSubfileData(file_handle_, file_id, file.data(), 0, file.size(), version, iteration);
 }
 
-void DatFile::PatchFile(int file_id, FILE_TYPE type, std::string path_to_file) {  
+void DatFile::PatchFile(int file_id, FILE_TYPE type, std::string path_to_file, int version, int iteration) {  
     BinaryData new_data(64 * 1024 * 1024);
     std::ifstream in(path_to_file, std::ifstream::binary);
     in.read((char*)new_data.data(), new_data.size());
@@ -133,7 +166,7 @@ void DatFile::PatchFile(int file_id, FILE_TYPE type, std::string path_to_file) {
     imported_subfile.options["ext"] = StringFromFileType(type);
     imported_subfile.options["fid"] = file_id;
 
-    PatchFile(imported_subfile);
+    PatchFile(imported_subfile, version, iteration);
 }
 
 FILE_TYPE DatFile::GetExistingFileType(int file_id) {
@@ -148,11 +181,11 @@ void DatFile::PerformOperationOnAllSubfiles(const SubfileOperation& operation) {
     }
     std::cout << "Performing operation on all files...";
     int i = 0;
-    for (const SubfileInfo& info : files_info_) {
+    for (const std::pair<int, SubfileInfo>& info : files_info_) {
         if (i * 100 / files_info_.size() != (i - 1) * 100 / files_info_.size()) {
             std::cout << "Completed " << i * 100 / files_info_.size() << "%" << std::endl;
         }
-        operation(info);
+        operation(info.second);
         ++i;
     }
 }
@@ -207,4 +240,15 @@ void DatFile::ExportFileById(int file_id, Database& db) {
     db.PushFile(file);
 }
 
+int DatFile::GetFileVersion(int file_id) {
+    return api_.GetSubfileVersion(file_handle_, file_id);
+}
+
+SubfileData DatFile::GetFile(int file_id) {
+    int version = 0;
+    int size = api_.GetSubfileData(file_handle_, file_id, export_data_buf_.data(), version);
+    auto data = export_data_buf_.CutData(0, size);
+    return BuildForExport(file_id, data);
+}
+
 }; // namespace LOTRO_DAT

+ 0 - 11
src/utils/inserter.cpp

@@ -18,17 +18,6 @@ void InitializeFileLoop(DatFile& file) {
         std::string filename;
         std::getline(std::cin, filename);
 
-        // std::cout << "Enter file id: ";
-        // std::string file_id_str;
-        // std::getline(std::cin, file_id_str);
-        // int file_id = 0;
-        // try {
-        //     file_id = stoi(file_id_str);
-        // } catch (std::invalid_argument) {
-        //     std::cout << "Invalid dat file id entered!\n\n";
-        //     continue;
-        // }
-
         std::cout << "Opening file " << filename << std::endl;
 
         bool result = file.Init(filename); // TODO: INIT WITH DAT FILE ID

+ 2 - 2
src/utils/single_file_import_export.cpp

@@ -11,9 +11,9 @@ int main() {
     FILE_TYPE file_type = FILE_TYPE::UNKNOWN;
 
     std::cout << "Enter path to .dat file: ";
-    std::cin >> dat_file_path;
+    std::getline(std::cin, dat_file_path);
 
-     DatFile file(0);
+    DatFile file(0);
     if (!file.Init(dat_file_path)) {
         std::cout << "Failed to open .dat file!" << std::endl;
         system("pause");