Browse Source

Refactor: last part

Ivan Arkhipov 7 years ago
parent
commit
2cdde51f8e

+ 35 - 19
CMakeLists.txt

@@ -5,8 +5,12 @@ set(CMAKE_CXX_STANDARD 11)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 0.1.0)
 
-SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
-SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS} -static" )
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O2" )
+SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
+
+if (MSVS)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} /MT /SAFESEH:NO")
+endif(MSVS)
 
 set(CMAKE_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin)
 set(CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Source)
@@ -61,28 +65,40 @@ set(SOURCE_FILES
         ${CMAKE_SOURCE_DIR}/Subfiles/UnknownSubfile.h
         )
 
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_CXX_FLAGS_MINSIZEREL
+        CMAKE_CXX_FLAGS_RELWITHDEBINFO
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        CMAKE_C_FLAGS_MINSIZEREL
+        CMAKE_C_FLAGS_RELWITHDEBINFO
+        )
+
+foreach(CompilerFlag ${CompilerFlags})
+    string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
+endforeach()
 
 # STATIC LIBRARY
 add_library(LotroDat_static STATIC ${SOURCE_FILES})
-target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
-target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
-target_link_libraries(LotroDat_static -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
-
 # SHARED LIBRARY
 add_library(LotroDat SHARED ${SOURCE_FILES})
-target_link_libraries(LotroDat ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
-target_link_libraries(LotroDat ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
-target_link_libraries(LotroDat -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
-
-# FOR EXTRACTOR USE NEXT LINE
+# CONSOLE EXTRACTOR TOOL
 add_executable(LotRO_dat_extract_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/extract_test.cpp)
-target_link_libraries(LotRO_dat_extract_tester ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
-target_link_libraries(LotRO_dat_extract_tester ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
-target_link_libraries(LotRO_dat_extract_tester -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
-
-# FOR PATCHER USE NEXT LINE
+# CONSOLE PATCHER TOOL
 add_executable(LotRO_dat_pat_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/patch_test.cpp)
-target_link_libraries(LotRO_dat_pat_tester ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
-target_link_libraries(LotRO_dat_pat_tester ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
-target_link_libraries(LotRO_dat_pat_tester -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
 
+foreach(TARGET LotroDat_static LotroDat LotRO_dat_extract_tester LotRO_dat_pat_tester)
+    if(MSVC)
+        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Common/Zlib/zlibstatic.lib)
+        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cppmt.lib)
+        target_link_libraries(${TARGET} vcruntime.lib MSVCRT.lib)
+    else(MSVC)
+        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
+        target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
+        target_link_libraries(${TARGET} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic)
+    endif(MSVC)
+endforeach(TARGET LotroDat_static LotroDat LotRO_dat_extract_tester LotRO_dat_pat_tester)

BIN
Source/Common/Yaml/libyaml-cpp.a


BIN
Source/Common/Yaml/libyaml-cppmt.lib


+ 135 - 83
Source/DatFile.cpp

@@ -8,7 +8,6 @@
 #include "Common/DatException.h"
 #include "SubDirectory.h"
 #include "Subfile.h"
-#include "yaml-cpp/yaml.h"
 
 #include <locale>
 
@@ -58,16 +57,31 @@ namespace LOTRO_DAT {
         if (dat_state_ != READY) {
             throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
         }
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
+        BinaryData file_data;
+
+        try {
+            file_data = GetFileData(dictionary_[file_id], 8);
+        } catch (...) {
+            fprintf(stderr, "Unable to extract file due to uncaught exception while getting file data. Passing...\n");
+            return false;
+        }
+
         long long export_size = 0;
         std::vector<BinaryData> binary_data;
         std::vector<std::u16string> text_data;
         std::vector<YAML::Node> options;
-        dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
+
+        try {
+            dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
+        } catch (...) {
+            fprintf(stderr, "Unable to extract file due to uncaught exception while preparing file for export. Passing...\n");
+            return false;
+        }
 
         for (int i = 0; i < export_size; ++i) {
             binary_data[i].WriteToFile(path + "_" + std::to_string(i) + options[i]["extension"].as<std::string>());
         }
+        return true;
     }
 
     /// Extracts file with file_id to database "db".
@@ -82,16 +96,40 @@ namespace LOTRO_DAT {
             throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
         }
 
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
+        BinaryData file_data;
+
+        try {
+            file_data = GetFileData(dictionary_[file_id], 8);
+        } catch (...) {
+            fprintf(stderr, "Unable to extract file due to uncaught exception while getting file data. Passing...\n");
+            return false;
+        }
+
         long long export_size = 0;
         std::vector<BinaryData> binary_data;
         std::vector<std::u16string> text_data;
         std::vector<YAML::Node> options;
-        dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
-        // TODO: Complete this function
+
+        try {
+            dictionary_[file_id]->PrepareForExport(file_data, export_size, binary_data, text_data, options);
+        } catch (...) {
+            fprintf(stderr, "Unable to extract file due to uncaught exception while preparing file for export. Passing...\n");
+            return false;
+        }
+
+        for (int i = 0; i < export_size; ++i) {
+            std::stringstream option;
+            option << options[i];
+            try {
+                db->PushFile(binary_data[i], text_data[i], option.str());
+            } catch (...) {
+                fprintf(stderr, "Unable to put file or it's part to database. Continuing without this part. Database may be not complete\n");
+            }
+        }
+        return true;
     }
 
-    /// Extracts all files with specific type to "path + type + file_id + extension" files;
+    /// Extracts all files with specific type to "path + type + file_id + file_part + extension" files;
     /// If path is undefined then it will be recognised as current working directory
     /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
     /// Otherwise DatException() will be thrown.
@@ -105,8 +143,8 @@ namespace LOTRO_DAT {
 
         int success = 0;
         for (auto i : dictionary_) {
-            FILE_TYPE ext = i.second->FileType();
-            if (ext == type) {
+            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())));
             }
         }
@@ -125,14 +163,98 @@ namespace LOTRO_DAT {
 
         int success = 0;
         for (auto i : dictionary_) {
-            FILE_TYPE ext = i.second->FileType();
-            if (ext == type) {
+            FILE_TYPE file_type = i.second->FileType();
+            if (file_type  == type) {
                 success += ExtractFile(i.second->file_id(), db);
             }
         }
         return success;
     }
 
+    /// DatFile::WriteUnorderedDictionary(...);
+    /// Prints list of all found files with some information about them to file.
+    /// Gets std::string path - path to directory, where the file will be written with name "dict.txt"
+
+    void DatFile::WriteUnorderedDictionary(std::string path) const {
+        FILE *f;
+        fopen_s(&f, (path + "dict.txt").c_str(), "w");
+        fprintf(f, "file_id offset size size2 extension\n");
+        for (auto i : dictionary_) {
+            fprintf(f, "%lld %lld %lld %lld %s\n", i.second->file_id(), i.second->file_offset(), i.second->file_size(),
+                    i.second->block_size(), i.second->Extension().c_str());
+        }
+        fclose(f);
+    }
+
+    /// DatFile::files_number();
+    /// Returns amount of files, found in dictionaries of DatFile. Some if them may be empty or erased.
+
+    long long DatFile::files_number() const {
+        return dictionary_.size();
+    }
+
+    /// DatFile::GetFileData()
+    /// Returns BinaryData, which contains of subfile data, made from parts of file in DatFile
+
+    BinaryData DatFile::GetFileData(const Subfile *file, long long int offset) {
+        BinaryData mfile_id(4);
+        ReadData(mfile_id, 4, file->file_offset() + 8);
+        if (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()));
+        if (file->block_size() >= file->file_size() + 8) {
+            ReadData(data, file->file_size(), file->file_offset() + offset);
+            return data;
+        }
+
+        BinaryData fragments_count(4);
+        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;
+
+        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);
+
+
+        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 );
+            current_block_size += fragment_size;
+        }
+
+        return data;
+    }
+
+    /// DatFile constants' getters.
+
+    long long DatFile::constant1() const {
+        return constant1_;
+    }
+
+    long long DatFile::constant2() const {
+        return constant2_;
+    }
+
+    long long DatFile::file_size() const {
+        return file_size_;
+    }
+
+    long long DatFile::version1() const {
+        return version1_;
+    }
+
+    long long DatFile::version2() const {
+        return version2_;
+    }
+
+    /// DatFile special functions for opening and reading/writing raw data.
+    /// Shouldn't be used by any external classes except Subfile and Subdirectory.
 
     void DatFile::OpenDatFile(const char *dat_name) {
         if (dat_state_ != CLOSED)
@@ -224,7 +346,7 @@ namespace LOTRO_DAT {
         }
 
         _fseeki64(file_handler_, offset, SEEK_SET);
-        fread(data.data() + data_offset, size, 1, file_handler_);
+        fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
         data.CheckCompression();
     }
 
@@ -236,77 +358,7 @@ namespace LOTRO_DAT {
         if (data_offset + size > data.size())
             throw DatException("Bad DatFile::WriteData - trying to write more than BinaryData size", WRITE_EXCEPTION);
 
-        fwrite(data.data() + data_offset, size, 1, file_handler_);
-    }
-
-    long long DatFile::constant1() const {
-        return constant1_;
-    }
-
-    long long DatFile::constant2() const {
-        return constant2_;
-    }
-
-    long long DatFile::file_size() const {
-        return file_size_;
-    }
-
-    long long DatFile::version1() const {
-        return version1_;
-    }
-
-    long long DatFile::version2() const {
-        return version2_;
-    }
-
-    void DatFile::WriteUnorderedDictionary(std::string path) const {
-        FILE *f;
-        fopen_s(&f, (path + "dict.txt").c_str(), "w");
-        fprintf(f, "file_id offset size size2 extension\n");
-        for (auto i : dictionary_) {
-            fprintf(f, "%lld %lld %lld %lld %s\n", i.second->file_id(), i.second->file_offset(), i.second->file_size(),
-                    i.second->block_size(), i.second->Extension());
-        }
-        fclose(f);
-    }
-
-    long long DatFile::files_number() const {
-        return dictionary_.size();
-    }
-
-    BinaryData DatFile::GetFileData(const Subfile *file, long long int offset = 0) {
-        BinaryData mfile_id(4);
-        ReadData(mfile_id, 4, file->file_offset() + 8);
-        if (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()));
-        if (file->block_size() >= file->file_size() + 8) {
-            ReadData(data, file->file_size(), file->file_offset() + offset);
-            return data;
-        }
-
-        BinaryData fragments_count(4);
-        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;
-
-        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);
-
-
-        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 );
-            current_block_size += fragment_size;
-        }
-
-        return data;
+        fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
     }
 }
 }

+ 11 - 58
Source/Database.cpp

@@ -15,22 +15,17 @@ namespace LOTRO_DAT {
 
     Database::Database() {
         db_ = nullptr;
-        query_size_ = 0;
     }
 
     Database::Database(const std::string &filename) {
-        query_size_ = 0;
         InitDatabase(filename.c_str());
     }
 
     Database::~Database() {
-        if (query_size_ != 0)
-            ExecSql("COMMIT");
+        ExecSql("COMMIT TRANSACTION");
 
         if (db_ != nullptr) {
-            sqlite3_finalize(insert_text_);
-            sqlite3_finalize(insert_binary_);
-
+            sqlite3_finalize(insert_request_);
             sqlite3_close(db_);
         }
     }
@@ -48,15 +43,11 @@ namespace LOTRO_DAT {
 		ExecSql("PRAGMA temp_store = MEMORY");
 		ExecSql("PRAGMA encoding = \"UTF-8\";");
 
-        ExecSql(CreateBinaryTableCommand_);
-        ExecSql(CreateTextTableCommand_);
-
-		sqlite3_prepare_v2(db_, InsertBinaryCommand_.c_str(), InsertBinaryCommand_.length(), &insert_binary_, nullptr);
-        sqlite3_prepare_v2(db_, InsertTextCommand_.c_str(), InsertTextCommand_.length(), &insert_text_, nullptr);
+        ExecSql(CreateTableCommand_);
 
-        //sqlite3_prepare_v2(db_, GetTextCommand, 50ll * 1024ll * 1024ll, &get_text_, nullptr);
-        //sqlite3_prepare_v2(db_, GetBinaryCommand, 50ll * 1024ll * 1024ll, &get_binary_, nullptr);
+		sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
 
+        ExecSql("BEGIN TRANSACTION");
     }
 
 	void Database::ExecSql(const std::string &sql) {
@@ -68,55 +59,17 @@ namespace LOTRO_DAT {
 		}
 	}
 
+    void Database::PushFile(const BinaryData &binary_data, const std::u16string &text_data, const std::string &options) {
+        sqlite3_bind_blob(insert_request_, 1, binary_data.data(), binary_data.size(), SQLITE_TRANSIENT);
+        sqlite3_bind_text16(insert_request_, 2, text_data.c_str(), -1, SQLITE_TRANSIENT);
+        sqlite3_bind_text(insert_request_, 3, options.c_str(), -1, SQLITE_TRANSIENT);
 
-    void Database::PushTextFile(long long file_id, long long gossip_id, const char16_t *text, const char *args, int dat_id) {
-        if (query_size_ == 0)
-            ExecSql("BEGIN TRANSACTION");
-        query_size_++;
-
-        sqlite3_bind_int(insert_text_, 1, (int)file_id);
-        sqlite3_bind_int(insert_text_, 2, (int)gossip_id);
-        sqlite3_bind_text16(insert_text_, 3, text, -1, SQLITE_TRANSIENT);
-        sqlite3_bind_text(insert_text_, 4, args, -1, SQLITE_TRANSIENT);
-
-        if (sqlite3_step(insert_text_) != SQLITE_DONE) {
+        if (sqlite3_step(insert_request_) != SQLITE_DONE) {
             fprintf(stderr, "SQLite3 error: %s\n", sqlite3_errmsg(db_));
             throw DatException((std::string("Bad Database::PushTextFile() - unable to perform push operation")).c_str(),
                                DATABASE_EXCEPTION);
         }
 
-        sqlite3_reset(insert_text_);
-
-        if (query_size_ >= QUERY_MAX_SIZE) {
-            ExecSql("COMMIT");
-            query_size_ = 0;
-        }
+        sqlite3_reset(insert_request_);
     }
-
-    //BinaryData &Database::GetTextFile(long long file_id) {}
-
-    void Database::PushBinaryFile(long long file_id, const BinaryData &data) {
-        if (query_size_ == 0)
-            ExecSql("BEGIN TRANSACTION");
-		query_size_++;
-
-        sqlite3_bind_int(insert_binary_, 1, (int)file_id);
-        sqlite3_bind_blob(insert_binary_, 2, data.data(), data.size(), SQLITE_TRANSIENT);
-
-		if (sqlite3_step(insert_binary_) != SQLITE_DONE) {
-            fprintf(stderr, "SQLite3 error: %s\n", sqlite3_errmsg(db_));
-            throw DatException(std::string("Bad Database::PushTextFile() - unable to perform operation").c_str()
-                    , DATABASE_EXCEPTION);
-        }
-        sqlite3_reset(insert_binary_);
-
-        if (query_size_ >= QUERY_MAX_SIZE) {
-            ExecSql("COMMIT");
-            query_size_ = 0;
-        }
-    }
-
-    //BinaryData &Database::GetBinaryFile(long long file_id) {
-    //
-    //}
 }

+ 11 - 31
Source/Database.h

@@ -23,48 +23,28 @@ namespace LOTRO_DAT
 
         void InitDatabase(const std::string &filename);
 
-        void PushTextFile(long long file_id, long long gossip_id, const char16_t *text, const char *args, int dat_id = 0);
-        //BinaryData& GetTextFile(long long file_id);
-
-        void PushBinaryFile(long long file_id, const BinaryData& data);
-        //BinaryData& GetBinaryFile(long long file_id);
+        void PushFile(const BinaryData &binary_data, const std::u16string &text_data, const std::string &options);
 
+        void GetFile();
+        void GetFile(long long file_id);
 
     private:
         void ExecSql(const std::string &sql);
 
         sqlite3* db_;
-        sqlite3_stmt* insert_text_;
-        sqlite3_stmt* insert_binary_;
+        sqlite3_stmt* insert_request_;
 
         sqlite3_stmt* get_text_;
         sqlite3_stmt* get_binary_;
 
-        unsigned long long query_size_;
-        const unsigned long long QUERY_MAX_SIZE = 210241024;
-
-        const std::string CreateBinaryTableCommand_ = "CREATE TABLE IF NOT EXISTS `binary_data` ( "
-            "`file_id` INTEGER NOT NULL DEFAULT '0', "
-            "`data` BLOB, "
-            "`dat_id` INTEGER NOT NULL DEFAULT '-1', "
-            "PRIMARY KEY (`file_id`));";
-
-        const std::string CreateTextTableCommand_ = "CREATE TABLE IF NOT EXISTS `text_data` ( "
-            "`file_id` INTEGER NOT NULL DEFAULT '0', "
-            "`gossip_id` INTEGER NOT NULL DEFAULT '0', "
-            "`content` TEXT, "
-            "`args` TEXT, "
-            "`args_order` TEXT, "
-            "`dat_id` INTEGER NOT NULL DEFAULT '-1', "
-            "PRIMARY KEY (`file_id`, `gossip_id`));";
-
-        const std::string InsertTextCommand_ = "INSERT INTO text_data "
-                "(file_id, gossip_id, content, args) "
-                "VALUES (?, ?, ?, ?); ";
+        const std::string CreateTableCommand_ = "CREATE TABLE IF NOT EXISTS `patch_data` ( "
+            "`binary_data` BLOB, "
+            "`text_data` TEXT, "
+            "`options` TEXT NOT NULL);";
 
-        const std::string InsertBinaryCommand_ = "INSERT INTO binary_data "
-                "(file_id, data) "
-                "VALUES (?, ?); ";
+        const std::string InsertFileCommand_ = "INSERT INTO patch_data "
+                "(binary_data, text_data, options) "
+                "VALUES (?, ?, ?); ";
 
     };
 }

+ 4 - 3
Source/SubDirectory.cpp

@@ -22,7 +22,7 @@ namespace LOTRO_DAT {
     }
 
     SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
-            offset_(offset), dat_(dat), max_subdirs_(max_subdirs) {
+            dat_(dat), offset_(offset), max_subdirs_(max_subdirs) {
         try {
             MakeSubDirectories();
         }catch (...) {
@@ -123,9 +123,10 @@ namespace LOTRO_DAT {
                 return dynamic_cast<Subfile *>(new OggSubfile(dat_, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
             case FONT:
                 return dynamic_cast<Subfile *>(new FontSubfile(dat_, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
-            default:
+            case UNKNOWN:
                 return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
         }
+        throw DatException("Bad SubDirectory::MakeSubfile() - unable to recognize file_type!", SUBFILE_EXCEPTION);
     }
 
     FILE_TYPE SubDirectory::GetSubfileType(long long file_id, long long file_offset) const {
@@ -159,7 +160,7 @@ namespace LOTRO_DAT {
             //auto markerSize = header.ToNumber<short>(28);
             //auto four = header.ToNumber<int>(30);
 
-            if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
+            if ((soi == 0xD8FFll && marker == 0xE0FFll) || marker == 0xE1FFll)
                 return JPG;
             return DDS;
         }

+ 2 - 2
Source/Subfile.h

@@ -44,6 +44,8 @@ namespace LOTRO_DAT
         long long block_size() const;
 
 	protected:
+		DatFile *dat_;
+
 		long long fragments_count_;
         long long unknown1_;
         long long file_id_;
@@ -52,8 +54,6 @@ namespace LOTRO_DAT
         long long timestamp_;
         long long version_;
         long long block_size_;
-
-        DatFile *dat_;
     };
 }
 };

+ 3 - 2
Source/Subfiles/JpgSubfile.cpp

@@ -18,11 +18,11 @@ namespace LOTRO_DAT {
     }
 
     FILE_TYPE JpgSubfile::FileType() const {
-        return FONT;
+        return JPG;
     }
 
     std::string JpgSubfile::Extension() const {
-        return ".fontbin";
+        return std::string(".jpg");
     }
 
     bool JpgSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
@@ -33,6 +33,7 @@ namespace LOTRO_DAT {
         options.emplace_back(YAML::Node());
         options[0]["file_id"] = file_id();
         options[0]["extension"] = Extension();
+        return true;
     }
 
     BinaryData JpgSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,

+ 8 - 3
Source/Subfiles/TextSubfile.cpp

@@ -21,6 +21,10 @@ namespace LOTRO_DAT {
         return TEXT;
     }
 
+    std::string TextSubfile::Extension() const {
+        return std::string(".txt");
+    }
+
     bool TextSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
                                        std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
         export_size = 0;
@@ -49,12 +53,12 @@ namespace LOTRO_DAT {
             std::vector<std::vector<BinaryData>> arg_strings = MakeArgumentStrings(file_data, offset);
 
             std::u16string text = u"[";
-            for (int j = 0; j + 1 < text_pieces.size(); j++)
+            for (size_t j = 0; j + 1 < text_pieces.size(); j++)
                 text += text_pieces[j] + u"<--DO_NOT_TOUCH!-->";
             text += text_pieces[text_pieces.size() - 1] + u"]";
 
             std::string arguments;
-            for (int j = 0; j + 1 < arg_references.size(); j++)
+            for (size_t j = 0; j + 1 < arg_references.size(); j++)
                 arguments += std::to_string(arg_references[j]) + "-";
             if (!arg_references.empty())
                 arguments += std::to_string(arg_references[arg_references.size() - 1]);
@@ -66,7 +70,8 @@ namespace LOTRO_DAT {
             options[export_size]["file_id"] = file_id();
             options[export_size]["gossip_id"] = fragment_id;
             options[export_size]["extension"] = Extension();
-            options[export_size]["arguments"] = arguments;
+            if (!arg_references.empty())
+                options[export_size]["arguments"] = arguments;
 
             ++export_size;
         }

+ 1 - 0
Source/Subfiles/TextSubfile.h

@@ -18,6 +18,7 @@ namespace LOTRO_DAT {
                     long long file_size, long long timestamp, long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
+        std::string Extension() const override;
 
         bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
                               std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;

+ 1 - 1
Source/Subfiles/UnknownSubfile.cpp

@@ -22,7 +22,7 @@ namespace LOTRO_DAT {
     }
 
     std::string UnknownSubfile::Extension() const {
-        return ".unknown";
+        return std::string(".unknown");
     }
 
     bool UnknownSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,

+ 23 - 25
Source/Tests/extract_test.cpp

@@ -20,11 +20,11 @@ const std::string path = "";//"E:\\SteamLibrary\\steamapps\\common\\";//Lord Of
 const std::string filename = "client_local_English.dat";
 
 // Change these variables to true if you want export catecory to files.
-const bool exportImagesToFiles = true;
-const bool exportFontsToFiles = true;
-const bool exportSoundsToFiles = true;
-const bool exportTexturesToFiles = true;
-const bool exportUnknownToFiles = true;
+const bool exportImagesToFiles = false;
+const bool exportFontsToFiles = false;
+const bool exportSoundsToFiles = false;
+const bool exportTexturesToFiles = false;
+const bool exportUnknownToFiles = false;
 
 // Change these variables to true if you want export catecory to databases.
 const bool exportTextsToDb = true;
@@ -38,7 +38,6 @@ const bool exportUnknownToDb = true;
 int main() {
     const clock_t begin_time = clock();
 
-    std::time_t time = std::time(nullptr);
     mkdir("Extracted data", 744);
 
     std::time_t result = std::time(nullptr);
@@ -54,83 +53,82 @@ int main() {
     freopen((output_dir + std::string("errors.log")).c_str(), "w", stderr);
 
     try {
-        std::cout << "Starting search...\n";
+        std::cout << "Starting search...\n" << std::flush;
         DatFile a((path + filename).c_str(), 0);
-        std::cout << "Total files found: " << a.files_number() << std::endl;
+        std::cout << "Total files found: " << a.files_number() << std::endl << std::flush;
 
         std::cout << "Writing unordered dictionary:\n";
         a.WriteUnorderedDictionary(output_dir);
 
         std::cout << "Beginning unpacking... Please, wait for some minutes."
-        "\nMaybe it's a good idea to have a cup of tea, while unpacker is working...\n";
+        "\nMaybe it's a good idea to have a cup of tea, while unpacker is working...\n" << std::flush;
 
 
         if (exportImagesToDb) {
             Database *images = new Database(output_dir + std::string("Images.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, images) << " .jpg files to Images.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, images) << " .jpg files to Images.db" << std::endl << std::flush;
             delete images;
         }
 
         if (exportSoundsToDb) {
             Database *sounds = new Database(output_dir + std::string("Sounds.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, sounds) << " .wav files to Sounds.db" << std::endl;
-            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, sounds) << " .ogg files to Sounds.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, sounds) << " .wav files to Sounds.db" << std::endl << std::flush;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, sounds) << " .ogg files to Sounds.db" << std::endl << std::flush;
             delete sounds;
         }
 
         if (exportTextsToDb) {
             Database *texts = new Database(output_dir + std::string("Texts.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(TEXT, texts) << " text files to Texts.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(TEXT, texts) << " text files to Texts.db" << std::endl << std::flush;
             delete texts;
         }
 
         if (exportFontsToDb) {
             Database *fonts = new Database(output_dir + std::string("Fonts.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, fonts) << " font files to Fonts.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, fonts) << " font files to Fonts.db" << std::endl << std::flush;
             delete fonts;
         }
 
         if (exportTexturesToDb) {
             Database *textures = new Database(output_dir + std::string("Textures.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, textures) << " .dds files to Textures.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, textures) << " .dds files to Textures.db" << std::endl << std::flush;
             delete textures;
         }
 
         if (exportUnknownToDb) {
             Database *unknown = new Database(output_dir + std::string("Unknown.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(UNKNOWN, unknown) << " unknown files to Unknown.db" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(UNKNOWN, unknown) << " unknown files to Unknown.db" << std::endl << std::flush;
         }
 
         if (exportImagesToFiles) {
             mkdir((output_dir + "jpg").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl << std::flush;
         }
 
         if (exportTexturesToFiles) {
             mkdir((output_dir + "dds").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl << std::flush;
         }
 
         if (exportSoundsToFiles) {
             mkdir((output_dir + "wav").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
             mkdir((output_dir + "ogg").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl << std::flush;
         }
 
         if (exportFontsToFiles) {
             mkdir((output_dir + "fonts").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl << std::flush;
         }
 
         if (exportUnknownToFiles) {
             mkdir((output_dir + "unknown").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl;
+            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
         }
-
     } catch (...) {
-        printf("Some critical errors occured. Need to stop execution. See information in errors.log file");
-        fprintf(stderr, "Some critical errors occured. Need to stop execution now...");
+        printf("Some critical errors occured. Need to stop execution. See information in errors.log file\n");
+        fprintf(stderr, "Some critical errors occured. Need to stop execution now...\n");
     }
     fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
             float(clock() - begin_time) / CLOCKS_PER_SEC);