فهرست منبع

Major code refactoring and some new functions implementation part 1

Gi1dor (Ivan Arkhipov) 6 سال پیش
والد
کامیت
c967d053c7

+ 38 - 15
CMakeLists.txt

@@ -1,31 +1,54 @@
 cmake_minimum_required(VERSION 3.8)
-project(LotRO_Universal_Dat_Library)
+project(LotRO_Gi1dor_dat_library)
 
 set(CMAKE_CXX_STANDARD 11)
+set(PROJECT_BINARY_DIR bin)
+set(PROJECT_VERSION 0.1.0)
+
+set(CMAKE_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin)
+set(CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Source)
+
+SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_OUTPUT_DIR})
+SET(LIBRARY_OUTPUT_PATH ${CMAKE_OUTPUT_DIR})
 
 set(SOURCE_FILES
-        DatException.h
-        LotroDatPatcher.h
+        ${CMAKE_SOURCE_DIR}/Common/CommonFunctions.h
+        ${CMAKE_SOURCE_DIR}/Common/DatException.h
+        ${CMAKE_SOURCE_DIR}/LotroDatPatcher.h
+
+        ${CMAKE_SOURCE_DIR}/DatFile/DatFile.cpp
+        ${CMAKE_SOURCE_DIR}/DatFile/DatFile.h
+
+        ${CMAKE_SOURCE_DIR}/BinaryData/BinaryData.cpp
+        ${CMAKE_SOURCE_DIR}/BinaryData/BinaryData.h
 
-        DatFile.cpp DatFile.h
-        BinaryData.cpp BinaryData.h
-        Database.cpp Database.h
+        ${CMAKE_SOURCE_DIR}/Database/Database.cpp
+        ${CMAKE_SOURCE_DIR}/Database/Database.h
 
-        Subfile.cpp Subfile.h
-        SubDirectory.cpp SubDirectory.h
+        ${CMAKE_SOURCE_DIR}/Subfiles/Subfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/Subfile.h
 
-        sqlite/sqlite3.c sqlite/sqlite3.h
-		CommonFunctions.h
+        ${CMAKE_SOURCE_DIR}/SubDirectory/SubDirectory.cpp
+        ${CMAKE_SOURCE_DIR}/SubDirectory/SubDirectory.h
+
+        ${CMAKE_SOURCE_DIR}/Common/SQLite/sqlite3.c
+        ${CMAKE_SOURCE_DIR}/Common/SQLite/sqlite3.h
         )
 
+
+# STATIC LIBRARY
+add_library(LotroDat_static STATIC ${SOURCE_FILES})
+target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
+
+# SHARED LIBRARY
 add_library(LotroDat SHARED ${SOURCE_FILES})
-target_link_libraries(LotroDat ${CMAKE_SOURCE_DIR}/zlib/libzlibstatic.a)
+target_link_libraries(LotroDat ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
 
 # FOR EXTRACTOR USE NEXT LINE
-add_executable(LotRO_dat_extract_tester ${SOURCE_FILES} extract_test.cpp)
-target_link_libraries(LotRO_dat_extract_tester ${CMAKE_SOURCE_DIR}/zlib/libzlibstatic.a)
+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)
 
 # FOR PATCHER USE NEXT LINE
-add_executable(LotRO_dat_patch_tester ${SOURCE_FILES} patch_test.cpp)
-target_link_libraries(LotRO_dat_patch_tester ${CMAKE_SOURCE_DIR}/zlib/libzlibstatic.a)
+add_executable(LotRO_dat_patch_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/patch_test.cpp)
+target_link_libraries(LotRO_dat_patch_tester ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
 

+ 0 - 192
DatFile.cpp

@@ -1,192 +0,0 @@
-//
-// Created by Иван_Архипов on 31.10.2017.
-//
-
-#include "DatFile.h"
-
-#include "BinaryData.h"
-#include "DatException.h"
-#include "SubDirectory.h"
-#include "Subfile.h"
-
-#include <locale>
-
-extern "C++"
-{
-namespace LOTRO_DAT {
-    DatFile::DatFile() {
-        dat_state_ = CLOSED;
-    }
-
-    DatFile::DatFile(const char *filename, int dat_id) {
-        dat_id_ = dat_id;
-        dat_state_ = CLOSED;
-        OpenDatFile(filename);
-        ReadSuperBlock();
-        MakeDirectories();
-        try {
-            MakeDictionary();
-        } catch (...) {
-            fprintf(stderr, "Unable to make dictionary!! Unable to init DatFile!!!");
-            return;
-        }
-        if (dat_state_ == SUCCESS_DICTIONARY)
-            dat_state_ = READY;
-        else
-            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
-                               INIT_EXCEPTION);
-    }
-
-    DatFile::DatFile(const std::string &filename, int dat_id) {
-        dat_id_ = dat_id;
-        dat_state_ = CLOSED;
-        OpenDatFile(filename.c_str());
-        ReadSuperBlock();
-        MakeDirectories();
-        MakeDictionary();
-        if (dat_state_ == SUCCESS_DICTIONARY)
-            dat_state_ = READY;
-        else
-            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
-                               INIT_EXCEPTION);
-    }
-
-    DatFile::~DatFile() {
-        if (file_handler_ != nullptr)
-            fclose(file_handler_);
-        delete file_handler_;
-        delete root_directory_;
-    }
-
-    void DatFile::OpenDatFile(const char *dat_name) {
-        if (dat_state_ != CLOSED)
-            throw DatException("Bad initialisation of DatFile - current DatFile isn't in correct state!",
-                               INIT_EXCEPTION);
-
-        fopen_s(&file_handler_, dat_name, "r+b");
-
-        if (file_handler_ == nullptr) {
-            std::string err = "Bad DatFile::OpenDatFile. Unable to open file ";
-            err += dat_name;
-            throw DatException(err.c_str(), INIT_EXCEPTION);
-        }
-
-        _fseeki64(file_handler_, 0, SEEK_END);
-        file_size_ = _ftelli64(file_handler_);
-        _fseeki64(file_handler_, 0, SEEK_SET);
-
-        dat_state_ = SUCCESS_OPENED;
-    }
-
-    void DatFile::ReadSuperBlock() {
-        if (dat_state_ != SUCCESS_OPENED)
-            throw DatException("Bad DatFile::ReadSuperBlock() - DatFile isn't in valid state!", INIT_EXCEPTION);
-
-        BinaryData data(1024);
-        ReadData(data, 1024);
-
-        constant1_ = data.ToNumber<4>(0x100);
-        constant2_ = data.ToNumber<4>(0x140);
-        version1_ = data.ToNumber<4>(0x14C);
-        version2_ = data.ToNumber<4>(0x150);
-        root_directory_offset_ = data.ToNumber<4>(0x160);
-
-        auto size1 = data.ToNumber<4>(0x148);
-
-        if (constant1_ != 0x4C5000)
-            throw DatException(
-                    "Bad DatFile::ReadSuperBlock - variable at position 0x100 is not equal to .dat file constant!",
-                    INIT_EXCEPTION);
-
-        if (constant2_ != 0x5442)
-            throw DatException(
-                    "Bad DatFile::ReadSuperBlock - variable at position 0x140 is not equal to .dat file constant!",
-                    INIT_EXCEPTION);
-
-        if (file_size_ != size1)
-            throw DatException(
-                    "Bad DatFile::ReadSuperBlock - variable at 0x148 position is not equal to .dat file size!",
-                    INIT_EXCEPTION);
-
-        dat_state_ = SUCCESS_SUPERBLOCK;
-    }
-
-    void DatFile::MakeDirectories() {
-        if (dat_state_ != SUCCESS_SUPERBLOCK)
-            throw DatException("Bad DatFile::MakeDirectories() - DatFile isn't in valid state!", INIT_EXCEPTION);
-        root_directory_ = new SubDirectory((unsigned) root_directory_offset_, this);
-        dat_state_ = SUCCESS_DIRECTORIES;
-    }
-
-    void DatFile::MakeDictionary() {
-        if (dat_state_ != SUCCESS_DIRECTORIES)
-            throw DatException("Bad DatFile::MakeDictionary() - DatFile isn't in valid state!", INIT_EXCEPTION);
-		try {
-			root_directory_->MakeDictionary(dictionary_);
-		} catch (...) {
-			fprintf(stderr, "Bad DatFile::MakeDictionary() - File is corrupted?\n");
-			return;
-		}
-		dat_state_ = SUCCESS_DICTIONARY;
-    }
-
-    void DatFile::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (dat_state_ == CLOSED)
-            throw DatException("Bad DatFile::ReadData() - DatFile isn't in valid state!", READ_EXCEPTION);
-
-        if (data_offset + size > data.size()) {
-            std::string err = "Bad DatFile::ReadData - trying to read more than BinaryData size\n";
-            err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
-                   + std::to_string(offset) + std::string(" position in dat file.");
-            throw DatException(err.c_str(), READ_EXCEPTION);
-        }
-
-        if (offset + size > file_size()) {
-            std::string err = "Bad DatFile::ReadData - trying to read more than DatFile size elapsed\n";
-            err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
-                   + std::to_string(offset) + std::string(" position in dat file.");
-            throw DatException(err.c_str(), READ_EXCEPTION);
-        }
-
-        _fseeki64(file_handler_, offset, SEEK_SET);
-        fread(data.data() + data_offset, size, 1, file_handler_);
-        data.CheckCompression();
-    }
-
-    void DatFile::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (dat_state_ != READY)
-            throw DatException("Bad DatFile::WriteData() - DatFile isn't in valid state!", WRITE_EXCEPTION);
-
-        _fseeki64(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);
-
-        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_;
-    }
-
-    const std::unordered_map<long long, Subfile *> &DatFile::dictionary() {
-        return dictionary_;
-    }
-
-}
-}

+ 0 - 14
LotroDatPatcher.h

@@ -1,14 +0,0 @@
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "DatFile.h"
-#include "BinaryData.h"
-#include "Database.h"
-
-#include "Subfile.h"
-
-#include "DatException.h"
-#include "SubDirectory.h"
-
-#include "CommonFunctions.h"

+ 2 - 2
BinaryData.cpp → Source/BinaryData/BinaryData.cpp

@@ -3,8 +3,8 @@
 //
 
 #include "BinaryData.h"
-#include "DatException.h"
-#include "zlib/zlib.h"
+#include "../Common/DatException.h"
+#include "../Common/Zlib/zlib.h"
 
 extern  "C++"
 {

+ 0 - 0
BinaryData.h → Source/BinaryData/BinaryData.h


+ 0 - 0
CommonFunctions.h → Source/Common/CommonFunctions.h


+ 0 - 0
DatException.h → Source/Common/DatException.h


+ 0 - 0
sqlite/shell.c → Source/Common/SQLite/shell.c


+ 0 - 0
sqlite/sqlite3.c → Source/Common/SQLite/sqlite3.c


+ 0 - 0
sqlite/sqlite3.h → Source/Common/SQLite/sqlite3.h


+ 0 - 0
zlib/libzlibstatic.a → Source/Common/ZLib/libzlibstatic.a


+ 0 - 0
zlib/zconf.h → Source/Common/ZLib/zconf.h


+ 0 - 0
zlib/zlib.h → Source/Common/ZLib/zlib.h


+ 323 - 0
Source/DatFile/DatFile.cpp

@@ -0,0 +1,323 @@
+//
+// Created by Иван_Архипов on 31.10.2017.
+//
+
+#include "DatFile.h"
+
+#include "../BinaryData/BinaryData.h"
+#include "../Common/DatException.h"
+#include "../SubDirectory/SubDirectory.h"
+#include "../Subfiles/Subfile.h"
+
+#include <locale>
+
+extern "C++"
+{
+namespace LOTRO_DAT {
+    DatFile::DatFile() {
+        dat_state_ = CLOSED;
+    }
+
+    DatFile::DatFile(const char *filename, int dat_id) {
+        dat_id_ = dat_id;
+        dat_state_ = CLOSED;
+        OpenDatFile(filename);
+        ReadSuperBlock();
+        MakeDirectories();
+        try {
+            MakeDictionary();
+        } catch (...) {
+            fprintf(stderr, "Unable to make dictionary!! Unable to init DatFile!!!");
+            return;
+        }
+        if (dat_state_ == SUCCESS_DICTIONARY)
+            dat_state_ = READY;
+        else
+            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
+                               INIT_EXCEPTION);
+    }
+
+    DatFile::DatFile(const std::string &filename, int dat_id) {
+        dat_id_ = dat_id;
+        dat_state_ = CLOSED;
+        OpenDatFile(filename.c_str());
+        ReadSuperBlock();
+        MakeDirectories();
+        MakeDictionary();
+        if (dat_state_ == SUCCESS_DICTIONARY)
+            dat_state_ = READY;
+        else
+            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
+                               INIT_EXCEPTION);
+    }
+
+    DatFile::~DatFile() {
+        if (file_handler_ != nullptr)
+            fclose(file_handler_);
+        delete file_handler_;
+        delete root_directory_;
+    }
+
+    /// Extracts file with file_id.
+    /// If path is undefined then it will be recognised as current working directory
+    /// Output file path consists of "path + file_id + file_extension";
+    /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
+    /// Otherwise DatException() will be thrown.
+    /// Returns true, if file was successfully extracted;
+    /// Throws DatException() if undefined behaviour happened
+
+    bool DatFile::ExtractFile(long long file_id, const std::string path) {
+        if (dat_state_ != READY) {
+            throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
+        }
+        return dictionary_[file_id]->ExportFile(path.c_str());
+    }
+
+    /// Extracts file with file_id to database "db".
+    /// DATABASE SHOULD BE ALREADY CREATED; Otherwise DatException will be called.
+    /// NOTICE: The directory, mentioned in "std::string path" variable SHOULD BE ALREADY CREATED;
+    /// Otherwise DatException() will be thrown.
+    /// Returns true, if file was successfully extracted;
+    /// Throws DatException() if undefined behaviour happened
+
+    bool DatFile::ExtractFile(long long file_id, Database *db) {
+        if (dat_state_ != READY) {
+            throw DatException("Bad DatFile::ExtractFile() - invalid DatFile state!", EXPORT_EXCEPTION);
+        }
+        return dictionary_[file_id]->ExportFile(db);
+    }
+
+    /// Extracts all files with specific type to "path + type + file_id + 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.
+    /// Returns number of successfully extracted files
+    /// Throws DatException() if undefined behaviour happened
+
+    int DatFile::ExtractAllFilesByType(FILE_TYPE type, std::string path) {
+        if (dat_state_ != READY) {
+            throw DatException("Bad DatFile::ExtractAllFilesByType() - invalid DatFile state!", EXPORT_EXCEPTION);
+        }
+
+        int success = 0;
+        for (auto i : dictionary_) {
+            FILE_TYPE ext = i.second->ext();
+            if (ext == type) {
+                success += i.second->ExportFile((path + std::to_string(i.second->file_id())).c_str());
+            }
+        }
+        return success;
+    }
+
+    /// Extracts all files with specific type to database "db";
+    /// DATABASE SHOULD BE ALREADY CREATED; Otherwise DatException will be called.
+    /// Returns number of successfully extracted files
+    /// Throws DatException() if undefined behaviour happened
+
+    int DatFile::ExtractAllFilesByType(FILE_TYPE type, Database *db) {
+        if (dat_state_ != READY) {
+            throw DatException("Bad DatFile::ExtractAllFilesByType() - invalid DatFile state!", EXPORT_EXCEPTION);
+        }
+
+        int success = 0;
+        for (auto i : dictionary_) {
+            FILE_TYPE ext = i.second->ext();
+            if (ext == type) {
+                success += i.second->ExportFile(db);
+            }
+        }
+        return success;
+    }
+
+    /// Patches .dat with text file with specific file_id, gossip_id and values, equal to values in text database.
+    /// std::string text contains of text data, surrounded by '[' and ']', where <--DO_NOT_TOUCH!--> represents
+    ///     position of variables in order, described in args_order.
+    /// std::string args_order contains of numbers, divided by '-'. Ex. "1-2-3-4". There should be not less numbers, than
+    ///     <--DO_NOT_TOUCH!--> pieces in text variable/
+    /// std::string args contains of numbers, divided by ' '. These numbers are references to variables. There should
+    ///     be not less references, than the biggest number in args_order
+    /// Returns true if text was succesfully patched.
+    /// Throws DatException() if undefined behaviour happened;
+
+    bool DatFile::PatchTextFile(long long file_id, long long gossip_id, std::string text, std::string args_order,
+                                std::string args) {
+
+    }
+
+    /// Patches .dat with text file with specific file_id and gossip_id.
+    /// All text file data is got from database.
+    /// Returns true if text file was successfully patched.
+    /// Throws DatException() if undefined behaviour happened;
+
+    bool DatFile::PatchTextFile(long long file_id, long long gossip_id, Database *db) {
+
+    }
+
+    /// Patches .dat with binary file with specific file_id.
+    /// All file data is got from file in "file_path".
+    /// Returns true if file was successfully patched.
+    /// Throws DatException() if undefined behaviour happened;
+
+    bool DatFile::PatchBinaryFile(long long file_id, std::string file_path) {
+
+    }
+
+    /// Patches .dat with binary file with specific file_id.
+    /// All file data is got from Database "db".
+    /// Returns true if file was successfully patched.
+    /// Throws DatException() if undefined behaviour happened;
+
+    bool DatFile::PatchBinaryFile(long long file_id, Database *db) {
+
+    }
+
+    void DatFile::OpenDatFile(const char *dat_name) {
+        if (dat_state_ != CLOSED)
+            throw DatException("Bad initialisation of DatFile - current DatFile isn't in correct state!",
+                               INIT_EXCEPTION);
+
+        fopen_s(&file_handler_, dat_name, "r+b");
+
+        if (file_handler_ == nullptr) {
+            std::string err = "Bad DatFile::OpenDatFile. Unable to open file ";
+            err += dat_name;
+            throw DatException(err.c_str(), INIT_EXCEPTION);
+        }
+
+        _fseeki64(file_handler_, 0, SEEK_END);
+        file_size_ = _ftelli64(file_handler_);
+        _fseeki64(file_handler_, 0, SEEK_SET);
+
+        dat_state_ = SUCCESS_OPENED;
+    }
+
+    void DatFile::ReadSuperBlock() {
+        if (dat_state_ != SUCCESS_OPENED)
+            throw DatException("Bad DatFile::ReadSuperBlock() - DatFile isn't in valid state!", INIT_EXCEPTION);
+
+        BinaryData data(1024);
+        ReadData(data, 1024);
+
+        constant1_ = data.ToNumber<4>(0x100);
+        constant2_ = data.ToNumber<4>(0x140);
+        version1_ = data.ToNumber<4>(0x14C);
+        version2_ = data.ToNumber<4>(0x150);
+        root_directory_offset_ = data.ToNumber<4>(0x160);
+
+        auto size1 = data.ToNumber<4>(0x148);
+
+        if (constant1_ != 0x4C5000)
+            throw DatException(
+                    "Bad DatFile::ReadSuperBlock - variable at position 0x100 is not equal to .dat file constant!",
+                    INIT_EXCEPTION);
+
+        if (constant2_ != 0x5442)
+            throw DatException(
+                    "Bad DatFile::ReadSuperBlock - variable at position 0x140 is not equal to .dat file constant!",
+                    INIT_EXCEPTION);
+
+        if (file_size_ != size1)
+            throw DatException(
+                    "Bad DatFile::ReadSuperBlock - variable at 0x148 position is not equal to .dat file size!",
+                    INIT_EXCEPTION);
+
+        dat_state_ = SUCCESS_SUPERBLOCK;
+    }
+
+    void DatFile::MakeDirectories() {
+        if (dat_state_ != SUCCESS_SUPERBLOCK)
+            throw DatException("Bad DatFile::MakeDirectories() - DatFile isn't in valid state!", INIT_EXCEPTION);
+        root_directory_ = new SubDirectory((unsigned) root_directory_offset_, this);
+        dat_state_ = SUCCESS_DIRECTORIES;
+    }
+
+    void DatFile::MakeDictionary() {
+        if (dat_state_ != SUCCESS_DIRECTORIES)
+            throw DatException("Bad DatFile::MakeDictionary() - DatFile isn't in valid state!", INIT_EXCEPTION);
+        try {
+            root_directory_->MakeDictionary(dictionary_);
+        } catch (...) {
+            fprintf(stderr, "Bad DatFile::MakeDictionary() - File is corrupted?\n");
+            return;
+        }
+        dat_state_ = SUCCESS_DICTIONARY;
+    }
+
+    void DatFile::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) {
+        if (dat_state_ == CLOSED)
+            throw DatException("Bad DatFile::ReadData() - DatFile isn't in valid state!", READ_EXCEPTION);
+
+        if (data_offset + size > data.size()) {
+            std::string err = "Bad DatFile::ReadData - trying to read more than BinaryData size\n";
+            err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
+                   + std::to_string(offset) + std::string(" position in dat file.");
+            throw DatException(err.c_str(), READ_EXCEPTION);
+        }
+
+        if (offset + size > file_size()) {
+            std::string err = "Bad DatFile::ReadData - trying to read more than DatFile size elapsed\n";
+            err += std::string("Reading ") + std::to_string(size) + std::string(" bytes from ")
+                   + std::to_string(offset) + std::string(" position in dat file.");
+            throw DatException(err.c_str(), READ_EXCEPTION);
+        }
+
+        _fseeki64(file_handler_, offset, SEEK_SET);
+        fread(data.data() + data_offset, size, 1, file_handler_);
+        data.CheckCompression();
+    }
+
+    void DatFile::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
+        if (dat_state_ != READY)
+            throw DatException("Bad DatFile::WriteData() - DatFile isn't in valid state!", WRITE_EXCEPTION);
+
+        _fseeki64(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);
+
+        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_) {
+            std::string extension = "unk";
+            FILE_TYPE ext = i.second->ext();
+            if (ext == TEXT) extension = "txt";
+            if (ext == JPG) extension = "jpg";
+            if (ext == DDS) extension = "dds";
+            if (ext == WAV) extension = "wav";
+            if (ext == OGG) extension = "ogg";
+            if (ext == FONT) extension = "font";
+            fprintf(f, "%lld %lld %lld %lld %s\n", i.second->file_id(), i.second->file_offset(), i.second->file_size(),
+                    i.second->block_size(), extension.c_str());
+        }
+        fclose(f);
+    }
+
+    long long DatFile::files_number() const {
+        return dictionary_.size();
+    }
+}
+}

+ 32 - 6
DatFile.h → Source/DatFile/DatFile.h

@@ -15,6 +15,7 @@
 #include <map>
 #include <unordered_map>
 #include <set>
+#include "../Database/Database.h"
 
 // Dat file names definitions
 #define CLIENT_LOCAL_ENGLISH 0
@@ -32,7 +33,17 @@ namespace LOTRO_DAT
     class SubDirectory;
     class Subfile;
 
-    enum STATE {
+    enum FILE_TYPE : int{
+        TEXT,
+        JPG,
+        DDS,
+        WAV,
+        OGG,
+        FONT,
+        UNKNOWN
+    };
+
+    enum DAT_STATE {
         CLOSED,
         SUCCESS_OPENED,
         SUCCESS_SUPERBLOCK,
@@ -43,14 +54,27 @@ namespace LOTRO_DAT
 
     class DatFile
     {
+        friend class Subfile;
+        friend class SubDirectory;
     public:
         DatFile();
         explicit DatFile(const char* filename, int dat_id);
         explicit DatFile(const std::string &filename, int dat_id);
         ~DatFile();
 
-        void ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
-        void WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
+        bool ExtractFile(long long file_id, const std::string path = "");
+        bool ExtractFile(long long file_id, Database *db);
+
+        int ExtractAllFilesByType(FILE_TYPE type, std::string path = "");
+        int ExtractAllFilesByType(FILE_TYPE type, Database *db);
+
+        bool PatchTextFile(long long file_id, long long gossip_id, std::string text, std::string args_order = "", std::string args = "");
+        bool PatchTextFile(long long file_id, long long gossip_id, Database *db);
+
+        bool PatchBinaryFile(long long file_id, std::string file_path);
+        bool PatchBinaryFile(long long file_id, Database *db);
+
+        void WriteUnorderedDictionary(std::string path) const;
 
         long long constant1() const;
         long long constant2() const;
@@ -58,7 +82,7 @@ namespace LOTRO_DAT
         long long version1() const;
         long long version2() const;
 
-        const std::unordered_map<long long, Subfile*> &dictionary();
+        long long files_number() const;
 
     private:
         FILE *file_handler_;
@@ -70,6 +94,9 @@ namespace LOTRO_DAT
         void MakeDirectories();
         void MakeDictionary();
 
+        void ReadData(BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
+        void WriteData(const BinaryData &data, long long size, long long offset = 0, long long data_offset = 0);
+
         long long constant1_;
         long long constant2_;
         long long file_size_;
@@ -77,9 +104,8 @@ namespace LOTRO_DAT
         long long version2_;
         long long root_directory_offset_;
 
-        STATE dat_state_;
+        DAT_STATE dat_state_;
         int dat_id_;
-
     };
 }
 }

+ 3 - 3
Database.cpp → Source/Database/Database.cpp

@@ -5,9 +5,9 @@
 #define _UNICODE 
 
 #include "Database.h"
-#include "DatException.h"
-#include "BinaryData.h"
-#include "CommonFunctions.h"
+#include "../Common/DatException.h"
+#include "../BinaryData/BinaryData.h"
+#include "../Common/CommonFunctions.h"
 
 #include <cstring>
 

+ 1 - 1
Database.h → Source/Database/Database.h

@@ -5,7 +5,7 @@
 #ifndef LOTRO_DAT_PATCHER_DATABASE_H
 #define LOTRO_DAT_PATCHER_DATABASE_H
 
-#include "sqlite/sqlite3.h"
+#include "../Common/SQLite/sqlite3.h"
 #include <string>
 
 extern  "C++"

+ 6 - 0
Source/LotroDatPatcher.h

@@ -0,0 +1,6 @@
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "DatFile/DatFile.h"
+#include "Database/Database.h"

+ 4 - 4
SubDirectory.cpp → Source/SubDirectory/SubDirectory.cpp

@@ -3,10 +3,10 @@
 //
 #include "SubDirectory.h"
 
-#include "DatFile.h"
-#include "DatException.h"
-#include "Subfile.h"
-#include "BinaryData.h"
+#include "../DatFile/DatFile.h"
+#include "../Common/DatException.h"
+#include "../Subfiles/Subfile.h"
+#include "../BinaryData/BinaryData.h"
 
 LOTRO_DAT::SubDirectory::SubDirectory() {
     offset_ = 0;

+ 0 - 0
SubDirectory.h → Source/SubDirectory/SubDirectory.h


+ 51 - 23
Subfile.cpp → Source/Subfiles/Subfile.cpp

@@ -3,11 +3,11 @@
 //
 
 #include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "DatException.h"
-#include "Database.h"
-#include "CommonFunctions.h"
+#include "../BinaryData/BinaryData.h"
+#include "../DatFile/DatFile.h"
+#include "../Common/DatException.h"
+#include "../Database/Database.h"
+#include "../Common/CommonFunctions.h"
 
 #include <algorithm>
 
@@ -66,10 +66,10 @@ long long LOTRO_DAT::Subfile::block_size() const {
     return block_size_;
 }
 
-LOTRO_DAT::EXTENSION LOTRO_DAT::Subfile::GetExtension() const {
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
     // Text check based on file_id
     if ((file_id_ >> 24ll) == 0x25ll)
-        return TXT;
+        return TEXT;
 
     // Font check based on file_id
     if ((file_id_ >> 24ll) == 0x42ll)
@@ -110,14 +110,14 @@ LOTRO_DAT::EXTENSION LOTRO_DAT::Subfile::GetExtension() const {
     return UNKNOWN;
 }
 
-LOTRO_DAT::EXTENSION LOTRO_DAT::Subfile::ext() const {
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::ext() const {
 	return ext_;
 }
 
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::EXTENSION ext) const {
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
 	switch (ext)
 	{
-	case LOTRO_DAT::TXT:
+	case LOTRO_DAT::TEXT:
 		return ".txt";
 	case LOTRO_DAT::JPG:
 		return ".jpg";
@@ -142,7 +142,7 @@ bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
     // Making data for placing in .dat, depending on file extension
     switch (ext_)
     {
-        case LOTRO_DAT::TXT:
+        case LOTRO_DAT::TEXT:
             throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
         case LOTRO_DAT::JPG:
             data = MakeFromJPG(file); break;
@@ -169,14 +169,14 @@ bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
     return true;
 }
 
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename, Database *db) const {
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
 	try {
         BinaryData data;
 
 		switch (ext_)
 		{
-		case LOTRO_DAT::TXT:
-			return ExportFileAsTXT(filename, db);
+		case LOTRO_DAT::TEXT:
+            return false;
 		case LOTRO_DAT::JPG:
 			data = PrepareAsJPG(); break;
 		case LOTRO_DAT::DDS:
@@ -192,14 +192,9 @@ bool LOTRO_DAT::Subfile::ExportFile(const char *filename, Database *db) const {
 		default:
 			break;
 		}
-
-		if (db == nullptr) {
-            std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-			return data.WriteToFile(s);
-		} else {
-            db->PushBinaryFile(file_id_, data);
-            return true;
-		}
+        
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
 	}
 	catch (DatException &e) {
 		fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
@@ -208,7 +203,40 @@ bool LOTRO_DAT::Subfile::ExportFile(const char *filename, Database *db) const {
 	}
 }
 
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(const char *filename, Database *db) const {
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
     if (db == nullptr) {
         return false;
     }

+ 9 - 11
Subfile.h → Source/Subfiles/Subfile.h

@@ -13,11 +13,8 @@ namespace LOTRO_DAT
     class DatFile;
 	class BinaryData;
     class Database;
+    enum FILE_TYPE : int;
 
-    enum EXTENSION
-    {
-        TXT, JPG, DDS, WAV, OGG, FONT, UNKNOWN
-    };
 
     class Subfile
     {
@@ -27,9 +24,10 @@ namespace LOTRO_DAT
         Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset, long long file_size,
                 long long timestamp, long long version, long long block_size);
 
-        bool ExportFile(const char* filename, Database *db = nullptr) const;
-		
-		bool ExportFileAsTXT(const char *filename, Database *db = nullptr) const;
+        bool ExportFile(const char* filename) const;
+        bool ExportFile(Database *db) const;
+
+		bool ExportFileAsTXT(Database *db = nullptr) const;
 
 		bool PatchBinaryFile(const BinaryData &file);
 
@@ -51,7 +49,7 @@ namespace LOTRO_DAT
 
         long long block_size() const;
 
-		EXTENSION ext() const;
+		FILE_TYPE ext() const;
     
 	private:
         long long fragments_count_;
@@ -66,10 +64,10 @@ namespace LOTRO_DAT
         bool compressed_;
 
         DatFile *dat_;
-		EXTENSION ext_;
+		FILE_TYPE ext_;
 
-		EXTENSION GetExtension() const;
-		std::string ExtensionToString(LOTRO_DAT::EXTENSION ext) const;
+		FILE_TYPE GetExtension() const;
+		std::string ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const;
 
 		BinaryData GetFileData(long long offset = 8) const;
 

+ 140 - 0
Source/Tests/extract_test.cpp

@@ -0,0 +1,140 @@
+//
+// Created by Иван_Архипов on 30.10.2017.
+//
+#define _CRT_SECURE_NO_WARNINGS
+#include <iostream>
+#include <ctime>
+#include <algorithm>
+
+#ifdef WIN32
+#include <direct.h>
+#define mkdir(dir, mode) _mkdir(dir)
+#endif
+
+#include "../LotroDatPatcher.h"
+using namespace LOTRO_DAT;
+
+
+// Change these 2 variables to your path and name of .dat file
+const std::string path = "E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
+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;
+
+// Change these variables to true if you want export catecory to databases.
+const bool exportTextsToDb = true;
+const bool exportImagesToDb = true;
+const bool exportFontsToDb = true;
+const bool exportSoundsToDb = true;
+const bool exportTexturesToDb = true;
+const bool exportUnknownToDb = true;
+// There is no need to change anything else
+
+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);
+    char *ttime = std::asctime(std::localtime(&result));
+    char *out_time = new char[25];
+    memcpy(out_time, ttime, 24);
+    out_time[24] = '\0';
+
+    std::string output_dir = std::string("Extracted data\\") + filename + " " + std::string(out_time) + "\\";
+    std::replace(output_dir.begin(), output_dir.end(), ':', '-');
+
+    mkdir(output_dir.c_str(), 744);
+    freopen((output_dir + std::string("errors.log")).c_str(), "w", stderr);
+
+    try {
+        std::cout << "Starting search...\n";
+        DatFile a(path + filename, 0);
+        std::cout << "Total files found: " << a.files_number() << std::endl;
+
+        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";
+
+
+        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;
+            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;
+            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;
+            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;
+            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;
+            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;
+        }
+
+        if (exportImagesToFiles) {
+            mkdir((output_dir + "jpg").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl;
+        }
+
+        if (exportTexturesToFiles) {
+            mkdir((output_dir + "dds").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl;
+        }
+
+        if (exportSoundsToFiles) {
+            mkdir((output_dir + "wav").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl;
+            mkdir((output_dir + "ogg").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl;
+        }
+
+        if (exportFontsToFiles) {
+            mkdir((output_dir + "fonts").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl;
+        }
+
+        if (exportUnknownToFiles) {
+            mkdir((output_dir + "unknown").c_str(), 744);
+            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl;
+        }
+
+    } 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...");
+    }
+    fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
+            float(clock() - begin_time) / CLOCKS_PER_SEC);
+    system("pause");
+    return 0;
+}
+

+ 2 - 3
patch_test.cpp → Source/Tests/patch_test.cpp

@@ -11,7 +11,7 @@
 #define mkdir(dir, mode) _mkdir(dir)
 #endif
 
-#include "LotroDatPatcher.h"
+#include "../LotroDatPatcher.h"
 using namespace LOTRO_DAT;
 
 // Change these 2 variables to your path and name of .dat file
@@ -28,8 +28,7 @@ int main() {
     try {
         std::cout << "Starting search...\n";
         DatFile a(path + filename, 0);
-        std::cout << "Total files found: " << a.dictionary().size() << std::endl;
-
+        std::cout << "Total files found: " << a.files_number() << std::endl;
 
         fprintf(stdout, "Spent %f seconds on running patcher! Thank you for your patience!\n",
                 float(clock() - begin_time) / CLOCKS_PER_SEC);

+ 0 - 234
extract_test.cpp

@@ -1,234 +0,0 @@
-//
-// Created by Иван_Архипов on 30.10.2017.
-//
-#define _CRT_SECURE_NO_WARNINGS
-#include <iostream>
-#include <ctime>
-#include <algorithm>
-
-#ifdef WIN32
-#include <direct.h>
-#define mkdir(dir, mode) _mkdir(dir)
-#endif
-
-#include "LotroDatPatcher.h"
-using namespace LOTRO_DAT;
-
-
-// Change these 2 variables to your path and name of .dat file
-const std::string path = "E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
-const std::string filename = "client_local_English.dat";
-
-// Change these variables to true if you want export catecory to files.
-const bool exportImagesToFiles = false;
-const bool exportFontsToFiles = true;
-const bool exportSoundsToFiles = false;
-const bool exportTexturesToFiles = false;
-const bool exportUnknownToFiles = true;
-
-// Change these variables to true if you want export catecory to databases.
-const bool exportTextsToDb = true;
-const bool exportImagesToDb = false;
-const bool exportFontsToDb = false;
-const bool exportSoundsToDb = false;
-const bool exportTexturesToDb = false;
-const bool exportUnknownToDb = false;
-// There is no need to change anything else
-
-
-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);
-    char *ttime = std::asctime(std::localtime(&result));
-    char *out_time = new char[25];
-    memcpy(out_time, ttime, 24);
-    out_time[24] = '\0';
-
-    std::string output_dir = std::string("Extracted data\\") + filename + " " + std::string(out_time) + "\\";
-    std::replace(output_dir.begin(), output_dir.end(), ':', '-');
-
-    mkdir(output_dir.c_str(), 744);
-    freopen((output_dir + std::string("errors.log")).c_str(), "w", stderr);
-
-    try {
-        std::string txt_dir = "txt\\";
-        std::string jpg_dir = "jpg\\";
-        std::string dds_dir = "dds\\";
-        std::string wav_dir = "wav\\";
-        std::string ogg_dir = "ogg\\";
-        std::string font_dir = "font\\";
-        std::string unk_dir = "unk\\";
-
-        int txt_all = 0, txt_suc = 0;
-        int jpg_all = 0, jpg_suc = 0;
-        int dds_all = 0, dds_suc = 0;
-        int wav_all = 0, wav_suc = 0;
-        int ogg_all = 0, ogg_suc = 0;
-        int font_all = 0, font_suc = 0;
-        int unk_all = 0, unk_suc = 0;
-
-        mkdir(output_dir.c_str(), 744);
-        mkdir((output_dir + txt_dir).c_str(), 744);
-        mkdir((output_dir + jpg_dir).c_str(), 744);
-        mkdir((output_dir + dds_dir).c_str(), 744);
-        mkdir((output_dir + wav_dir).c_str(), 744);
-        mkdir((output_dir + ogg_dir).c_str(), 744);
-        mkdir((output_dir + font_dir).c_str(), 744);
-        mkdir((output_dir + unk_dir).c_str(), 744);
-
-        Database *images = nullptr;
-        Database *sounds = nullptr;
-        Database *texts = nullptr;
-        Database *fonts = nullptr;
-        Database *textures = nullptr;
-        Database *unknown = nullptr;
-
-        if (exportImagesToDb) images = new Database(output_dir + std::string("Images.db"));
-        if (exportSoundsToDb) sounds = new Database(output_dir + std::string("Sounds.db"));
-        if (exportTextsToDb) texts = new Database(output_dir + std::string("Texts.db"));
-        if (exportFontsToDb) fonts = new Database(output_dir + std::string("Fonts.db"));
-        if (exportTexturesToDb) textures = new Database(output_dir + std::string("Textures.db"));
-        if (exportUnknownToDb) unknown = new Database(output_dir + std::string("Unknown.db"));
-
-        std::cout << "Starting search...\n";
-        DatFile a(path + filename, 0);
-        std::cout << "Total files found: " << a.dictionary().size() << std::endl;
-
-        std::cout << "Writing unordered dictionary:\n";
-        FILE *f;
-        fopen_s(&f, (output_dir + "dict.txt").c_str(), "w");
-        fprintf(f, "file_id offset size size2 extension\n");
-        for (auto i : a.dictionary()) {
-            std::string extension = "unk";
-            EXTENSION ext = i.second->ext();
-            if (ext == TXT) extension = "txt";
-            if (ext == JPG) extension = "jpg";
-            if (ext == DDS) extension = "dds";
-            if (ext == WAV) extension = "wav";
-            if (ext == OGG) extension = "ogg";
-            if (ext == FONT) extension = "font";
-            fprintf(f, "%lld %lld %lld %lld %s\n", i.second->file_id(), i.second->file_offset(), i.second->file_size(),
-                    i.second->block_size(), extension.c_str());
-        }
-        fclose(f);
-
-        std::cout << "Beginning unpacking...\n";
-
-        long long all = a.dictionary().size();
-        long long counter = 0;
-
-        for (auto i : a.dictionary()) {
-            EXTENSION ext = i.second->ext();
-            if (ext == TXT) {
-                txt_all++;
-                if (exportTextsToDb)
-                    txt_suc += i.second->ExportFile(
-                            (output_dir + txt_dir + std::to_string(i.second->file_id())).c_str(), texts);
-                //if (exportTextsToFiles) txt_suc += i.second->ExportFile((output_dir + txt_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == JPG) {
-                jpg_all++;
-                if (exportImagesToDb)
-                    jpg_suc += i.second->ExportFile(
-                            (output_dir + jpg_dir + std::to_string(i.second->file_id())).c_str(), images);
-                if (exportImagesToFiles)
-                    jpg_suc += i.second->ExportFile(
-                            (output_dir + jpg_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == DDS) {
-                dds_all++;
-                if (exportTexturesToDb)
-                    dds_suc += i.second->ExportFile(
-                            (output_dir + dds_dir + std::to_string(i.second->file_id())).c_str(), textures);
-                if (exportTexturesToFiles)
-                    dds_suc += i.second->ExportFile(
-                            (output_dir + dds_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == WAV) {
-                wav_all++;
-                if (exportSoundsToDb)
-                    wav_suc += i.second->ExportFile(
-                            (output_dir + wav_dir + std::to_string(i.second->file_id())).c_str(), sounds);
-                if (exportSoundsToFiles)
-                    wav_suc += i.second->ExportFile(
-                            (output_dir + wav_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == OGG) {
-                ogg_all++;
-                if (exportSoundsToDb)
-                    ogg_suc += i.second->ExportFile(
-                            (output_dir + ogg_dir + std::to_string(i.second->file_id())).c_str(), sounds);
-                if (exportSoundsToFiles)
-                    ogg_suc += i.second->ExportFile(
-                            (output_dir + ogg_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == FONT) {
-                font_all++;
-                if (exportFontsToDb)
-                    font_suc += i.second->ExportFile(
-                            (output_dir + font_dir + std::to_string(i.second->file_id())).c_str(), fonts);
-                if (exportFontsToFiles)
-                    font_suc += i.second->ExportFile(
-                            (output_dir + font_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            if (ext == UNKNOWN) {
-                unk_all++;
-                if (exportUnknownToDb)
-                    unk_suc += i.second->ExportFile(
-                            (output_dir + unk_dir + std::to_string(i.second->file_id())).c_str(), unknown);
-                if (exportUnknownToFiles)
-                    unk_suc += i.second->ExportFile(
-                            (output_dir + unk_dir + std::to_string(i.second->file_id())).c_str());
-            }
-
-            counter++;
-            if ((counter - 1) * 100ll / all != counter * 100ll / all) {
-                fprintf(stdout, "Done: %lld%%\n", counter * 100ll / all);
-            }
-        }
-
-        delete images;
-        delete sounds;
-        delete texts;
-        delete fonts;
-        delete textures;
-        delete unknown;
-
-        std::cout << "Total found:" << std::endl;
-        std::cout << "Txt: " << txt_all << std::endl
-                  << "JPG: " << jpg_all << std::endl
-                  << "DDS: " << dds_all << std::endl
-                  << "WAV: " << wav_all << std::endl
-                  << "OGG: " << ogg_all << std::endl
-                  << "Fonts " << font_all << std::endl
-                  << "Unknown: " << unk_all << std::endl;
-
-        std::cout << "Total exported (counted both to files and databases):" << std::endl;
-        std::cout << "Txt: " << txt_suc << std::endl
-                  << "JPG: " << jpg_suc << std::endl
-                  << "DDS: " << dds_suc << std::endl
-                  << "WAV: " << wav_suc << std::endl
-                  << "OGG: " << ogg_suc << std::endl
-                  << "Fonts " << font_suc << std::endl
-                  << "Unknown: " << unk_suc << std::endl;
-
-        fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
-                float(clock() - begin_time) / CLOCKS_PER_SEC);
-        system("pause");
-    } 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...");
-    }
-    return 0;
-}
-