Ivan Arkhipov пре 6 година
родитељ
комит
f53738f25a

+ 3 - 0
CHANGELOG

@@ -35,4 +35,7 @@ Version 4.0.0
 Version 4.1.0
     * Some minor fixes and stability improvements, which should cause less library critical errors.
 ----------------------------------------------------------------------
+Version 4.2.0
+    * Fixed critical bug, which caused .dat file corruption, if 2 different texts less than 256 bytes size were patched with different versions.
+----------------------------------------------------------------------
 

BIN
bin/LotRO_dat_extractor.exe


BIN
bin/LotRO_dat_patcher.exe


+ 2 - 2
include/DatFile.h

@@ -108,7 +108,7 @@ namespace LOTRO_DAT {
 
         DAT_RESULT PatchFile(const char *filename, YAML::Node options);
 
-        DAT_RESULT PatchFile(const SubfileData &data, bool rewrite_original = false);
+        DAT_RESULT PatchFile(const SubfileData &data);
 
         DAT_RESULT PatchAllDatabase(Database *db);
 
@@ -142,7 +142,7 @@ namespace LOTRO_DAT {
 
         // PATCH SECTION
 
-        DAT_RESULT ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original = false);
+        DAT_RESULT ApplyFilePatch(Subfile *file, const BinaryData &data);
 
         std::vector<std::pair<long long, long long> > GetFragmentationJournal();
 

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 33 - 27
src/DatFile.cpp

@@ -313,9 +313,9 @@ namespace LOTRO_DAT {
     }
 
     // TODO: Write description and make asserts
-    DAT_RESULT DatFile::PatchFile(const SubfileData &data, bool rewrite_original) {
-        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>()
-                   << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
+    DAT_RESULT DatFile::PatchFile(const SubfileData &data) {
+        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>() << ".";
+
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
             return INCORRECT_STATE_ERROR;
@@ -329,10 +329,15 @@ namespace LOTRO_DAT {
             return NO_FILE_ERROR;
         }
 
+        if (!CorrectSubfile(file)) {
+            LOG(ERROR) << "Incorrect subfile with id " << file->file_id() << " (headers do not match). Cannot patch it";
+            return FAILED;
+        }
+
         // If file has inactive category, then we should set it to patched state in order to commit patch and
         // then in ApplyFilePatch(), if new category is still inactive, return dictionary to its original state;
 
-        if (inactive_categories.count(file->category) != 0 && patch_dict_.count(file_id) != 0) {
+        if (inactive_categories.count(file->category) != 0 && patch_dict_.count(file_id) != 0 && file_id != 2013266257) {
             dictionary_[file_id]->file_offset_ = patch_dict_[file_id]->file_offset_;
             dictionary_[file_id]->file_size_ = patch_dict_[file_id]->file_size_;
             dictionary_[file_id]->block_size_ = patch_dict_[file_id]->block_size_;
@@ -354,15 +359,14 @@ namespace LOTRO_DAT {
 
         BinaryData patch_data = file->MakeForImport(old_data, data);
         try {
-            DAT_RESULT result = ApplyFilePatch(file, patch_data, rewrite_original);
+            DAT_RESULT result = ApplyFilePatch(file, patch_data);
             if (result != SUCCESS)
                 return result;
         } catch (std::exception &e) {
             LOG(ERROR) << "Caught " << e.what() << " exception";
             return FAILED;
         }
-        LOG(DEBUG) << "Patched successfully file " << data.options["fid"].as<long long>()
-                   << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
+        LOG(DEBUG) << "Patched successfully file " << data.options["fid"].as<long long>() << ".";
         return SUCCESS;
     }
 
@@ -615,8 +619,13 @@ namespace LOTRO_DAT {
 
     /// Special functions used by patch process.
     /// Shouldn't be used by any external class.
-    DAT_RESULT DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original) {
+    DAT_RESULT DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data) {
         LOG(DEBUG) << "Applying " << file->file_id() << " patch.";
+        if (data.Empty()) {
+            LOG(ERROR) << "Error caused during making file for import. Cannot patch file " << file->file_id();
+            return FAILED;
+        }
+
         auto file_id = file->file_id();
         if (patched_list.count(file_id) != 0) {
             LOG(WARNING) << "Warning: DatFile::ApplyFilePatch - found 2 files in patch with the same file_id = "
@@ -624,43 +633,40 @@ namespace LOTRO_DAT {
             return DUBLICATE_PATCH_FILES_ERROR;
         }
 
-        if (current_locale() != PATCHED && !rewrite_original) {
+        if (current_locale() != PATCHED && file_id != 2013266257) {
             LOG(INFO) << "Changing locale to PATCHED(RU) in order to patch file";
             SetLocale(PATCHED);
         }
 
-        if (current_locale() == PATCHED && rewrite_original && patch_dict_.count(file_id) != 0) {
-            LOG(INFO) << "Changing locale to ORIGINAL in order to patch original version of file, which has both "
-                      << "original and patched versions.";
-            SetLocale(ORIGINAL);
-        }
-
         dat_state_ = UPDATED;
 
-        if (orig_dict_.count(file_id) == 0 && !rewrite_original) {
+        if (orig_dict_.count(file_id) == 0 && file_id != 2013266257) {
             orig_dict_[file_id] = new Subfile(this, file->MakeHeaderData());
         }
 
         auto journal = GetFragmentationJournal();
 
-        file->file_size_ = data.size() - 8;
-
-        if ((patch_dict_.count(file_id) == 0 && !rewrite_original) || data.size() + 8 > file->block_size()) {
+        if ((patch_dict_.count(file_id) == 0 && file_id != 2013266257)
+            || data.size() > file->block_size() || file->file_size() + 8 > file->block_size()) {
             if (journal[0].second != file_size_) {
                 journal[0].second = file_size_;
             }
 
+            file->file_size_ = data.size() - 8;
             file->file_offset_ = journal[0].second;
-            file->block_size_ = std::max(data.size(), 256u);
+            file->block_size_ = std::max((long long)data.size(), file->block_size_);
 
-            journal[0].second += data.size();
+            journal[0].second += file->block_size_;
 
-            BinaryData nulls(data.size());
+            BinaryData nulls((unsigned)file->block_size_);
             WriteData(nulls, nulls.size(), file_size_);
 
-            this->file_size_ += data.size();
+            this->file_size_ += file->block_size_;
         }
 
+        file->file_size_ = data.size() - 8;
+        file->block_size_ = std::max(file->block_size_, file->file_size_ + 8);
+
         BinaryData fragments_count(4);
         fragments_count = BinaryData::FromNumber<4>(0);
 
@@ -675,7 +681,7 @@ namespace LOTRO_DAT {
 
         patched_list.insert(file_id);
 
-        if (!rewrite_original) {
+        if (file_id != 2013266257) {
             patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
             patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
         }
@@ -689,9 +695,9 @@ namespace LOTRO_DAT {
             dictionary_[file_id]->version_ = orig_dict_[file_id]->version_;
         }
 
-        if (orig_dict_.count(file_id) != 0)
+        if (orig_dict_.count(file_id) != 0 && file_id != 2013266257)
             orig_dict_[file_id]->category = file->category;
-        if (patch_dict_.count(file_id) != 0)
+        if (patch_dict_.count(file_id) != 0 && file_id != 2013266257)
             patch_dict_[file_id]->category = file->category;
 
         UpdateFragmentationJournal(journal);
@@ -1106,7 +1112,7 @@ namespace LOTRO_DAT {
             current_size += 4;
         }
 
-        DAT_RESULT result = PatchFile(data, true);
+        DAT_RESULT result = PatchFile(data);
         if (result != SUCCESS)
             return result;
 

+ 1 - 1
src/Examples/extractor_example.cpp

@@ -31,7 +31,7 @@ bool exportUnknownToDb = false;
 // There is no need to change anything else
 
 int main() {
-    std::cout << "Gi1dor's LotRO .dat extractor ver. 4.0.0" << std::endl;
+    std::cout << "Gi1dor's LotRO .dat extractor ver. 4.2.0" << std::endl;
 
     std::cout << "Hello! I'm a basic shell version of .dat file extractor. I can open .dat file directly, "
             "if you write path to it (with name of file) in file \"dat_file_path.txt\"\n";

+ 1 - 1
src/Examples/patcher_example.cpp

@@ -15,7 +15,7 @@ using namespace LOTRO_DAT;
 using namespace std;
 
 int main() {
-    std::cout << "Gi1dor's LotRO .dat patcher ver. 4.1.0" << std::endl;
+    std::cout << "Gi1dor's LotRO .dat patcher ver. 4.2.0" << std::endl;
     freopen("patcher_errors.log", "w", stderr);
 
     setbuf(stdout, nullptr);