Ivan Arkhipov 6 vuotta sitten
vanhempi
commit
99bb037dac

+ 5 - 1
CHANGELOG

@@ -27,8 +27,12 @@ Version 3.2.0
 Version 3.3.0
     * Added check and repair functions for situation, when .dat file was patched by LotRO launcher because of official update
 ----------------------------------------------------------------------
-Version 4.0.0 (ALPHA)
+Version 4.0.0
     * Refactored most functions of DatFile class - they throw much less exceptions and base on returning special error values
     * Added Easylogging++ library and implememted it fully in DatFile class
     * Improved stability and constantly of library with using ordered locale sets and maps
 ----------------------------------------------------------------------
+Version 4.1.0
+    * Some minor fixes and stability improvements, which should cause less library critical errors.
+----------------------------------------------------------------------
+

+ 1 - 2
CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.8)
 project(LotRO_dat_library)
 
-set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD 14)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 0.1.0)
 
@@ -25,7 +25,6 @@ SET(LIBRARY_OUTPUT_PATH ${CMAKE_OUTPUT_DIR})
 
 set(HEADER_FILES
     ${CMAKE_SOURCE_DIR}/include/BinaryData.h
-    ${CMAKE_SOURCE_DIR}/include/CommonFunctions.h
     ${CMAKE_SOURCE_DIR}/include/Database.h
     ${CMAKE_SOURCE_DIR}/include/DatException.h
     ${CMAKE_SOURCE_DIR}/include/DatFile.h

BIN
bin/LotRO_dat_extractor.exe


BIN
bin/LotRO_dat_patcher.exe


+ 5 - 4
include/BinaryData.h

@@ -28,19 +28,20 @@ namespace LOTRO_DAT
 
         bool operator == (const BinaryData &b) const;
         bool operator != (const BinaryData &b) const;
+        bool Empty() const;
 
         void Append(const BinaryData &b, size_t offset = 0);
 
-        template <int T>
+        template <unsigned int T>
         long long ToNumber(const long long &pos) const;
 
-        template <int T>
+        template <unsigned int T>
         long long ToNumberRAW(const long long &pos) const;
 
-        template <int T>
+        template <unsigned int T>
         static BinaryData FromNumber(const long long &number);
 
-        template <int T>
+        template <unsigned int T>
         static BinaryData FromNumberRAW(const long long &number);
 
         size_t size() const;

+ 0 - 39
include/CommonFunctions.h

@@ -1,39 +0,0 @@
-#ifndef COMMON_FUNCTIONS_H
-#define COMMON_FUNCTIONS_H
-
-#include <string>
-#include <uchar.h>
-#include <codecvt>
-#include <locale>
-
-inline long long mstrlen(const char16_t *s) {
-	return sizeof(s) / sizeof(*s);
-}
-
-inline std::string u16stringToBytes(const std::u16string& str)
-{
-#if defined(_MSC_VER)
-	auto p = reinterpret_cast<unsigned short const*>(str.data());
-	auto out = std::wstring_convert<std::codecvt_utf16<unsigned short>, unsigned short>().to_bytes(p, p + str.size());
-	return out;
-#else
-	std::wstring_convert<std::codecvt_utf16<char16_t>, char16_t> conv;
-	return conv.to_bytes(str);
-#endif
-}
-
-inline std::u16string bytesToU16string(const std::string& str)
-{
-#if defined(_MSC_VER)
-	std::u16string out;
-	auto s = std::wstring_convert<std::codecvt_utf16<unsigned short>, unsigned short>().from_bytes(str);
-	auto p = reinterpret_cast<wchar_t const*>(s.data());
-	out.assign(p, p + s.size());
-	return out;
-#else
-	std::wstring_convert<std::codecvt_utf16<char16_t>, char16_t> conv;
-	return conv.from_bytes(str);
-#endif
-}
-
-#endif

+ 0 - 3
include/DatException.h

@@ -15,7 +15,6 @@ extern  "C++"
 namespace LOTRO_DAT
 {
     enum DAT_EXCEPTION_TYPE {
-        INIT_EXCEPTION,
         READ_EXCEPTION,
         WRITE_EXCEPTION,
         SUBDIR_EXCEPTION,
@@ -24,8 +23,6 @@ namespace LOTRO_DAT
         EXPORT_EXCEPTION,
         DATA_EXCEPTION,
         DATABASE_EXCEPTION,
-        LOCALE_EXCEPTION,
-        NOFILE_EXCEPTION,
         UNKNOWN_EXCEPTION
     };
 

+ 11 - 8
include/DatFile.h

@@ -22,12 +22,6 @@
 
 // Dat file names definitions
 
-#define CLIENT_LOCAL_ENGLISH 0
-#define CLIENT_GENERAL 1
-#define CLIENT_SOUND 2
-#define CLIENT_SURFACE 3
-#define CLIENT_HIGHRES 4
-
 extern "C++"
 {
 namespace LOTRO_DAT {
@@ -59,16 +53,22 @@ namespace LOTRO_DAT {
         FALSE = 0,
         TRUE = 1,
 
+        //----WARNINGS----//
+        CORRUPTED_FILE_WARNING = 2,
+
+        //----ERRORS----//
         INCORRECT_STATE_ERROR = -1,
         NO_FILE_ERROR = -2,
         WRITE_TO_FILE_ERROR = -3,
-
         INCORRECT_DAT_ID = -4,
         INCORRECT_SUPERBLOCK_ERROR = -5,
         INIT_ERROR = -6,
-        DAT_READ_ERROR = -7,
         DUBLICATE_PATCH_FILES_ERROR = -8,
         INCORRECT_PATCH_FILE = -9,
+        DAT_PATCH_FILE_ERROR = -10,
+        DAT_READ_ERROR = -11,
+        DAT_WRITE_ERROR = -12,
+        CRITICAL_DAT_ERROR = -14
     };
 
     enum DAT_STATE {
@@ -161,6 +161,9 @@ namespace LOTRO_DAT {
     public:
         DAT_RESULT SetLocale(LOCALE locale);
 
+        DAT_RESULT RepairDatFile();
+        bool CorrectSubfile(Subfile *file);
+
         bool CheckIfUpdatedByGame();
 
         DAT_RESULT RepairPatches(Database *db);

+ 1 - 1
include/SubfileData.h

@@ -18,7 +18,7 @@ namespace LOTRO_DAT {
             options = YAML::Node();
         }
 
-        SubfileData(const BinaryData &binary_data_, const std::u16string &text_data_, const YAML::Node options_) {
+        SubfileData(const BinaryData &binary_data_, const std::u16string &text_data_, const YAML::Node &options_) {
             binary_data = binary_data_;
             text_data = text_data_;
             options = options_;

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 9 - 6
src/BinaryData.cpp

@@ -57,7 +57,7 @@ namespace LOTRO_DAT {
     }
 
     // Translates T bytes from data into number using UTF-16LE encoding of the .dat file
-    template<int T>
+    template<unsigned int T>
     long long BinaryData::ToNumber(const long long &pos) const {
         try {
             long long ans = 0;
@@ -75,7 +75,7 @@ namespace LOTRO_DAT {
     }
 
     // Translates T bytes from data into number in raw format
-    template<int T>
+    template<unsigned int T>
     long long BinaryData::ToNumberRAW(const long long &pos) const {
         try {
             long long ans = 0;
@@ -83,7 +83,7 @@ namespace LOTRO_DAT {
             if (pos + T >= size_)
                 throw DatException("Bad BinaryData::ToNumber(). Reached end of BinaryData!", DATA_EXCEPTION);
 
-            for (int i = 0; i < T; i++)
+            for (unsigned i = 0; i < T; i++)
                 ans = ((ans << 8ll) | data_[pos + i]);
 
             return ans;
@@ -93,7 +93,7 @@ namespace LOTRO_DAT {
     }
 
     // Makes data from specified T bytes of number in Little Endian encoding
-    template<int T>
+    template<unsigned int T>
     BinaryData BinaryData::FromNumber(const long long &number) {
         if (T < 0)
             throw DatException("Bad BinaryData::FromNumber() - trying to make data from amount of bytes < 0");
@@ -108,7 +108,7 @@ namespace LOTRO_DAT {
     }
 
     // Makes data from specified T bytes of number in raw
-    template<int T>
+    template<unsigned int T>
     BinaryData BinaryData::FromNumberRAW(const long long &number) {
         if (T <= 0)
             throw DatException("Bad BinaryData::FromNumber() - trying to make data from amount of bytes <= 0");
@@ -165,7 +165,6 @@ namespace LOTRO_DAT {
         return WriteToFile(filename.c_str());
     }
 
-
     void BinaryData::ReadFromFile(const char *filename) {
         FILE *f;
         fopen_s(&f, filename, "rb");
@@ -252,6 +251,10 @@ namespace LOTRO_DAT {
         return !(*this == b);
     }
 
+    bool BinaryData::Empty() const {
+        return size_ == 0;
+    }
+
     void BinaryData::Append(const BinaryData &b, size_t append_offset) {
         if (append_offset + b.size() > size())
             throw DatException("Bad Binary:Data::Append() - data for appending has more bytes than BinaryData size!", DATA_EXCEPTION);

+ 134 - 49
src/DatFile.cpp

@@ -3,16 +3,19 @@
 //
 
 #include "DatFile.h"
-
 #include "BinaryData.h"
+
 #include "DatException.h"
 #include "SubDirectory.h"
 #include "Subfile.h"
 #include "SubfileData.h"
 
-#include "EasyLogging++/easylogging++.h"
+#include <EasyLogging++/easylogging++.h>
+#include <unistd.h>
+
 #define ELPP_FEATURE_CRASH_LOG
 INITIALIZE_EASYLOGGINGPP
+
 #include <locale>
 
 #ifdef WIN32
@@ -31,7 +34,8 @@ namespace LOTRO_DAT {
 
         el::Configurations defaultConf;
         defaultConf.setToDefault();
-        defaultConf.setGlobally(el::ConfigurationType::Format, "%datetime %level %fbase (line %line) : %msg (function: %func)");
+        defaultConf.setGlobally(el::ConfigurationType::Format,
+                                "%datetime %level %fbase (line %line) : %msg (function: %func)");
         defaultConf.setGlobally(el::ConfigurationType::ToFile, "true");
         defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
         defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
@@ -70,6 +74,7 @@ namespace LOTRO_DAT {
         filename_ = "none";
 
         DAT_RESULT result;
+        DAT_RESULT return_value = SUCCESS;
 
         result = OpenDatFile(filename.c_str());
         if (result != SUCCESS) {
@@ -77,39 +82,49 @@ namespace LOTRO_DAT {
             CloseDatFile();
             return result;
         }
+        return_value = std::max(return_value, result);
 
         result = ReadSuperBlock();
-        if (result != SUCCESS) {
+        if (result <= 0) {
             LOG(ERROR) << "Unable to read super block. Aborting.";
             CloseDatFile();
             return result;
         }
+        return_value = std::max(return_value, result);
 
         result = MakeDirectories();
-        if (result != SUCCESS) {
+        if (result <= 0) {
             LOG(ERROR) << "Unable to make directories. Aborting.";
             CloseDatFile();
             return result;
         }
+        return_value = std::max(return_value, result);
 
         result = MakeDictionary();
-        if (result != SUCCESS) {
+        if (result <= 0) {
             LOG(ERROR) << "Unable to make dictionary. Aborting.";
             CloseDatFile();
             return result;
         }
+        return_value = std::max(return_value, result);
 
         result = InitLocales();
-        if (result != SUCCESS) {
+        if (result <= 0) {
             LOG(ERROR) << "Unable to initialize locales. Aborting.";
             CloseDatFile();
             return result;
         }
+        return_value = std::max(return_value, result);
 
+        if (return_value >= 2) {
+            LOG(WARNING) << "Dat file is corrupted. Trying to delete corrupted dictionary rows";
+            if (RepairDatFile() != SUCCESS)
+                return CRITICAL_DAT_ERROR;
+        }
         LOG(INFO) << "File " << filename << " opened successfully!";
         filename_ = filename;
         dat_state_ = READY;
-        return SUCCESS;
+        return return_value;
     }
 
     DAT_STATE DatFile::DatFileState() const {
@@ -222,8 +237,9 @@ namespace LOTRO_DAT {
         int success = 0;
         for (auto i : dictionary_) {
             FILE_TYPE file_type = i.second->FileType();
-            if (file_type  == type) {
-                success += (ExtractFile(i.second->file_id(), (path + std::to_string(i.second->file_id()))) == SUCCESS ? 1 : 0);
+            if (file_type == type) {
+                success += (ExtractFile(i.second->file_id(), (path + std::to_string(i.second->file_id()))) == SUCCESS
+                            ? 1 : 0);
             }
         }
         LOG(INFO) << "Successfully extracted " << success << " files";
@@ -246,7 +262,7 @@ namespace LOTRO_DAT {
         int success = 0;
         for (auto i : dictionary_) {
             FILE_TYPE file_type = i.second->FileType();
-            if (file_type  == type) {
+            if (file_type == type) {
                 success += (ExtractFile(i.second->file_id(), db) == SUCCESS ? 1 : 0);
             }
         }
@@ -271,11 +287,16 @@ namespace LOTRO_DAT {
         auto file_id = options["fid"].as<long long>();
 
         if (dictionary_[file_id] == nullptr) {
-            LOG(ERROR) <<  "Cannot patch file - there is no file in dictionary with file_id = " << file_id;
+            LOG(ERROR) << "Cannot patch file - there is no file in dictionary with file_id = " << file_id;
             return NO_FILE_ERROR;
         }
 
         BinaryData old_data = GetFileData(dictionary_[file_id]);
+        if (old_data.Empty()) {
+            LOG(ERROR) << "GetFileData returned empty data. Aborting.";
+            return DAT_PATCH_FILE_ERROR;
+        }
+
         data = dictionary_[file_id]->MakeForImport(old_data, SubfileData(data, u"", options));
 
         try {
@@ -283,16 +304,18 @@ namespace LOTRO_DAT {
             if (result != SUCCESS)
                 return result;
         } catch (std::exception &e) {
-            LOG(ERROR) << "Caught " << e.what() <<" exception.";
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
             return FAILED;
         }
-        LOG(DEBUG) << "Successfully patched file with filename = " << filename << " and id = " << options["fid"].as<long long>();
+        LOG(DEBUG) << "Successfully patched file with filename = " << filename << " and id = "
+                   << options["fid"].as<long long>();
         return SUCCESS;
     }
 
     // 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." : ".");
+        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>()
+                   << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
             return INCORRECT_STATE_ERROR;
@@ -324,6 +347,11 @@ namespace LOTRO_DAT {
         }
 
         BinaryData old_data = GetFileData(file);
+        if (old_data.Empty()) {
+            LOG(ERROR) << "GetFileData returned empty data. Aborting.";
+            return DAT_PATCH_FILE_ERROR;
+        }
+
         BinaryData patch_data = file->MakeForImport(old_data, data);
         try {
             DAT_RESULT result = ApplyFilePatch(file, patch_data, rewrite_original);
@@ -333,7 +361,8 @@ namespace LOTRO_DAT {
             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>()
+                   << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
         return SUCCESS;
     }
 
@@ -352,7 +381,7 @@ namespace LOTRO_DAT {
             DAT_RESULT result = PatchFile(data);
             if (result != SUCCESS)
                 LOG(ERROR) << "Cannot patch file" << data.options["fid"].as<long long>() << " continuing";
-                data = db->GetNextFile();
+            data = db->GetNextFile();
         }
         DAT_RESULT result = CommitChanges();
         if (result != SUCCESS)
@@ -400,11 +429,19 @@ namespace LOTRO_DAT {
         try {
             BinaryData mfile_id(20);
             ReadData(mfile_id, 20, file->file_offset() + 8);
+            if (mfile_id.Empty()) {
+                LOG(ERROR) << "Error while reading file " << file->file_id() << " header (offset = "
+                           << file->file_offset() << "); Aborting.";
+                return BinaryData(0);
+            }
+            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 BinaryData(0);
+            }
 
-            if (!mfile_id.CheckCompression() && file->file_id() != mfile_id.ToNumber<4>(0))
-                throw DatException("Bad DatFile::GetFileData() - file_id in Subfile doesn't match to file_id in DatFile.", READ_EXCEPTION);
-
-            BinaryData data((unsigned)(file->file_size() + (8 - offset)));
+            BinaryData data((unsigned) (file->file_size() + (8 - offset)));
             if (file->block_size() >= file->file_size() + 8) {
                 ReadData(data, file->file_size() + (8 - offset), file->file_offset() + offset);
                 return data;
@@ -417,22 +454,24 @@ namespace LOTRO_DAT {
 
             long long current_block_size = file->block_size() - offset - 8 * fragments_number;
 
-            ReadData(data, current_block_size , file->file_offset() + offset);
+            ReadData(data, current_block_size, file->file_offset() + offset);
 
             BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-            ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file->file_offset() + file->block_size() - 8 * fragments_number);
+            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);
-                ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset, current_block_size );
+                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 data;
         } catch (std::exception &e) {
-            LOG(ERROR) << "Caught " << e.what() << "exception";
+            LOG(ERROR) << "Caught " << e.what() << " exception";
         }
         return BinaryData(0);
     }
@@ -491,7 +530,9 @@ namespace LOTRO_DAT {
 
         if (file_size_ != size1) {
             LOG(ERROR) << "variable at 0x148 position is not equal to .dat file size!";
-            return INCORRECT_SUPERBLOCK_ERROR;
+            file_size_ = size1;
+            dat_state_ = SUCCESS_SUPERBLOCK;
+            return CORRUPTED_FILE_WARNING;
         }
 
         dat_state_ = SUCCESS_SUPERBLOCK;
@@ -533,17 +574,22 @@ namespace LOTRO_DAT {
     DAT_RESULT DatFile::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) {
         if (dat_state_ == CLOSED) {
             LOG(ERROR) << "Dat state is CLOSED. Cannot read data.";
-            throw DatException("", READ_EXCEPTION);
+            data = BinaryData(0);
+            return INIT_ERROR;
         }
 
         if (data_offset + size > data.size()) {
-            LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset << " position.";
-            throw DatException("", READ_EXCEPTION);
+            LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset
+                       << " position.";
+            data = BinaryData(0);
+            return DAT_READ_ERROR;
         }
 
         if (offset + size > file_size_) {
-            LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset << " position.";
-            throw DatException("", READ_EXCEPTION);
+            LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset
+                       << " position.";
+            data = BinaryData(0);
+            return DAT_READ_ERROR;
         }
 
         fseek(file_handler_, offset, SEEK_SET);
@@ -557,9 +603,11 @@ namespace LOTRO_DAT {
             return INCORRECT_STATE_ERROR;
         }
 
-       fseek(file_handler_, offset, SEEK_SET);
-        if (data_offset + size > data.size())
-            throw DatException("Bad DatFile::WriteData - trying to write more than BinaryData size", WRITE_EXCEPTION);
+        fseek(file_handler_, offset, SEEK_SET);
+        if (data_offset + size > data.size()) {
+            LOG(ERROR) << "Trying to write more than BinaryData size";
+            return DAT_WRITE_ERROR;
+        }
 
         fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
         return SUCCESS;
@@ -736,15 +784,18 @@ namespace LOTRO_DAT {
         pending_patch_.clear();
 
         current_locale_ = ORIGINAL;
-        filename_ = "none";
 
-        if (file_handler_ != nullptr)
+        if (file_handler_ != nullptr) {
             fclose(file_handler_);
+        }
 
         delete root_directory_;
 
-        patched_list.clear();
         dictionary_.clear();
+        patched_list.clear();
+
+        truncate64(filename_.c_str(), file_size_);
+        filename_ = "none";
 
         dat_state_ = CLOSED;
         LOG(INFO) << "File closed successfully.";
@@ -761,13 +812,13 @@ namespace LOTRO_DAT {
             dicts_data = GetFileData(dictionary_[2013266257]);
 
         if (dicts_data.size() < 29) {
-            LOG(WARNING) << "locales file is empty.. Initialising locale dicts as empty";
-            LOG(INFO) << "Could't find locales file... Continuing without them";
+            LOG(WARNING) << "Locales file is empty.. Initialising locale dicts as empty";
+            LOG(INFO) << "Could't find locales file or it's corrupted/empty... Continuing without locales";
             return SUCCESS;
         }
 
         BinaryData hi_data = dicts_data.CutData(14, 29) + BinaryData("\0", 1);
-        std::string hi = std::string((char*)(hi_data.data()));
+        std::string hi = std::string((char *) (hi_data.data()));
         LOG(DEBUG) << "hi info is " << hi;
 
         if (hi != "Hi from Gi1dor!") {
@@ -778,7 +829,7 @@ namespace LOTRO_DAT {
 
         int offset = 29;
         BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
-        std::string locale((char*)(current_locale_data.data()));
+        std::string locale((char *) (current_locale_data.data()));
         offset += 4;
         LOG(DEBUG) << "current locale:" << locale;
 
@@ -855,6 +906,38 @@ namespace LOTRO_DAT {
         }
     }
 
+    bool DatFile::CorrectSubfile(Subfile *file) {
+        BinaryData mfile_id(20);
+        ReadData(mfile_id, 20, file->file_offset() + 8);
+        if (mfile_id.Empty())
+            return false;
+
+        return mfile_id.CheckCompression() || file->file_id() == mfile_id.ToNumber<4>(0);
+    }
+
+    DAT_RESULT DatFile::RepairDatFile() {
+        for (auto file : dictionary_) {
+            auto subfile = file.second;
+            auto file_id = file.first;
+
+            if (CorrectSubfile(subfile))
+                continue;
+
+            if (orig_dict_.count(file_id) == 0 || subfile->file_offset() == orig_dict_[file_id]->file_offset())
+                return CRITICAL_DAT_ERROR;
+
+            dictionary_[file_id]->file_offset_ = orig_dict_[file_id]->file_offset_;
+            dictionary_[file_id]->file_size_ = orig_dict_[file_id]->file_size_;
+            dictionary_[file_id]->block_size_ = orig_dict_[file_id]->block_size_;
+            dictionary_[file_id]->timestamp_ = orig_dict_[file_id]->timestamp_;
+            dictionary_[file_id]->version_ = orig_dict_[file_id]->version_;
+            patch_dict_.erase(file_id);
+            orig_dict_.erase(file_id);
+        }
+        return SUCCESS;
+    }
+
+
     DAT_RESULT DatFile::SetLocale(LOCALE locale) {
         LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
         if (dat_state_ < READY) {
@@ -876,7 +959,8 @@ namespace LOTRO_DAT {
                 continue;
             }
             if (dictionary_[file.first]->MakeHeaderData().CutData(8, 16) ==
-                file.second->MakeHeaderData().CutData(8, 16) || inactive_categories.count(orig_dict_[file.first]->category) != 0)
+                file.second->MakeHeaderData().CutData(8, 16) ||
+                inactive_categories.count(orig_dict_[file.first]->category) != 0)
                 continue;
 
             long long file_id = file.first;
@@ -909,13 +993,13 @@ namespace LOTRO_DAT {
 
         for (auto i : dictionary_) {
             long long file_id = i.first;
-            Subfile* subfile = i.second;
+            Subfile *subfile = i.second;
             if (inactive_categories.count(subfile->category) > 0)
                 continue;
             if (patch_dict_.count(file_id) > 0
                 && (subfile->file_size() != patch_dict_[file_id]->file_size()
-                || subfile->file_offset() != patch_dict_[file_id]->file_offset()
-                || subfile->block_size() != patch_dict_[file_id]->block_size())) {
+                    || subfile->file_offset() != patch_dict_[file_id]->file_offset()
+                    || subfile->block_size() != patch_dict_[file_id]->block_size())) {
                 orig_dict_.erase(file_id);
                 patch_dict_.erase(file_id);
                 pending_patch_.insert(file_id);
@@ -1075,23 +1159,24 @@ namespace LOTRO_DAT {
         return SUCCESS;
     }
 
-    const std::set<long long>& DatFile::GetInactiveCategoriesList() {
+    const std::set<long long> &DatFile::GetInactiveCategoriesList() {
         return inactive_categories;
     }
 
     bool DatFile::CheckIfNotPatched() {
-        LOG(INFO) << "DatFile " << (patch_dict_.empty() ? "HASN'T " : "HAS already") << " been patched by LEGACY launcher!";
+        LOG(INFO) << "DatFile " << (patch_dict_.empty() ? "HASN'T " : "HAS already")
+                  << " been patched by LEGACY launcher!";
         return patch_dict_.empty();
     }
 
     bool DatFile::CheckIfPatchedByOldLauncher() {
-        LOG(INFO) << "DatFile " << (dictionary_.count(620750000) == 0 ? "HASN'T " : "HAS already") << " been patched by OLD LAUNCHER!";
+        LOG(INFO) << "DatFile " << (dictionary_.count(620750000) == 0 ? "HASN'T " : "HAS already")
+                  << " been patched by OLD LAUNCHER!";
         return dictionary_.count(620750000) > 0;
     }
 
     const std::string &DatFile::filename() const {
         return filename_;
     }
-
 }
 }

+ 0 - 1
src/Database.cpp

@@ -5,7 +5,6 @@
 #include "Database.h"
 #include "DatException.h"
 #include "BinaryData.h"
-#include "CommonFunctions.h"
 #include "SubfileData.h"
 #include "EasyLogging++/easylogging++.h"
 

+ 0 - 1
src/Examples/extractor_example.cpp

@@ -1,7 +1,6 @@
 //
 // Created by Иван_Архипов on 30.10.2017.
 //
-#define _CRT_SECURE_NO_WARNINGS
 #include <iostream>
 #include <ctime>
 #include <algorithm>

+ 10 - 8
src/Examples/patcher_example.cpp

@@ -1,7 +1,6 @@
 //
 // Created by Иван_Архипов on 23.11.2017.
 //
-#define _CRT_SECURE_NO_WARNINGS
 #include <iostream>
 #include <ctime>
 #include <algorithm>
@@ -16,14 +15,14 @@ using namespace LOTRO_DAT;
 using namespace std;
 
 int main() {
-    std::cout << "Gi1dor's LotRO .dat patcher ver. 4.0.0" << std::endl;
+    std::cout << "Gi1dor's LotRO .dat patcher ver. 4.1.0" << std::endl;
     freopen("patcher_errors.log", "w", stderr);
 
-    setbuf(stdout, NULL);
-    setbuf(stderr, NULL);
+    setbuf(stdout, nullptr);
+    setbuf(stderr, nullptr);
 
-    setvbuf (stdout, NULL, _IONBF, BUFSIZ);
-    setvbuf (stderr, NULL, _IONBF, BUFSIZ);
+    setvbuf (stdout, nullptr, _IONBF, BUFSIZ);
+    setvbuf (stderr, nullptr, _IONBF, BUFSIZ);
 
     std::cout << "Hello! I'm a basic shell version of .dat file patcher. I can open .dat file directly, "
             "if you write path to it (with name of file) in file \"dat_file_path.txt\"\n";
@@ -36,8 +35,11 @@ int main() {
 
         std::cout << "Using .dat file from dat_file_path.txt...\n";
         std::cout << "Opening file " << filename << std::endl;
-
-        if (file.InitDatFile(filename, 0) == false) {
+        DAT_RESULT result = file.InitDatFile(filename, 0);
+        if (result >= 2) {
+            std::cout << "Dat file may be corrupted! It's opened, but all functions MAY WORK INCORRECTLY! It's better to DOWNLOAD CLEAR .DAT FILE\n";
+        }
+        if (result <= 0) {
             std::cout << "Dat file path from dat_file_path.txt - " << filename << " may be incorrect (cannot open "
                     "DatFile due to error. See it in errors.log)\n";
             file.CloseDatFile();

+ 8 - 7
src/SubDirectory.cpp

@@ -92,6 +92,7 @@ namespace LOTRO_DAT {
                 BinaryData mfile_id(20);
                 dat_->ReadData(mfile_id, 20, data.ToNumber<4>(i + 12) + 8);
                 if (!mfile_id.CheckCompression() && data.ToNumber<4>(i + 8) != mfile_id.ToNumber<4>(0)) {
+                    LOG(DEBUG) << "File id in file doesn't match to file_id in dictionary";
                     continue;
                 }
 
@@ -127,18 +128,18 @@ namespace LOTRO_DAT {
     }
 
     void SubDirectory::UpdateDirectories(std::unordered_set<long long> &patched_files, std::unordered_map<long long, Subfile*> &dict) {
-        for (unsigned i = 0; i < subfiles_.size(); i++) {
-            long long file_id = subfiles_[i]->file_id();
+        for (auto subfile : subfiles_) {
+            long long file_id = subfile->file_id();
 
             if (patched_files.count(file_id) != 0) {
                 BinaryData data(32);
-                dat_->ReadData(data, 32, subfiles_[i]->dictionary_offset());
+                dat_->ReadData(data, 32, subfile->dictionary_offset());
 
-                auto subfile = dict[file_id];
+                auto new_subfile = dict[file_id];
 
-                dat_->WriteData(BinaryData::FromNumber<4>(subfile->file_offset()), 4, subfiles_[i]->dictionary_offset() + 12);
-                dat_->WriteData(BinaryData::FromNumber<4>(subfile->file_size()), 4, subfiles_[i]->dictionary_offset() + 16);
-                dat_->WriteData(BinaryData::FromNumber<4>(subfile->block_size()), 4, subfiles_[i]->dictionary_offset() + 28);
+                dat_->WriteData(BinaryData::FromNumber<4>(new_subfile->file_offset()), 4, subfile->dictionary_offset() + 12);
+                dat_->WriteData(BinaryData::FromNumber<4>(new_subfile->file_size()), 4, subfile->dictionary_offset() + 16);
+                dat_->WriteData(BinaryData::FromNumber<4>(new_subfile ->block_size()), 4, subfile->dictionary_offset() + 28);
             }
         }
 

+ 3 - 4
src/Subfiles/TextSubfile.cpp

@@ -10,7 +10,6 @@
 #include "SubfileData.h"
 #include "EasyLogging++/easylogging++.h"
 
-#include <algorithm>
 #include <codecvt>
 #include <locale>
 
@@ -345,8 +344,8 @@ namespace LOTRO_DAT {
         BinaryData temp_data = BinaryData::FromNumber<4>(pieces.size());
         result = result + temp_data;
 
-        for (long long i = 0; i < pieces.size(); i++) {
-            long long piece_size = pieces[i].length();
+        for (auto piece : pieces) {
+            long long piece_size = piece.length();
             if (piece_size < 128) {
                 temp_data = BinaryData::FromNumber<1>(piece_size);
             } else {
@@ -355,7 +354,7 @@ namespace LOTRO_DAT {
             result = result + temp_data;
 
             for (long long j = 0; j < piece_size; j++) {
-                temp_data = BinaryData::FromNumber<2>(short(pieces[i][j]));
+                temp_data = BinaryData::FromNumber<2>(short(piece[j]));
                 result = result + temp_data;
             }
         }