Browse Source

Updated library to 6.0.1

Ivan Arkhipov 6 years ago
parent
commit
9788f0047b

+ 9 - 2
helper.cpp

@@ -324,6 +324,7 @@ int Helper::dateToTimestamp(QString customDateString, QString format){
 void Helper::installMicroPatch(){
     App *app = &App::getInstance();
     if(app->config->getValue("Updates", "micro") != "true") return;
+
     app->helper->setState("busy");
     app->window->ui->hintLabel->setText("Установка последних обновлений");
     app->window->ui->exthintLabel->setText("Идет проверка и установка новых обновлений");
@@ -345,17 +346,21 @@ void Helper::prepareMicroPatch(){
     app->helper->setState("busy");
     app->window->ui->hintLabel->setText("Загрузка последних обновлений");
     app->window->ui->exthintLabel->setText("Подождите пока загрузятся последние изменения в системе переводов");
+
     QString date = app->config->getValue("Updates", "update");
+    if (date == QDate::currentDate().toString("yyyy-MM-dd"))
+        return;
 
     if (date == "false" || date == "-1")
         date = QDate::currentDate().toString("yyyy-MM-dd");
 
     QTime time = QTime::currentTime();
     int seconds = QTime(0, 0, 0).secsTo(time);
-    int timestamp = app->helper->dateToTimestamp(date + " " + time.toString("hh:mm:ss"), "yyyy-MM-dd hh:mm:ss") - 2592000;
+    //int timestamp = app->helper->dateToTimestamp(date + " " + time.toString("hh:mm:ss"), "yyyy-MM-dd hh:mm:ss") - seconds - 1209600;
+    int timestamp = app->helper->dateToTimestamp(date, "yyyy-MM-dd") - 1209600;
 
     qInfo("%s:%i: %s", __FILE__, __LINE__, "Опция активна. Начинаем загрузку обновлений");
-    app->network->micropatch = QApplication::applicationDirPath() + "/data/micro/" + QString::number(timestamp + seconds) + ".db";
+    app->network->micropatch = QApplication::applicationDirPath() + "/data/micro/" + QString::number(timestamp) + ".db";
     if(!app->helper->fileExists(app->network->micropatch)){
         qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Файл патча: ", app->helper->stringToChar(app->network->micropatch));
         app->network->micropatch = app->network->getMicroPath(timestamp);
@@ -382,6 +387,8 @@ void Helper::applyMicroPatch(){
     //for (int i = 0; i < 5; i++) app->datfiles[i].CommitChanges();
     app->db->CloseDatabase();
 
+    app->config->setValue("Updates", "update", QDate::currentDate().toString("yyyy-MM-dd"));
+
     app->helper->setState("free");
     qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
     app->logSectionEnd();

BIN
lib/lib/libLotroDat.dll.a


BIN
lib/lib/libLotroDat_static.a


+ 0 - 289
lib/src/BinaryData.cpp

@@ -1,289 +0,0 @@
-//
-// Created by Иван_Архипов on 31.10.2017.
-//
-
-#include "BinaryData.h"
-#include "zlib.h"
-#include "EasyLogging++/easylogging++.h"
-
-#include <algorithm>
-
-extern  "C++"
-{
-namespace LOTRO_DAT {
-
-    BinaryData::BinaryData() {
-        data_ = nullptr;
-        size_ = 0;
-    }
-
-    BinaryData::BinaryData(const BinaryData &d) {
-        size_ = d.size_;
-        data_ = new unsigned char[size_];
-        memcpy(data_, d.data_, size_);
-    }
-
-    BinaryData::BinaryData(const char* data, unsigned int size) {
-        size_ = size;
-        data_ = new unsigned char[size_];
-        memcpy(data_, data, size_);
-    }
-
-    BinaryData::BinaryData(unsigned int size) {
-        data_ = new unsigned char[size];
-        for (size_t i = 0; i < size; i++)
-            data_[i] = 0;
-        size_ = size;
-    }
-
-    BinaryData::~BinaryData() {
-        delete[] data_;
-    }
-
-    unsigned char&  BinaryData::operator[](const unsigned int &pos) {
-        if (pos >= size_)
-            LOG(ERROR) << "Bad BinaryData::operator[]. Position " << pos
-                       << " is out of range in BinaryData with size " << size_;
-        return data_[pos];
-    }
-
-    BinaryData BinaryData::operator +(const BinaryData &b) {
-        BinaryData res(size_ + b.size());
-        if (size_ > 0)
-            memcpy(res.data_, data_, size_);
-        if (b.size() > 0)
-            memcpy(res.data_ + size_, b.data_, b.size_);
-        return res;
-    }
-
-    // Translates T bytes from data into number using UTF-16LE encoding of the .dat file
-    template<unsigned int T>
-    long long BinaryData::ToNumber(const long long &pos) const {
-        long long ans = 0;
-
-        if (pos + T > size_) {
-            LOG(ERROR) << "Reading " << T << " bytes from " << pos << " offset with BinaryData size " << size_
-                       << " Reached end of BinaryData!";
-            return 0;
-        }
-
-        for (int i = T - 1; i >= 0; i--)
-            ans = ((ans << 8ll) | data_[pos + i]);
-
-        return ans;
-    }
-
-    // Translates T bytes from data into number in raw format
-    template<unsigned int T>
-    long long BinaryData::ToNumberRAW(const long long &pos) const {
-        long long ans = 0;
-
-        if (pos + T > size_) {
-            LOG(ERROR) << "Reading " << T << " bytes from " << pos << " offset with BinaryData size " << size_
-                       << " Reached end of BinaryData!";
-            return 0;
-        }
-
-        for (unsigned i = 0; i < T; i++)
-            ans = ((ans << 8ll) | data_[pos + i]);
-
-        return ans;
-    }
-
-    // Makes data from specified T bytes of number in Little Endian encoding
-    template<unsigned int T>
-    BinaryData BinaryData::FromNumber(const long long &number) {
-        if (T <= 0) {
-            LOG(ERROR) << "Trying to make data from amount of bytes < 0";
-            return BinaryData(0);
-        }
-
-        BinaryData data(T);
-        for (size_t i = 0; i < T; i++)
-            data.data_[i] = (unsigned char)((number >> (8 * i)) & 0xFF);
-        return data;
-    }
-
-    // Makes data from specified T bytes of number in raw
-    template<unsigned int T>
-    BinaryData BinaryData::FromNumberRAW(const long long &number) {
-        if (T <= 0) {
-            LOG(ERROR) << "Trying to make data from amount of bytes < 0";
-            return BinaryData(0);
-        }
-
-        BinaryData data = FromNumber<T>(number);
-        std::reverse(data.data_, data.data_ + data.size());
-        return data;
-    }
-
-    BinaryData &BinaryData::operator=(const BinaryData &data) {
-        if (&data == this)
-            return *this;
-
-        if (size_ != 0 && data_ != nullptr)
-            delete[] data_;
-
-        size_ = data.size_;
-        data_ = nullptr;
-
-        if (size_ != 0) {
-            data_ = new unsigned char[size_];
-            memcpy(data_, data.data_, size_);
-        }
-
-        return *this;
-    }
-
-    size_t BinaryData::size() const {
-        return size_;
-    }
-
-    unsigned char *BinaryData::data() const {
-        return data_;
-    }
-
-    bool BinaryData::WriteToFile(const char *filename) const {
-        FILE *f;
-        f = fopen64(filename, "wb");
-        if (f == nullptr) {
-            LOG(ERROR) << "File " << std::string(filename) << " doesn't exist or is unreachable.. Cannot write data";
-            return false;
-        }
-
-        fwrite(data(), size(), 1, f);
-        fclose(f);
-        return true;
-    }
-
-    bool BinaryData::WriteToFile(const std::string &filename) const {
-        return WriteToFile(filename.c_str());
-    }
-
-    void BinaryData::ReadFromFile(const char *filename) {
-        FILE *f;
-        fopen_s(&f, filename, "rb");
-        if (f == nullptr) {
-            LOG(ERROR) << "File " << std::string(filename) << " doesn't exist.. Retuning null data";
-            size_ = 0;
-            delete[] data_;
-            return;
-        }
-
-        _fseeki64(f, 0, SEEK_END);
-        long long file_size = ftell(f);
-        _fseeki64(f, 0, SEEK_SET);
-
-        BinaryData temp_data = BinaryData(unsigned(file_size));
-
-        fread(temp_data.data_, temp_data.size_, 1, f);
-        *this = temp_data;
-        fclose(f);
-    }
-
-    void BinaryData::ReadFromFile(const std::string &filename) {
-        ReadFromFile(filename.c_str());
-    }
-
-    bool BinaryData::CheckCompression() const {
-        if (size() < 10)
-            return false;
-        auto header = ToNumberRAW<2>(4);
-        return (header == 0x7801 || header == 0x789C || header == 0x78DA);
-    }
-
-    BinaryData BinaryData::DecompressData(unsigned int offset) const {
-        const unsigned max_unpacked_size = 1024 * 1024 * 40; // Setting 40 MB as a maximum unpacked data;
-
-        BinaryData decompressed(max_unpacked_size);
-
-        uLongf new_size = max_unpacked_size;
-        int res = uncompress(decompressed.data_, &new_size, data_ + offset, size_ - offset);
-
-        if (res != 0) {
-            LOG(ERROR) << "Failed to decompress. Function returned " << res;
-            return BinaryData(0);
-        }
-
-        decompressed.size_ = (unsigned int)new_size;
-        return decompressed;
-    }
-
-    BinaryData BinaryData::CompressData(unsigned int offset) const {
-        const unsigned max_file_size = 1024 * 1024 * 40; // Setting 40 MB as a maximum packed data;
-
-        BinaryData compressed(max_file_size);
-
-        uLongf new_size = max_file_size;
-        int res = compress2(compressed.data_, &new_size, data_ + offset, size_ - offset, 9);
-
-        if (res != 0) {
-            LOG(ERROR) << "Failed to compress. Function returned " << res;
-            return BinaryData(0);
-        }
-
-        compressed.size_ = (unsigned int)new_size;
-        return compressed;
-    }
-
-    BinaryData BinaryData::CutData(long long first, long long last) const {
-        if (last < 0)
-            last = size();
-
-        if (last > size()) {
-            LOG(ERROR) << "Unable to cut data - parameter last is out of range";
-            return BinaryData(0);
-        }
-
-        BinaryData newdata(unsigned(last - first));
-        memcpy(newdata.data(), data() + first, newdata.size());
-        return newdata;
-    }
-
-    bool BinaryData::operator==(const BinaryData &b) const {
-        if (size() != b.size())
-            return false;
-        for (size_t i = 0; i < size(); i++)
-            if (data_[i] != b.data_[i])
-                return false;
-        return true;
-    }
-
-    bool BinaryData::operator!=(const BinaryData &b) const {
-        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()) {
-            LOG(ERROR) << "data for appending has more bytes than BinaryData size!";
-            return;
-        }
-        memcpy(data_ + append_offset, b.data_, b.size_);
-    }
-
-
-    template long long BinaryData::ToNumber<1>(long long const&) const;
-    template long long BinaryData::ToNumber<2>(long long const&) const;
-    template long long BinaryData::ToNumber<4>(long long const&) const;
-    template long long BinaryData::ToNumber<8>(long long const&) const;
-
-    template BinaryData BinaryData::FromNumber<1>(const long long &);
-    template BinaryData BinaryData::FromNumber<2>(const long long &);
-    template BinaryData BinaryData::FromNumber<4>(const long long &);
-    template BinaryData BinaryData::FromNumber<8>(const long long &);
-
-    template long long BinaryData::ToNumberRAW<1>(long long const&) const;
-    template long long BinaryData::ToNumberRAW<2>(long long const&) const;
-    template long long BinaryData::ToNumberRAW<4>(long long const&) const;
-    template long long BinaryData::ToNumberRAW<8>(long long const&) const;
-
-    template BinaryData BinaryData::FromNumberRAW<1>(const long long &);
-    template BinaryData BinaryData::FromNumberRAW<2>(const long long &);
-    template BinaryData BinaryData::FromNumberRAW<4>(const long long &);
-    template BinaryData BinaryData::FromNumberRAW<8>(const long long &);
-}
-}

+ 0 - 1254
lib/src/DatFile.cpp

@@ -1,1254 +0,0 @@
-//
-// Created by Иван_Архипов on 31.10.2017.
-//
-
-#include "DatFile.h"
-#include "BinaryData.h"
-
-#include "SubDirectory.h"
-#include "Subfile.h"
-#include "SubfileData.h"
-
-#include <EasyLogging++/easylogging++.h>
-#include <unistd.h>
-#include <algorithm>
-#include <iterator>
-#include <locale>
-
-#define ELPP_FEATURE_CRASH_LOG
-INITIALIZE_EASYLOGGINGPP
-
-#ifdef WIN32
-#define fseek _fseeki64
-#define ftell _ftelli64
-#endif
-
-extern "C++"
-{
-namespace LOTRO_DAT {
-
-    //------------------------------------------------//
-    // INIT SECTION
-    //------------------------------------------------//
-
-    DatFile::DatFile() {
-        dat_state_ = CLOSED;
-        root_directory_ = nullptr;
-        file_handler_ = nullptr;
-        free_buffered_size_ = 0;
-
-        orig_dict_.clear();
-        patch_dict_.clear();
-        dictionary_.clear();
-
-        el::Configurations defaultConf;
-        defaultConf.setToDefault();
-        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");
-        defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
-        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
-        defaultConf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1"); // Flush after every one log
-
-        defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
-        defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "dat_library_debug.log");
-
-        el::Loggers::reconfigureAllLoggers(defaultConf);
-        LOG(INFO) << "==================================================================";
-        LOG(INFO) << "Starting new DatFile class instance";
-    }
-
-    DAT_RESULT DatFile::InitDatFile(const std::string &filename, int dat_id) {
-        LOG(DEBUG) << "Started initialisation of DatFile " << filename;
-        if (dat_state_ != CLOSED && filename == filename_) {
-            LOG(DEBUG) << "Trying to reopen the same file: " << filename << ". Doing nothing.";
-            return SUCCESS;
-        }
-
-        if (dat_state_ != CLOSED && filename != filename_) {
-            LOG(DEBUG) << "DatFile wasn't closed yet. Closing in order to reopen.";
-            if (CloseDatFile() != SUCCESS) {
-                LOG(ERROR) << "Unable to perform CloseDatFile()! Aborting initialization!";
-                return FAILED;
-            }
-        }
-
-        dat_id_ = dat_id;
-        dat_state_ = CLOSED;
-        current_locale_ = ORIGINAL;
-        root_directory_ = nullptr;
-        file_handler_ = nullptr;
-        free_buffered_size_ = 0;
-        filename_ = "none";
-
-        DAT_RESULT result;
-        DAT_RESULT return_value = SUCCESS;
-
-        result = OpenDatFile(filename.c_str());
-        if (result != SUCCESS) {
-            LOG(ERROR) << "Unable to perform opening file. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        result = ReadSuperBlock();
-        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 <= 0) {
-            LOG(ERROR) << "Unable to make directories. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        result = MakeDictionary();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to make dictionary. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        result = InitLocales();
-        if (result <= 0) {
-            LOG(ERROR) << "Unable to initialize locales. Aborting.";
-            CloseDatFile();
-            return result;
-        }
-        return_value = std::max(return_value, result);
-
-        LOG(INFO) << "File " << filename << " opened successfully!";
-        filename_ = filename;
-        dat_state_ = READY;
-
-        LOG(INFO) << "Making last preparations...";
-        return_value = std::max(return_value, result);
-
-        PerformDictionaryCheck();
-
-        if (return_value >= 2) {
-            LOG(WARNING) << "Dat file could be corrupted. Trying to delete corrupted dictionary rows";
-            if (RepairDatFile() != SUCCESS)
-                return CRITICAL_DAT_ERROR;
-        }
-
-        if (CheckIfUpdatedByGame()) {
-            LOG(INFO) << ".dat file was updated by game! Need to reinitialize files and directories!";
-            CloseDatFile();
-            InitDatFile(filename, dat_id);
-        }
-
-
-        dat_without_patches_ = CheckIfNotPatched();
-        LOG(INFO) << "Preparations made successfully! Init return value = " << return_value;
-        return return_value;
-    }
-
-    DAT_RESULT DatFile::OpenDatFile(const char *dat_name) {
-        LOG(DEBUG) << "Started opening DatFile";
-        if (dat_state_ != CLOSED) {
-            CloseDatFile();
-        }
-
-        file_handler_ = fopen(dat_name, "r+b");
-
-        if (file_handler_ == nullptr) {
-            LOG(ERROR) << "Unable to open file " << dat_name;
-            return NO_FILE_ERROR;
-        }
-
-        fseek(file_handler_, 0, SEEK_END);
-        actual_dat_size_ = ftell(file_handler_);
-        fseek(file_handler_, 0, SEEK_SET);
-
-        dat_state_ = SUCCESS_OPENED;
-        LOG(DEBUG) << "Successfully opened DatFile";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ReadSuperBlock() {
-        LOG(DEBUG) << "Started reading superblock";
-        if (dat_state_ != SUCCESS_OPENED) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_OPENED. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        BinaryData data(1024);
-        ReadData(data, 1024);
-
-        constant1_ = data.ToNumber<4>(0x100);
-        constant2_ = data.ToNumber<4>(0x140);
-        version1_ = data.ToNumber<4>(0x14C);
-        file_size_ = data.ToNumber<4>(0x148);
-        version2_ = data.ToNumber<4>(0x150);
-        fragmentation_journal_offset_ = data.ToNumber<4>(0x154);
-        fragmentation_journal_end_ = data.ToNumber<4>(0x158);
-        fragmentation_journal_size_ = data.ToNumber<4>(0x15C);
-        root_directory_offset_ = data.ToNumber<4>(0x160);
-        free_dat_size_ = data.ToNumber<4>(0x19C);
-
-        if (constant1_ != 0x4C5000) {
-            LOG(ERROR) << "variable at position 0x100 is not equal to .dat file constant!";
-            return INCORRECT_SUPERBLOCK_ERROR;
-        }
-        if (constant2_ != 0x5442) {
-            LOG(ERROR) << "variable at position 0x140 is not equal to .dat file constant!";
-            return INCORRECT_SUPERBLOCK_ERROR;
-        }
-
-        if (file_size_ != actual_dat_size_) {
-            LOG(ERROR) << "variable at 0x148 position is not equal to .dat file size!";
-            //return CORRUPTED_FILE_WARNING;
-        }
-
-        dat_state_ = SUCCESS_SUPERBLOCK;
-        LOG(DEBUG) << "Superblock read successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::MakeDirectories() {
-        LOG(DEBUG) << "Started making directories";
-        if (dat_state_ != SUCCESS_SUPERBLOCK) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_SUPERBLOCK. Cannot make directories.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        root_directory_ = new SubDirectory((unsigned) root_directory_offset_, this);
-        dat_state_ = SUCCESS_DIRECTORIES;
-
-        LOG(DEBUG) << "Directories made successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::MakeDictionary() {
-        LOG(DEBUG) << "Started making dictionary";
-        if (dat_state_ != SUCCESS_DIRECTORIES) {
-            LOG(ERROR) << "Dat state isn't SUCCESS_DIRECTORIES. Cannot make directories.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        if (root_directory_ == nullptr) {
-            LOG(ERROR) << "root_directory is nullptr!!";
-            return INIT_ERROR;
-        }
-
-        root_directory_->MakeDictionary(dictionary_);
-        dat_state_ = SUCCESS_DICTIONARY;
-        LOG(DEBUG) << "Dictionary made successfull";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::InitLocales() {
-        LOG(INFO) << "Initialising locales...";
-        BinaryData dicts_data(4);
-
-        ReadData(dicts_data, 4, 300);
-        long long dict_offset = dicts_data.ToNumber<4>(0);
-
-        if (dict_offset == 0 || dict_offset + 8 >= actual_dat_size_) {
-            LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
-            return SUCCESS;
-        }
-
-        ReadData(dicts_data, 4, dict_offset);
-        long long dict_size = dicts_data.ToNumber<4>(0);
-
-        ReadData(dicts_data, 4, dict_offset + 4);
-        long long dict_version = dicts_data.ToNumber<4>(0);
-        LOG(INFO) << "Dictionary size is " << dict_size << ". Version is " << dict_version;
-
-        if (dict_version != 100) {
-            LOG(WARNING) << "DICTIONARY IS OLD!!!";
-            return SUCCESS;
-        }
-
-        dicts_data = BinaryData((unsigned)dict_size);
-        ReadData(dicts_data, dict_size, dict_offset + 8);
-
-        if (dicts_data.size() < 15) {
-            LOG(ERROR) << "Incorrect dictionary. Passing without it.";
-            orig_dict_.clear();
-            patch_dict_.clear();
-            WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-            dat_state_ = UPDATED;
-            dat_without_patches_ = true;
-            return SUCCESS;
-        }
-
-        BinaryData hi_data = dicts_data.CutData(0, 15) + BinaryData("\0", 1);
-        std::string hi = std::string((char *) (hi_data.data()));
-        LOG(DEBUG) << "hi info is " << hi;
-
-        if (hi != "Hi from Gi1dor!") {
-            LOG(WARNING) << "Didn't receive 'hi' from Gi1dor... Initialising locale dicts as empty";
-            LOG(INFO) << "Could't init locales' file... Continuing without them";
-            return SUCCESS;
-        }
-
-        int offset = 15;
-        BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
-        std::string locale((char *) (current_locale_data.data()));
-        offset += 4;
-        LOG(DEBUG) << "current locale:" << locale;
-
-        if (locale != "PATC" && locale != "ORIG") {
-            LOG(WARNING) << "Incorrect locale... Initialising locale dicts as empty";
-            LOG(INFO) << "Could't recognize locale... Continuing without locales";
-            return SUCCESS;
-        }
-        current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
-
-        // 15 bytes for "Hi from Gi1dor"
-        // 4 bytes for LOCALE
-        // 4 bytes for orig_dict.size()
-        // (32 + 4) * orig_dict.size() bytes for orig_dict data
-        // 4 bytes for patch_dict.size()
-        // (32 + 4) * patch_dict.size() bytes for patch_dict data
-        // 4 bytes for inactive_categories dict
-        // 4 * inactive_categories.size() bytes for inactive_categories data
-
-        size_t orig_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
-        offset += 4;
-        for (size_t i = 0; i < orig_dict_size; i++) {
-            auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
-            orig_dict_[file->file_id()] = file;
-            offset += 32;
-            orig_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
-            offset += 4;
-
-            if (orig_dict_[file->file_id()]->category == 0)
-                LOG(DEBUG) << "file category is undefined (0)!";
-        }
-
-        size_t patch_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
-        offset += 4;
-        for (size_t i = 0; i < patch_dict_size; i++) {
-            auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
-            patch_dict_[file->file_id()] = file;
-            offset += 32;
-            patch_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
-            offset += 4;
-            if (patch_dict_[file->file_id()]->category == 0)
-                LOG(DEBUG) << "file category is undefined (0)!";
-
-        }
-
-        size_t active_patches_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
-        offset += 4;
-        for (size_t i = 0; i < active_patches_dict_size; i++) {
-            inactive_categories.insert(dicts_data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        LOG(INFO) << "There are " << patch_dict_.size() << " files in patch locale dictionary";
-        LOG(INFO) << "There are " << orig_dict_.size() << " files in original locale dictionary";
-        std::string inactive_cat_s;
-        for (auto i : inactive_categories) {
-            inactive_cat_s += std::to_string(i) + " ";
-        }
-        LOG(INFO) << "Unactive patches now: " << inactive_cat_s;
-        LOG(INFO) << "Finished initialising locales";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::PerformDictionaryCheck() {
-        for (auto mpair : dictionary_) {
-            auto file = mpair.second;
-            auto file_id = mpair.first;
-            if (CorrectSubfile(file))
-                continue;
-
-            if (current_locale_ == PATCHED && orig_dict_.count(file_id) > 0) {
-                LOG(WARNING) << "Potential incorrect patched version of file " << file_id << ". Switching to original.";
-                dictionary_[file_id] = orig_dict_[file_id];
-            }
-
-            if (!CorrectSubfile(file)) {
-                LOG(ERROR) << "Incorrect file " << file_id << ". It's offset is said as " << file->file_offset()
-                           << ". Erasing it from dictionary.";
-                dictionary_.erase(file_id);
-            }
-        }
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // CLOSE SECTION
-    //------------------------------------------------//
-
-    DatFile::~DatFile() {
-        CloseDatFile();
-    }
-
-    DAT_RESULT DatFile::CloseDatFile() {
-        LOG(INFO) << "Closing DatFile";
-        if (dat_state_ == CLOSED) {
-            LOG(INFO) << "DatFile is already closed. Nothing to do";
-            return SUCCESS;
-        }
-
-        // Committing changes and updating/writing locales and header info
-
-        if (!pending_dictionary_.empty() || dat_state_ == UPDATED) {
-            CommitLocales();
-            CommitDirectories();
-            //ModifyFragmentationJournal();
-            //free_dat_size_ = 128248;
-            //fragmentation_journal_end_ = 0;
-            //fragmentation_journal_size_ = 1;
-            //UpdateHeader();
-        }
-
-        current_locale_ = ORIGINAL;
-
-        if (file_handler_ != nullptr) {
-            fclose(file_handler_);
-        }
-        SubDirectory::visited_subdirectories_.clear();
-        delete root_directory_;
-        //truncate64(filename_.c_str(), file_size_);
-
-        free_buffered_size_ = 0;
-
-        filename_ = "none";
-
-        orig_dict_.clear();
-        patch_dict_.clear();
-        pending_patch_.clear();
-        inactive_categories.clear();
-
-        file_handler_ = nullptr;
-        root_directory_ = nullptr;
-
-
-        pending_dictionary_.clear();
-        dictionary_.clear();
-
-        constant1_ = 0;
-        constant2_ = 0;
-        file_size_ = 0;
-        version1_ = 0;
-        version2_ = 0;
-        fragmentation_journal_size_ = 0;
-        fragmentation_journal_end_ = 0;
-        root_directory_offset_ = 0;
-        fragmentation_journal_offset_ = 0;
-
-        dat_state_ = CLOSED;
-
-        dat_id_ = -1;
-
-
-        LOG(INFO) << "File closed successfully.";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::CommitLocales() {
-        LOG(INFO) << "Committing locales...";
-        // 15 bytes for "Hi from Gi1dor"
-        // 4 bytes for LOCALE
-        // 4 bytes for orig_dict.size()
-        // (32 + 4) * orig_dict.size() bytes for orig_dict data
-        // 4 bytes for patch_dict.size()
-        // (32 + 4) * patch_dict.size() bytes for patch_dict data
-        // 4 bytes for inactive_categories list
-        // 4 * inactive_categories.size() bytes for inactive_categories data
-
-        BinaryData binary_data = BinaryData(14 + 15 + 4
-                                            + 4 + (32 + 4) * orig_dict_.size()
-                                            + 4 + (32 + 4) * patch_dict_.size()
-                                            + 4 + 4 * inactive_categories.size());
-
-        size_t current_size = 0;
-        binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
-        current_size += 15;
-
-        binary_data.Append(BinaryData((current_locale_ == ORIGINAL ? "ORIG" : "PATC"), 4), current_size);
-        current_size += 4;
-
-        binary_data.Append(BinaryData::FromNumber<4>(orig_dict_.size()), current_size);
-        current_size += 4;
-
-        for (auto file : orig_dict_) {
-            binary_data.Append(file.second->MakeHeaderData(), current_size);
-            current_size += 32;
-            binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
-            current_size += 4;
-        }
-
-        binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
-        current_size += 4;
-
-        for (auto file : patch_dict_) {
-            binary_data.Append(file.second->MakeHeaderData(), current_size);
-            current_size += 32;
-            binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
-            current_size += 4;
-        }
-
-        binary_data.Append(BinaryData::FromNumber<4>(inactive_categories.size()), current_size);
-        current_size += 4;
-        for (auto patch_id : inactive_categories) {
-            binary_data.Append(BinaryData::FromNumber<4>(patch_id), current_size);
-            current_size += 4;
-        }
-
-
-        BinaryData dicts_data(4);
-        ReadData(dicts_data, 4, 300);
-        long long dict_offset = dicts_data.ToNumber<4>(0);
-        ReadData(dicts_data, 4, dict_offset);
-        long long dict_size = dicts_data.ToNumber<4>(0);
-
-        if (binary_data.size() > dict_size || dict_offset == 0) {
-            WriteData(BinaryData::FromNumber<4>(file_size_), 4, 300);
-
-            WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 4, file_size_);
-            WriteData(BinaryData::FromNumber<4>(100), 4, file_size_ + 4);
-            WriteData(binary_data, binary_data.size(), file_size_ + 8);
-            file_size_ += binary_data.size() + 8;
-
-            // Adding space for 25 megabytes locales file in total.
-            BinaryData nulls(unsigned(20 * 1024 * 1024));
-            WriteData(nulls, nulls.size(), file_size_);
-            file_size_ += nulls.size();
-
-        } else {
-            WriteData(BinaryData::FromNumber<4>(std::max(binary_data.size(), 20u * 1024u * 1024u)), 4, dict_offset);
-            WriteData(BinaryData::FromNumber<4>(100), 4, dict_offset + 4);
-            WriteData(binary_data, binary_data.size(), dict_offset + 8);
-        }
-        LOG(INFO) << "Locales commited successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::CommitDirectories() {
-        for (auto file_id : pending_dictionary_) {
-            if (dictionary_[file_id] == nullptr || !CorrectSubfile(dictionary_[file_id]))
-                continue;
-            WriteData(dictionary_[file_id]->MakeHeaderData(), 32, dictionary_[file_id]->dictionary_offset());
-        }
-        pending_dictionary_.clear();
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ModifyFragmentationJournal() {
-        if (fragmentation_journal_size_ == 0)
-            return SUCCESS;
-        LOG(DEBUG) << "Modifying fragmentation journal";
-        BinaryData data(4);
-        ReadData(data, 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_);
-        LOG(INFO) << "FREE_SIZE BLOCK = " << data.ToNumber<4>(0);
-
-        long long free_size = data.ToNumber<4>(0);
-        long long free_offset = file_size_;
-
-        BinaryData nulldata = BinaryData(unsigned(free_size));
-        WriteData(nulldata, nulldata.size(), file_size_);
-        file_size_ += nulldata.size();
-
-        WriteData(BinaryData::FromNumber<4>(free_size), 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_);
-        WriteData(BinaryData::FromNumber<4>(free_offset), 4, fragmentation_journal_offset_ + 8 * fragmentation_journal_size_ + 4);
-
-        //nulldata = BinaryData(8);
-        //WriteData(nulldata, nulldata.size(), fragmentation_journal_offset_ + 16);
-        LOG(DEBUG) << "Finished modifying fragmentation journal";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::UpdateHeader() {
-        LOG(DEBUG) << "Updating header";
-        WriteData(BinaryData::FromNumber<4>(constant1_), 4, 0x100);
-        WriteData(BinaryData::FromNumber<4>(constant2_), 4, 0x140);
-        //WriteData(BinaryData::FromNumber<4>(    0     ), 4, 0x144);
-        WriteData(BinaryData::FromNumber<4>(file_size_), 4, 0x148);
-        WriteData(BinaryData::FromNumber<4>(version1_ ), 4, 0x14C);
-        WriteData(BinaryData::FromNumber<4>(version2_ ), 4, 0x150);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset_), 4, 0x154);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_end_), 4, 0x158);
-        WriteData(BinaryData::FromNumber<4>(fragmentation_journal_size_), 4, 0x15C);
-        WriteData(BinaryData::FromNumber<4>(root_directory_offset_), 4, 0x160);
-        WriteData(BinaryData::FromNumber<4>(free_dat_size_), 4, 0x19C);
-        LOG(DEBUG) << "Finished updating header";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::RepairDatFile() {
-        for (auto file : dictionary_) {
-            auto subfile = file.second;
-            auto file_id = file.first;
-
-            if (CorrectSubfile(subfile))
-                continue;
-
-            orig_dict_.clear();
-            patch_dict_.clear();
-            return SUCCESS;
-
-            if (orig_dict_.count(file_id) == 0 || subfile->file_offset() == orig_dict_[file_id]->file_offset())
-                return CRITICAL_DAT_ERROR;
-
-            *dictionary_[file_id] = *orig_dict_[file_id];
-            patch_dict_.erase(file_id);
-            orig_dict_.erase(file_id);
-        }
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // DAT INFO SECTION
-    //------------------------------------------------//
-
-    DAT_STATE DatFile::DatFileState() const {
-        return dat_state_;
-    }
-
-    long long DatFile::files_number() const {
-        return dictionary_.size();
-    }
-
-    //------------------------------------------------//
-    // EXTRACT SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::ExtractFile(long long file_id, const std::string &path) {
-        LOG(DEBUG) << "Extracting file " << file_id << " to path " << path;
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
-
-        if (file_data.size() == 0) {
-            LOG(ERROR) << "File data is empty. Aborting extraction.";
-            return NO_FILE_ERROR;
-        }
-
-        SubfileData export_data = dictionary_[file_id]->PrepareForExport(file_data);
-
-        if (export_data.Empty()) {
-            LOG(ERROR) << "Export data is empty. Aborting extraction.";
-            return NO_FILE_ERROR;
-        }
-
-        if (export_data.binary_data.WriteToFile(path + export_data.options["ext"].as<std::string>()) != SUCCESS) {
-            LOG(ERROR) << "Cannot write to file.";
-            return WRITE_TO_FILE_ERROR;
-        }
-        LOG(DEBUG) << "File " << file_id << " extracted successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ExtractFile(long long file_id, Database *db) {
-        LOG(DEBUG) << "Extracting file " << file_id << " to database.";
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        BinaryData file_data = GetFileData(dictionary_[file_id], 8);
-
-        if (file_data.Empty()) {
-            LOG(WARNING) << "File with id " << dictionary_[file_id]->file_id() << " is empty. Passing it.";
-            return SUCCESS;
-        }
-
-        SubfileData export_data;
-        export_data = dictionary_[file_id]->PrepareForExport(file_data);
-        export_data.options["did"] = dat_id_;
-
-        if (export_data == SubfileData()) {
-            LOG(WARNING) << "File with id " << dictionary_[file_id]->file_id() << " is empty or incorrect.";
-            return SUCCESS;
-        }
-
-        try {
-            db->PushFile(export_data);
-        } catch (std::exception &e) {
-            LOG(ERROR) << "Caught " << e.what() << " exception.";
-            return FAILED;
-        }
-        LOG(DEBUG) << "File " << file_id << " extracted successfully";
-        return SUCCESS;
-    }
-
-    int DatFile::ExtractAllFilesByType(FILE_TYPE type, std::string path) {
-        LOG(INFO) << "Extracting all files to path " << path;
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        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);
-            }
-        }
-        LOG(INFO) << "Successfully extracted " << success << " files";
-        return success;
-    }
-
-    int DatFile::ExtractAllFilesByType(FILE_TYPE type, Database *db) {
-        LOG(INFO) << "Extracting all files to database...";
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        int success = 0;
-        for (auto i : dictionary_) {
-            FILE_TYPE file_type = i.second->FileType();
-            if (file_type == type) {
-                success += (ExtractFile(i.second->file_id(), db) == SUCCESS ? 1 : 0);
-            }
-        }
-        LOG(INFO) << "Extracted " << success << " files";
-        return success;
-    }
-
-    //------------------------------------------------//
-    // PATCH SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::PatchFile(const SubfileData &data) {
-        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>() << ".";
-        actual_dat_size_ = std::max(file_size_, actual_dat_size_);
-
-        if (!dat_without_patches_) {
-            file_size_ = actual_dat_size_;
-        }
-
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        auto file_id = data.options["fid"].as<long long>();
-
-        if (dictionary_.count(file_id) == 0) {
-            LOG(ERROR) << "Cannot patch file - there is no file in dictionary with file_id = " << file_id;
-            return NO_FILE_ERROR;
-        }
-        Subfile *file = dictionary_[file_id];
-
-//        if (!CorrectSubfile(file)) {
-//            if (current_locale_ == PATCHED && patch_dict_.count(file_id) > 0) {
-//                LOG(WARNING) << "Patched subfile header with id = " << file->file_id() << " differs from original version...";
-//            } else {
-//                LOG(ERROR) << "Incorrect subfile with id " << file->file_id()
-//                           << " (headers do not match). Cannot patch it";
-//                return FAILED;
-//            }
-//        }
-
-        // If file has inactive category, then we should set it to patched state in order to commit patch and
-        // then in ApplyFilePatch(), if new category is still inactive, return dictionary to its original state;
-
-        if (inactive_categories.count(file->category) != 0 && patch_dict_.count(file_id) != 0 && file_id != 2013266257) {
-            *dictionary_[file_id] = *patch_dict_[file_id];
-        }
-
-        if (data.options["cat"].IsDefined()) {
-            file->category = data.options["cat"].as<long long>();
-        } else {
-            file->category = 1;
-        }
-
-        BinaryData old_data = GetFileData(orig_dict_.count(file->file_id()) == 0 ? file : orig_dict_[file->file_id_]);
-        if (old_data.Empty()) {
-            LOG(ERROR) << "GetFileData returned empty data. Aborting.";
-            return DAT_PATCH_FILE_ERROR;
-        }
-
-        BinaryData patch_data = file->MakeForImport(old_data, data);
-        DAT_RESULT result = ApplyFilePatch(file, patch_data);
-        if (result != SUCCESS)
-            return result;
-
-        LOG(DEBUG) << "Patched successfully file " << data.options["fid"].as<long long>() << ".";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::PatchAllDatabase(Database *db) {
-        LOG(INFO) << "Patching all database";
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        SubfileData data;
-        data = db->GetNextFile();
-
-        while (!data.Empty()) {
-            DAT_RESULT result = PatchFile(data);
-            if (result != SUCCESS)
-                LOG(ERROR) << "Cannot patch file " << data.options["fid"].as<long long>() << " continuing";
-            data = db->GetNextFile();
-        }
-        LOG(INFO) << "Successfully patched whole database";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::WriteUnorderedDictionary(std::string path) const {
-        LOG(INFO) << "Writing unordered dictionary to " << path << "dict.txt";
-        FILE *f = nullptr;
-        fopen_s(&f, (path + "dict.txt").c_str(), "w");
-
-        if (f == nullptr) {
-            LOG(ERROR) << "Cannot open file " << path + "dict.txt";
-            return WRITE_TO_FILE_ERROR;
-        }
-
-        fprintf(f, "unk1 file_id offset size1 timestamp version size2 unknown2 type\n");
-        for (auto i : dictionary_) {
-            fprintf(f, "%lld %lld %lld %lld %lld %lld %lld %lld %s\n", i.second->unknown1(), i.second->file_id(),
-                    i.second->file_offset(), i.second->file_size(), i.second->timestamp(), i.second->version(),
-                    i.second->block_size(), i.second->unknown2(), i.second->Extension().c_str());
-        }
-        fclose(f);
-        LOG(INFO) << "Unordered dictionary was written successfully to " << path << "dict.txt";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::ApplyFilePatch(Subfile *file, BinaryData &data) {
-        LOG(DEBUG) << "Applying " << file->file_id() << " patch.";
-
-//        if (patch_dict_.size() == 0 && pending_dictionary_.size() == 0) {
-//            BinaryData nulls(50 * 1024 * 1024);
-//            WriteData(nulls, nulls.size(), file_size_);
-//            file_size_ += 50 * 1024 * 1024;
-//        }
-
-        if (data.Empty()) {
-            LOG(ERROR) << "Error caused during making file for import. Cannot patch file " << file->file_id();
-            return FAILED;
-        }
-
-        auto file_id = file->file_id();
-
-        if (current_locale() != PATCHED && file_id != 2013266257) {
-            LOG(INFO) << "Changing locale to PATCHED(RU) in order to patch file";
-            SetLocale(PATCHED);
-        }
-
-        dat_state_ = UPDATED;
-
-        if (orig_dict_.count(file_id) == 0 && file_id != 2013266257) {
-            orig_dict_[file_id] = new Subfile(this, file->MakeHeaderData());
-        }
-
-
-        if ((patch_dict_.count(file_id) == 0 && file_id != 2013266257) || data.size() > file->block_size()
-            || file->file_size() + 8 > file->block_size()) {
-
-            file->file_offset_ = file_size_;
-            file->block_size_ = std::max((long long)data.size(), file->block_size_);
-
-            free_buffered_size_ = std::max(0ll, free_buffered_size_ - file->block_size_ - 8);
-            AddBufferedSize();
-
-            this->file_size_ += file->block_size_ + 8;
-        }
-
-        file->file_size_ = data.size() - 8;
-
-        data.Append(BinaryData::FromNumber<4>(0), 0); // set additional fragments count to zero
-
-        if (file_id != data.ToNumber<4>(8)) {
-            LOG(ERROR) << "Created data's file_id doesn't match to original! Patch wasn't written to .dat file";
-            return INCORRECT_PATCH_FILE;
-        }
-
-        //data.ProtectData();
-        //BinaryData data1(data.size());
-        WriteData(data, data.size(), file->file_offset());
-        //data.DeprotectData();
-
-        patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
-        if (file_id != 2013266257) {
-            patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
-        }
-
-        // If category is forbidden, then return file header data to original state
-        if (inactive_categories.count(file->category) != 0) {
-            file->file_offset_ = orig_dict_[file_id]->file_offset_;
-            file->file_size_ = orig_dict_[file_id]->file_size_;
-            file->block_size_ = orig_dict_[file_id]->block_size_;
-            file->timestamp_ = orig_dict_[file_id]->timestamp_;
-            file->version_ = orig_dict_[file_id]->version_;
-        }
-
-        if (orig_dict_.count(file_id) != 0 && file_id != 2013266257)
-            orig_dict_[file_id]->category = file->category;
-        if (patch_dict_.count(file_id) != 0 && file_id != 2013266257)
-            patch_dict_[file_id]->category = file->category;
-
-
-        // Applying file info in directory
-        pending_dictionary_.insert(file_id);
-
-        LOG(DEBUG) << "Successfully applied file " << file->file_id() << " patch.";
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // INPUT-OUTPUT SECTION
-    //------------------------------------------------//
-
-    BinaryData DatFile::GetFileData(const Subfile *file, long long int offset) {
-        LOG(DEBUG) << "Getting file " << file->file_id() << " data";
-
-        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);
-        }
-
-        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;
-        }
-
-        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;
-        }
-        LOG(DEBUG) << "Successfully got file " << file->file_id() << " data";
-        return data;
-    }
-
-    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.";
-            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.";
-            data = BinaryData(0);
-            return DAT_READ_ERROR;
-        }
-
-
-
-        if (offset + size > actual_dat_size_) {
-            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);
-        fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (dat_state_ < SUCCESS_DICTIONARY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot write data.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        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_);
-        actual_dat_size_ = std::max(file_size_, actual_dat_size_);
-        return SUCCESS;
-    }
-
-    //------------------------------------------------//
-    // LOCALE SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::SetLocale(LOCALE locale) {
-        LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "Dat state isn't READY. Cannot set locale.";
-            return INCORRECT_STATE_ERROR;
-        }
-
-        if (current_locale_ == locale) {
-            return SUCCESS;
-        }
-
-        dat_state_ = UPDATED;
-        auto dict = GetLocaleDictReference(locale);
-        for (auto file : *dict) {
-            if (file.second == nullptr)
-                continue;
-
-            if (dictionary_.count(file.first) == 0) {
-                LOG(WARNING) << "In locale dictionary there is file with file_id = " << file.first
-                             << "which is not in .dat file! Passing it and removing from locale dictionary";
-                dict->erase(file.first);
-                continue;
-            }
-            if (dictionary_[file.first]->MakeHeaderData().CutData(8, 16) ==
-                file.second->MakeHeaderData().CutData(8, 16) ||
-                inactive_categories.count(orig_dict_[file.first]->category) != 0)
-                continue;
-
-            long long file_id = file.first;
-            Subfile *new_file = file.second;
-
-            *dictionary_[file_id] = *new_file;
-
-            pending_dictionary_.insert(file_id);
-            dat_state_ = UPDATED;
-        }
-
-        current_locale_ = locale;
-        LOG(INFO) << "Locale set successfull";
-        return SUCCESS;
-    }
-
-    LOCALE DatFile::current_locale() {
-        if (dat_state_ < READY) {
-            LOG(ERROR) << "dat_file is in incorrect state!";
-            return ORIGINAL;
-        }
-        if (current_locale_ != PATCHED && current_locale_ != ORIGINAL) {
-            LOG(ERROR) << "locale has incorrect value. Setting it to original";
-            current_locale_ = ORIGINAL;
-        }
-        return current_locale_;
-    }
-
-    std::map<long long, Subfile *> *DatFile::GetLocaleDictReference(LOCALE locale) {
-        switch (locale) {
-            case PATCHED:
-                return &patch_dict_;
-            case ORIGINAL:
-                return &orig_dict_;
-            default:
-                LOG(ERROR) << "Unknown locale! Returning original";
-                return &orig_dict_;
-        }
-    }
-
-    //------------------------------------------------//
-    // CHECKERS SECTION
-    //------------------------------------------------//
-
-    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)) && file->file_size() < 50ll * 1024ll * 1024ll;
-    }
-
-    bool DatFile::CheckIfUpdatedByGame() {
-        LOG(INFO) << "Checking if DatFile was updated by LotRO";
-        if (!pending_patch_.empty())
-            return true;
-
-        bool updated = false;
-
-        for (auto i : dictionary_) {
-            long long file_id = i.first;
-            Subfile *subfile = i.second;
-            if (patch_dict_.count(file_id) == 0)
-                continue;
-
-            if (*subfile != *patch_dict_[file_id] && *subfile != *orig_dict_[file_id]) {
-                orig_dict_.clear();
-                patch_dict_.clear();
-                LOG(INFO) << "DAT FILE WAS UPDATED!!!! CLEARING PATCH DATA";
-                pending_patch_.insert(file_id);
-                WriteData(BinaryData::FromNumber<4>(0), 4, 300);
-                return true;
-            }
-        }
-        return updated;
-    }
-
-    bool DatFile::CheckIfNotPatched() {
-        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!";
-        return dictionary_.count(620750000) > 0;
-    }
-
-    //------------------------------------------------//
-    // CATEGORY SECTION
-    //------------------------------------------------//
-
-    DAT_RESULT DatFile::EnableCategory(int category) {
-        LOG(INFO) << "Enabling category " << category;
-        if (inactive_categories.count(category) == 0)
-            return SUCCESS;
-
-        inactive_categories.erase(category);
-        dat_state_ = UPDATED;
-
-        for (auto file : dictionary_) {
-            auto file_id = file.first;
-            if (patch_dict_.count(file_id) > 0 && patch_dict_[file_id]->category == category) {
-                *file.second = *patch_dict_[file_id];
-                pending_dictionary_.insert(file_id);
-            }
-        }
-        LOG(INFO) << "Category " << category << " enabled successfully";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::DisableCategory(int category) {
-        LOG(INFO) << "Disabling category " << category;
-        if (inactive_categories.count(category) != 0)
-            return SUCCESS;
-        inactive_categories.insert(category);
-        dat_state_ = UPDATED;
-
-        for (auto file : dictionary_) {
-            auto file_id = file.first;
-            if (orig_dict_.count(file_id) && orig_dict_[file_id]->category == category) {
-                *file.second = *orig_dict_[file_id];
-                pending_dictionary_.insert(file_id);
-            }
-        }
-        LOG(INFO) << "Category " << category << " disabled successfully";
-        return SUCCESS;
-    }
-
-    const std::set<long long> &DatFile::GetInactiveCategoriesList() {
-        return inactive_categories;
-    }
-
-    const std::string &DatFile::filename() const {
-        return filename_;
-    }
-
-    void DatFile::AddBufferedSize() {
-        if (free_buffered_size_ >= MIN_BUFFERED_SIZE)
-            return;
-        BinaryData nulls(MAX_BUFFERED_SIZE);
-        WriteData(nulls, MAX_BUFFERED_SIZE, file_size_);
-        free_buffered_size_ = MAX_BUFFERED_SIZE;
-    }
-
-    //------------------------------------------------//
-    // BACKUP SECTION
-    //------------------------------------------------//
-
-    bool DatFile::CheckIfBackupExists(const std::string &backup_datname) {
-        std::ifstream dst("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-        return !dst.fail();
-    }
-
-    DAT_RESULT DatFile::RemoveBackup(const std::string &backup_datname) {
-        if (!CheckIfBackupExists(backup_datname))
-            return SUCCESS;
-        if (remove(("DAT_LIBRARY_BACKUP/" + backup_datname).c_str()) == 0)
-            return SUCCESS;
-        return REMOVE_FILE_ERROR;
-    }
-
-    DAT_RESULT DatFile::CreateBackup(const std::string &backup_datname) {
-        auto filename = filename_;
-        auto dat_id = dat_id_;
-        LOG(INFO) << "Restoring .dat file " << filename << " from backup " << backup_datname;
-        LOG(INFO) << "    Closing DatFile...";
-        CloseDatFile();
-        LOG(INFO) << "    Copying " << filename << " to " << backup_datname;
-        mkdir("DAT_LIBRARY_BACKUP");
-        std::ifstream  src(filename, std::ios::binary);
-        std::ofstream  dst("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-
-        std::istreambuf_iterator<char> begin_source(src);
-        std::istreambuf_iterator<char> end_source;
-        std::ostreambuf_iterator<char> begin_dest(dst);
-        std::copy(begin_source, end_source, begin_dest);
-
-        src.close();
-        dst.close();
-
-        LOG(INFO) << "    Done copying. Initializing restored" << filename << " DatFile...";
-        InitDatFile(filename, dat_id);
-        LOG(INFO) << "Restoring .dat file success!";
-        return SUCCESS;
-    }
-
-    DAT_RESULT DatFile::RestoreFromBackup(const std::string &backup_datname) {
-        auto filename = filename_;
-        auto dat_id = dat_id_;
-        LOG(INFO) << "Restoring .dat file " << filename << " from backup " << backup_datname;
-        LOG(INFO) << "    Closing DatFile...";
-        CloseDatFile();
-        LOG(INFO) << "    Copying " << filename << " to " << backup_datname;
-        mkdir("DAT_LIBRARY_BACKUP");
-        std::ifstream  src("DAT_LIBRARY_BACKUP/" + backup_datname, std::ios::binary);
-        std::ofstream  dst(filename, std::ios::binary);
-        if (src.fail()) {
-            LOG(ERROR) << "CANNOT RESTORE FILE FROM BACKUP - no backup specified with name " << backup_datname;
-            return NO_BACKUP_ERROR;
-        }
-
-        std::istreambuf_iterator<char> begin_source(src);
-        std::istreambuf_iterator<char> end_source;
-        std::ostreambuf_iterator<char> begin_dest(dst);
-        std::copy(begin_source, end_source, begin_dest);
-
-        src.close();
-        dst.close();
-
-        LOG(INFO) << "    Done copying. Initializing restored" << filename << " DatFile...";
-        InitDatFile(filename, dat_id);
-        LOG(INFO) << "Restoring .dat file success!";
-        return SUCCESS;
-    }
-}
-}

+ 0 - 158
lib/src/Database.cpp

@@ -1,158 +0,0 @@
-//
-// Created by Иван_Архипов on 17.11.2017.
-//
-
-#include "Database.h"
-#include "BinaryData.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-
-namespace LOTRO_DAT {
-    Database::Database() {
-        LOG(DEBUG) << "Initialising new Database instance.";
-        db_ = nullptr;
-    }
-
-    bool Database::CloseDatabase() {
-        LOG(DEBUG) << "Closing database.";
-
-        if (db_ != nullptr) {
-            ExecSql("COMMIT TRANSACTION");
-            sqlite3_finalize(insert_request_);
-            sqlite3_finalize(fetch_one_request_);
-            sqlite3_finalize(get_rows_number_request_);
-            if (sqlite3_close_v2(db_) != SQLITE_OK)
-                LOG(ERROR) << "Database error when closing: " << sqlite3_errmsg(db_);
-            db_ = nullptr;
-        }
-
-        LOG(DEBUG) << "Database successfully closed.";
-        return true;
-    }
-
-    Database::~Database() {
-        CloseDatabase();
-    }
-
-    bool Database::InitDatabase(const std::string &filename) {
-        LOG(DEBUG) << "Initializing database " << filename;
-
-        CloseDatabase();
-        if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
-            sqlite3_close(db_);
-            db_ = nullptr;
-            LOG(ERROR) << "sqlite3_open returned an error. Unable to open file " << filename;
-            return false;
-        }
-
-        ExecSql("PRAGMA synchronous = OFF");
-        ExecSql("PRAGMA count_changes = OFF");
-        ExecSql("PRAGMA journal_mode = MEMORY");
-        ExecSql("PRAGMA temp_store = MEMORY");
-        ExecSql("PRAGMA encoding = \"UTF-8\";");
-
-        ExecSql(CreateTableCommand_);
-
-        sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
-        sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr);
-        sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(),
-                           &get_rows_number_request_, nullptr);
-
-        ExecSql("BEGIN TRANSACTION");
-
-        LOG(DEBUG) << "Database " << filename << " successfully initialized";
-        return true;
-    }
-
-	void Database::ExecSql(const std::string &sql) {
-        LOG(DEBUG) << "Executing SQL request: " << sql;
-        if (db_ == nullptr) {
-            LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
-            return;
-        }
-		char *error;
-		if (sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &error) != SQLITE_OK) {
-			LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
-			return;
-		}
-        LOG(DEBUG) << "SQL request " << sql << " executed successfully";
-	}
-
-    bool Database::PushFile(const SubfileData &data) {
-        LOG(DEBUG) << "Pushing to database file with file_id " << data.options["fid"].as<long long>();
-
-        if (db_ == nullptr) {
-            LOG(WARNING) << "Trying to push file to db, which hasn't been opened yet.";
-            return false;
-        }
-
-        std::stringstream options_;
-        options_ << data.options;
-
-        sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
-        sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
-        sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT);
-
-        if (sqlite3_step(insert_request_) != SQLITE_DONE) {
-            LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
-            return false;
-        }
-
-        sqlite3_reset(insert_request_);
-
-        LOG(DEBUG) << "File with file_id " << data.options["fid"].as<long long>() << " pushed to database successfully.";
-        return true;
-    }
-
-    SubfileData Database::GetNextFile() {
-        LOG(DEBUG) << "Getting next file from database..";
-
-        if (db_ == nullptr) {
-            LOG(WARNING) << "Trying to get next file from db, which hasn't been opened yet.";
-            return SubfileData();
-        }
-
-        SubfileData data;
-        int result = sqlite3_step(fetch_one_request_);
-
-        if (result == SQLITE_ROW) {
-            data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
-                                          unsigned(sqlite3_column_bytes(fetch_one_request_, 0)));
-
-            data.text_data = std::u16string((char16_t *) sqlite3_column_text16(fetch_one_request_, 1));
-
-            std::string _options = std::string((char *) sqlite3_column_text(fetch_one_request_, 2),
-                                               unsigned(sqlite3_column_bytes(fetch_one_request_, 2)));
-            data.options = YAML::Load(_options);
-            return data;
-        }
-
-        if (result == SQLITE_DONE) {
-            LOG(DEBUG) << "Next file fetched successfully.";
-            return data;
-        }
-
-        LOG(ERROR) << "SQLite3 fetch_one request returned " << result << " code. SQLite message is: "<< sqlite3_errmsg(db_);
-        return data;
-    }
-
-    size_t Database::CountRows() {
-        LOG(INFO) << "Counting rows in database...";
-        if (db_ == nullptr) {
-            LOG(WARNING) << "Trying to execute sql query (Count rows) to db, which hasn't been opened yet.";
-            return 0;
-        }
-
-        int result = sqlite3_step(get_rows_number_request_);
-
-        if (result == SQLITE_ERROR) {
-            LOG(ERROR) << "Error when counting rows " << sqlite3_errmsg(db_);
-            return 0;
-        }
-        long long res = sqlite3_column_int64(get_rows_number_request_, 0);
-        sqlite3_reset(get_rows_number_request_);
-        LOG(INFO) << "Counted " << size_t(res) << " rows in database.";
-        return size_t(res);
-    }
-}

+ 0 - 282
lib/src/Examples/extractor_example.cpp

@@ -1,282 +0,0 @@
-//
-// Created by Иван_Архипов on 30.10.2017.
-//
-#include <iostream>
-#include <ctime>
-#include <algorithm>
-
-#ifdef WIN32
-#include <direct.h>
-#define mkdir(dir, mode) _mkdir(dir)
-#endif
-
-#include "LotroDat.h"
-using namespace LOTRO_DAT;
-using namespace std;
-
-// Change these variables to true if you want export category to files.
-bool exportImagesToFiles = false;
-bool exportFontsToFiles = false;
-bool exportSoundsToFiles = false;
-bool exportTexturesToFiles = false;
-bool exportUnknownToFiles = false;
-
-// Change these variables to true if you want export category to databases.
-bool exportTextsToDb = false;
-bool exportImagesToDb = false;
-bool exportFontsToDb = false;
-bool exportSoundsToDb = false;
-bool exportTexturesToDb = false;
-bool exportUnknownToDb = false;
-// There is no need to change anything else
-
-int main() {
-    std::cout << "Gi1dor's LotRO .dat extractor ver. 5.2.0" << std::endl;
-
-    std::cout << "Hello! I'm a basic shell version of .dat file extractor. I can open .dat file directly, "
-            "if you write path to it (with name of file) in file \"dat_file_path.txt\"\n";
-    DatFile file;
-
-    ifstream in("dat_file_path.txt");
-    if (!in.fail()) {
-        std::string filename;
-        getline(in, filename);
-
-        std::cout << "Using .dat file from dat_file_path.txt...\n";
-        std::cout << "Opening file " << filename << std::endl;
-
-        if (file.InitDatFile(filename, 0) == false) {
-            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();
-        }
-    }
-
-    while (file.DatFileState() == CLOSED) {
-        std::cout << "Please, tell, where the .dat file is\n";
-        std::cout << "Enter path to file (including filename): ";
-        std::string filename;
-        std::getline(std::cin, filename);
-
-        std::cout << "Opening file " << filename << std::endl;
-
-        if (file.InitDatFile(filename, 0) == false) {
-            std::cout << "Some error caused while opening the file... "
-                    "Could you enter .dat filename once more?" << std::endl;
-            file.CloseDatFile();
-        }
-    }
-
-    std::cout << "Great! File initialised successfully!\n";
-    if (file.CheckIfNotPatched())
-        std::cout << "MESSAGE: Dat file is new and haven't been patched yet\n";
-
-    if (file.CheckIfPatchedByOldLauncher())
-        std::cout << "MESSAGE: Dat file was patched by old launcher. Capability isn't guaranteed! Some functions may not work properly!!!\n";
-
-    if (file.CheckIfUpdatedByGame())
-        std::cout << "MESSAGE: .dat file was updated by game! Need to repair patches with functions RepairPatches() and FinishRepairingPatches()\n";
-
-    std::cout << "Files number: " << file.files_number() << std::endl;
-
-    int cmd = 0;
-    while (true) {
-        std::cout << "Please, choose, what should I do. I can extract .dat file to files (press 1), "
-                    "open another .dat file (press 2), or configure, what should I extract. Choose, what to do or exit (press -1)\n";
-
-        if (cmd != 3) {
-            std::cout << "Enter number of command (1-3): ";
-            std::cin >> cmd;
-
-            std::string tmp;
-            std::getline(std::cin, tmp);
-        }
-        if (cmd == -1) {
-            std::cout << "Exiting. Thanks for using me!\n";
-            break;
-        }
-
-        if (cmd == 1) {
-            const clock_t begin_time = clock();
-
-            mkdir("Extracted data", 744);
-
-            std::time_t result = std::time(nullptr);
-            char *ttime = std::asctime(std::localtime(&result));
-            auto *out_time = new char[25];
-            memcpy(out_time, ttime, 24);
-            out_time[24] = '\0';
-
-            std::string output_dir = std::string("Extracted data\\") + file.filename().substr(file.filename().length() - 16, 16) + " " + std::string(out_time) + "\\";
-            std::replace(output_dir.begin(), output_dir.end(), ':', '-');
-
-            mkdir(output_dir.c_str(), 744);
-            
-            std::cout << "Total files found: " << file.files_number() << std::endl << std::flush;
-            file.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" << std::flush;
-
-            Database output_db;
-
-            if (exportImagesToDb) {
-                output_db.InitDatabase(output_dir + std::string("Images.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(JPG, &output_db) << " .jpg files to Images.db" << std::endl << std::flush;
-                output_db.CloseDatabase();
-            }
-
-            if (exportSoundsToDb) {
-                output_db.InitDatabase(output_dir + std::string("Sounds.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(WAV, &output_db) << " .wav files to Sounds.db" << std::endl << std::flush;
-                std::cout << "Extracted " << file.ExtractAllFilesByType(OGG, &output_db) << " .ogg files to Sounds.db" << std::endl << std::flush;
-                output_db.CloseDatabase();
-            }
-
-            if (exportTextsToDb) {
-                output_db.InitDatabase(output_dir + std::string("Texts.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(TEXT, &output_db) << " text files to Texts.db" << std::endl << std::flush;
-                output_db.CloseDatabase();
-            }
-
-            if (exportFontsToDb) {
-                output_db.InitDatabase(output_dir + std::string("Fonts.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(FONT, &output_db) << " font files to Fonts.db" << std::endl << std::flush;
-                output_db.CloseDatabase();
-            }
-
-            if (exportTexturesToDb) {
-                output_db.InitDatabase(output_dir + std::string("Textures.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(DDS, &output_db) << " .dds files to Textures.db" << std::endl << std::flush;
-                output_db.CloseDatabase();
-            }
-
-            if (exportImagesToFiles) {
-                mkdir((output_dir + "jpg").c_str(), 744);
-                std::cout << "Extracted " << file.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 " << file.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 " << file.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
-                mkdir((output_dir + "ogg").c_str(), 744);
-                std::cout << "Extracted " << file.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 " << file.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 " << file.ExtractAllFilesByType(UNKNOWN, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
-            }
-
-            file.CloseDatFile();
-
-            fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
-                    float(clock() - begin_time) / CLOCKS_PER_SEC);
-        }
-
-        if (cmd == 2) {
-            std::cout << "Closing file...\n";
-            if (!file.CloseDatFile())
-                std::cout << "An error occured while closing the file!!!\n";
-
-            while (file.DatFileState() == CLOSED) {
-                std::cout << "Please, tell, where the .dat file is\n";
-                std::cout << "Enter path to file (including filename): ";
-                std::string filename;
-                std::getline(std::cin, filename);
-
-                std::cout << "Opening file " << filename << std::endl;
-
-                if (file.InitDatFile(filename, 0) == false) {
-                    std::cout << "Some error caused while opening the file... "
-                            "Could you enter .dat filename once more?" << std::endl;
-                    file.CloseDatFile();
-                }
-            }
-        }
-
-        if (cmd == 3) {
-            std::cout << "Current parameters:\n";
-            std::cout << "(01) Export texts to database - " << (exportTextsToDb ? "true\n" : "false\n");
-
-            std::cout << "(11) Export images to files - " << (exportImagesToFiles ? "true\n" : "false\n");
-            std::cout << "(12) Export images to database - " << (exportImagesToDb ? "true\n" : "false\n");
-
-            std::cout << "(21) Export fonts to files - " << (exportFontsToFiles ? "true\n" : "false\n");
-            std::cout << "(22) Export fonts to database - " << (exportFontsToDb ? "true\n" : "false\n");
-
-            std::cout << "(31) Export sounds to files - " << (exportSoundsToFiles ? "true\n" : "false\n");
-            std::cout << "(32) Export sounds to database - " << (exportSoundsToDb ? "true\n" : "false\n");
-
-            std::cout << "(41) Export textures to files - " << (exportTexturesToFiles ? "true\n" : "false\n");
-            std::cout << "(42) Export textures to database - " << (exportTexturesToDb ? "true\n" : "false\n");
-
-            std::cout << "(51) Export unknown files to files - " << (exportUnknownToFiles ? "true\n" : "false\n");
-            std::cout << "(52) Export unknown files to database - " << (exportUnknownToDb ? "true\n" : "false\n");
-
-            std::cout << "Enter number of parameter to change (or -1 to exit this menu): ";
-
-            int number = 0;
-
-            std::cin >> number;
-            std::string tmp;
-            std::getline(std::cin, tmp);
-
-            if (number == -1) {
-                std::cout << "Returning to main menu..\n";
-                cmd = 0;
-            } else {
-                switch (number) {
-                    case 01:
-                        exportTextsToDb = !exportTextsToDb;
-                        break;
-                    case 11:
-                        exportImagesToFiles = !exportImagesToFiles;
-                        break;
-                    case 12:
-                        exportImagesToDb = !exportImagesToDb;
-                        break;
-                    case 21:
-                        exportFontsToFiles = !exportFontsToFiles;
-                        break;
-                    case 22:
-                        exportFontsToDb = !exportFontsToDb;
-                        break;
-                    case 31:
-                        exportSoundsToFiles = !exportSoundsToFiles;
-                        break;
-                    case 32:
-                        exportSoundsToDb = !exportSoundsToDb;
-                        break;
-                    case 41:
-                        exportTexturesToFiles = !exportTexturesToFiles;
-                        break;
-                    case 42:
-                        exportTexturesToDb = !exportTexturesToDb;
-                        break;
-                    case 51:
-                        exportUnknownToFiles = !exportTexturesToFiles;
-                        break;
-                    case 52:
-                        exportUnknownToDb = !exportTexturesToDb;
-                        break;
-                    default:
-                        std::cout << "Incorrect number. Returning to main menu..\n";
-                }
-            }
-        }
-    }
-    file.CloseDatFile();
-    system("pause");
-    return 0;
-}
-

+ 0 - 210
lib/src/Examples/patcher_example.cpp

@@ -1,210 +0,0 @@
-//
-// Created by Иван_Архипов on 23.11.2017.
-//
-#include <iostream>
-#include <ctime>
-#include <algorithm>
-
-#ifdef WIN32
-#include <direct.h>
-#define mkdir(dir, mode) _mkdir(dir)
-#endif
-
-#include "LotroDat.h"
-using namespace LOTRO_DAT;
-using namespace std;
-
-int main() {
-    std::cout << "Gi1dor's LotRO .dat patcher ver. 5.2.0" << std::endl;
-    freopen("patcher_errors.log", "w", stderr);
-
-    setbuf(stdout, nullptr);
-    setbuf(stderr, nullptr);
-
-    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";
-    DatFile file;
-
-    ifstream in("dat_file_path.txt");
-    if (!in.fail()) {
-        std::string filename;
-        getline(in, filename);
-
-        std::cout << "Using .dat file from dat_file_path.txt...\n";
-        std::cout << "Opening file " << filename << std::endl;
-        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();
-        }
-    }
-
-    while (file.DatFileState() == CLOSED) {
-        std::cout << "Please, tell, where the .dat file is\n";
-        std::cout << "Enter path to file (including filename): ";
-        std::string filename;
-        std::getline(std::cin, filename);
-
-        std::cout << "Opening file " << filename << std::endl;
-
-        if (file.InitDatFile(filename, 0) == false) {
-                std::cout << "Some error caused while opening the file... "
-                        "Could you enter .dat filename once more?" << std::endl;
-            file.CloseDatFile();
-        }
-    }
-
-    std::cout << "Great! File initialised successfully!\n";
-    file.WriteUnorderedDictionary("");
-
-    if (file.CheckIfNotPatched())
-        std::cout << "MESSAGE: Dat file is new and haven't been patched yet\n";
-
-    if (file.CheckIfPatchedByOldLauncher())
-        std::cout << "MESSAGE: Dat file was patched by old launcher. Capability isn't guaranteed! Some functions may not work properly!!!\n";
-
-    if (file.CheckIfUpdatedByGame())
-        std::cout << "MESSAGE: .dat file was updated by game! Need to repair patches with functions RepairPatches() and FinishRepairingPatches()\n";
-
-    std::cout << "Files number: " << file.files_number() << std::endl;
-
-    while (true) {
-        std::cout << "Please, choose, what should I do. I can patch datfile from database to .dat file (enter 1), "
-                "change locale (enter 2), print current locale (enter 3), enable category (enter 4), disable category (enter 5), "
-                "print disabled categories (enter 6), create backup (enter 7), remove backup (enter 8), "
-                "restore .dat file from backup (enter 9), check if backup exists (enter 10) or exit (enter -1)\n";
-
-        int cmd = 0;
-        std::cout << "Enter number of command (1-10): ";
-        std::cin >> cmd;
-
-        std::string tmp;
-        std::getline(std::cin, tmp);
-
-        if (cmd == -1) {
-            std::cout << "Exiting. Thanks for using me!\n";
-            break;
-        }
-
-        if (cmd == 1) {
-            std::cout << "You've chosen to patch database! Write name of database file (it should be in the same "
-                    "directory), of enter 0 to return to main dialogue.\n";
-            while (true) {
-                std::cout << "Enter name of file or 0: ";
-                std::string dbname;
-                std::getline(std::cin, dbname);
-
-                if (dbname == std::to_string(0)) {
-                    std::cout << "Okay, returning back...\n\n";
-                    break;
-                }
-
-                Database db;
-
-                std::cout << "Opening database... " << dbname << std::endl;
-
-                if (!db.InitDatabase(dbname)) {
-                    std::cout << "Unfortunately, I cannot open this database. Could you try again please?\n";
-                    continue;
-                };
-
-                if (db.CountRows() == 0) {
-                    std::cout << "There are no files in database or database doesn't exist. "
-                            "Please, try again!\n";
-                    continue;
-                }
-
-                std::cout << "There are " << db.CountRows() << " files in database." << std::endl;
-
-                std::cout << "Successfully opened database! Beginning patching...\n";
-                const clock_t begin_time = clock();
-                size_t all = db.CountRows();
-                size_t now = 0;
-
-                SubfileData subfile = db.GetNextFile();
-                while (!subfile.Empty()) {
-                    if (!file.PatchFile(subfile)) {
-                        fprintf(stderr, "Error! Caught exception while patching file! Passing it\n");
-                    }
-
-                    subfile = db.GetNextFile();
-                    ++now;
-                    if (now * 100 / all > (now - 1) * 100 / all)
-                        std::cout << now * 100 / all << "%\n";
-                }
-
-                db.CloseDatabase();
-
-                fprintf(stdout, "Spent %f seconds on patching! Thank you for your patience!\n",
-                        float(clock() - begin_time) / CLOCKS_PER_SEC);
-
-                std::cout << "Great! File was patched successfully!\n\n";
-                break;
-            }
-        }
-        if (cmd == 2) {
-            std::cout << "Old locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl;
-            std::cout << "Changing locale..." << std::endl;
-            file.SetLocale(file.current_locale() == PATCHED ? ORIGINAL : PATCHED);
-            std::cout << "New locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
-        }
-
-        if (cmd == 3) {
-            std::cout << "Current locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
-        }
-
-        if (cmd == 4) {
-            int category_id = 0;
-            std::cout << "Enter category id: ";
-            std::cin >> category_id;
-            file.EnableCategory(category_id);
-            std::cout << "Category successfully enabled!" << std::endl;
-        }
-
-        if (cmd == 5) {
-            int category_id = 0;
-            std::cout << "Enter category id: ";
-            std::cin >> category_id;
-            file.DisableCategory(category_id);
-            std::cout << "Category successfully disabled!" << std::endl;
-        }
-
-        if (cmd == 6) {
-            std::cout << "Disabled categories: ";
-            for (auto i : file.GetInactiveCategoriesList())
-                std::cout << i << " ";
-            std::cout << endl;
-        }
-
-        if (cmd == 7) {
-            std::cout << "Creating backup..." << std::endl;
-            std::cout << "Create backup function returned " << file.CreateBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 8) {
-            std::cout << "Removing backup..." << std::endl;
-            std::cout << "Remove backup function returned " << file.RemoveBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 9) {
-            std::cout << "Restoring file from backup..." << std::endl;
-            std::cout << "Restore file function returned " << file.RestoreFromBackup("cli_local_En.backup") << std::endl;
-        }
-
-        if (cmd == 10) {
-            std::cout << "Backup file " << (file.CheckIfBackupExists("clie_local_En.backup") ? "exists!" : "doesn't exist.") << std::endl;
-        }
-    }
-    file.CloseDatFile();
-
-    system("pause");
-    return 0;
-}
-

+ 0 - 215
lib/src/SubDirectory.cpp

@@ -1,215 +0,0 @@
-//
-// Created by Иван_Архипов on 07.11.2017.
-//
-#include "SubDirectory.h"
-
-#include "DatFile.h"
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "EasyLogging++/easylogging++.h"
-
-#include "Subfiles/TextSubfile.h"
-#include "Subfiles/DdsSubfile.h"
-#include "Subfiles/FontSubfile.h"
-#include "Subfiles/JpgSubfile.h"
-#include "Subfiles/OggSubfile.h"
-#include "Subfiles/WavSubfile.h"
-#include "Subfiles/UnknownSubfile.h"
-
-namespace LOTRO_DAT {
-    std::set<long long> SubDirectory::visited_subdirectories_ = std::set<long long>();
-
-    SubDirectory::SubDirectory() {
-        offset_ = 0;
-    }
-
-    SubDirectory::~SubDirectory() {
-        subfiles_.clear();
-        subdirs_.clear();
-    }
-
-    SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
-            dat_(dat), offset_(offset), max_subdirs_(max_subdirs) {
-        LOG(DEBUG) << "Initialising " << offset_ << " SubDirectory";
-        LOG(DEBUG) << "Processing SubDirectories";
-
-        if (!MakeSubDirectories()) {
-            subfiles_.clear();
-            subdirs_.clear();
-            return;
-        }
-
-        LOG(DEBUG) << "Processing SubFiles";
-        if (!MakeSubFiles()) {
-            subfiles_.clear();
-            subdirs_.clear();
-            return;
-        }
-        LOG(DEBUG) << "SubDirectory " << offset_ << " initialized successfully";
-    }
-
-    bool SubDirectory::MakeSubDirectories() {
-        BinaryData data(1024);
-        dat_->ReadData(data, 63 * 8, offset_);
-
-        if (data.Empty()) {
-            LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
-            return false;
-        }
-
-        if (data.ToNumber<4>(0) != 0 || data.ToNumber<4>(4) != 0) {
-            LOG(DEBUG) << "first 8 bytes are not equal to 0 at offset " << offset_;
-            return false;
-        }
-
-        for (unsigned int i = 8; i < 63 * 8; i += 8) {
-            if (data.ToNumber<4>(i) == 0 || data.ToNumber<4>(i + 4) == 0)
-                break;
-
-            if (visited_subdirectories_.count(data.ToNumber<4>(i + 4)) > 0) {
-                LOG(DEBUG) << "Visiting subdirectory at offset " << data.ToNumber<4>(i + 4) << " more than one time. Passing.";
-                continue;
-            }
-            visited_subdirectories_.insert(data.ToNumber<4>(i + 4));
-
-            SubDirectory *subdir = new SubDirectory(data.ToNumber<4>(i + 4), dat_);
-
-            if (subdir->subfiles_.empty() && subdir->subdirs_.empty()) {
-                LOG(WARNING) << "Sub-subdirectory is empty or made empty... Dictionary offset = " << offset_ + i << "; Passing others";
-                break;
-            } else
-                subdirs_.push_back(subdir);
-        }
-        return true;
-    }
-
-    bool SubDirectory::MakeSubFiles() {
-        BinaryData data = BinaryData(4);
-        dat_->ReadData(data, 4, offset_ + 63 * 8);
-
-        if (data.Empty()) {
-            LOG(ERROR) << "(READ ERROR) Incorrect directory at offset " << offset_;
-            return false;
-        }
-
-        auto subfiles_number = data.ToNumber<4>(0);
-        if (subfiles_number >= 64) {
-            LOG(ERROR) << "Incorrect directory (subfiles_num >= 64) at offset " << offset_;
-            return false;
-        }
-
-        for (int i = 0; i < subfiles_number; i++) {
-            BinaryData header(32);
-            dat_->ReadData(header, 32, offset_ + 63 * 8 + 4 + 32 * i);
-
-            if (header.Empty()) {
-                LOG(ERROR) << "(READ ERROR) Incorrect directory (unable to read subfile data) at offset " << offset_;
-                return false;
-            }
-
-            if (header.ToNumber<4>(20) == 0 || header.ToNumber<4>(28) != 0)
-                continue;
-
-            Subfile *subfile = MakeSubfile(
-                    offset_ + 63 * 8 + 4 + 32 * i,
-                    header.ToNumber<4>(0), // unknown1
-                    header.ToNumber<4>(4), // file_id
-                    header.ToNumber<4>(8), // file_offset
-                    header.ToNumber<4>(12), // file_size
-                    header.ToNumber<4>(16), // timestamp
-                    header.ToNumber<4>(20), // version
-                    header.ToNumber<4>(24), // block_size
-                    header.ToNumber<4>(28) // unknown2 - must be zero??
-            );
-
-//            if (dat_->CorrectSubfile(subfile)) {
-                subfiles_.emplace_back(subfile);
-//            } else {
-//                LOG(WARNING) << "Incorrect Subfile in directory at offset " << offset_ + 63 * 8 + 4 + 32 * i << " (id = " << subfile->file_id() << ");";
-//                break;
-//            }
-        }
-        return true;
-    }
-
-    void SubDirectory::MakeDictionary(std::map<long long, Subfile *> &dict) {
-        for (Subfile *i : subfiles_) {
-            if (dict.count(i->file_id() != 0)) {
-                LOG(WARNING) << "Found multiple instances of file " << i->file_id() << " at dictionary offset "
-                             << i->dictionary_offset() << ". Base offset = " << dict[i->file_id()]->dictionary_offset();
-                if (!dat_->CorrectSubfile(i) || dat_->CorrectSubfile(dict[i->file_id_]))
-                    continue;
-            }
-            dict[i->file_id()] = i;
-        }
-
-        for (SubDirectory *i : subdirs_)
-            i->MakeDictionary(dict);
-    }
-
-    Subfile *SubDirectory::MakeSubfile(long long dictionary_offset, 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, long long unknown2) {
-
-        FILE_TYPE type = GetSubfileType(file_id, file_offset);
-
-        switch (type) {
-            case TEXT:
-                return dynamic_cast<Subfile *>(new TextSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case JPG:
-                return dynamic_cast<Subfile *>(new JpgSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case DDS:
-                return dynamic_cast<Subfile *>(new DdsSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case WAV:
-                return dynamic_cast<Subfile *>(new WavSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case OGG:
-                return dynamic_cast<Subfile *>(new OggSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case FONT:
-                return dynamic_cast<Subfile *>(new FontSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-            case UNKNOWN:
-                return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-        }
-        LOG(ERROR) << "Incorrect file type..";
-        return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, dictionary_offset, unknown1, file_id, file_offset, file_size, timestamp, version, block_size, unknown2));
-    }
-
-    FILE_TYPE SubDirectory::GetSubfileType(long long file_id, long long file_offset) const {
-        // Text check based on file_id
-        if ((file_id >> 24ll) == 0x25ll)
-            return TEXT;
-
-        // Font check based on file_id
-        if ((file_id >> 24ll) == 0x42ll)
-            return FONT;
-
-        BinaryData header(64);
-        dat_->ReadData(header, 64, (unsigned) file_offset + 8);
-
-        if (header.Empty()) {
-            LOG(ERROR) << "Unable to read file header. file_id = " << file_id << ", offset = " << offset_;
-            return UNKNOWN;
-        }
-
-
-        // jpeg / dds check
-        if ((file_id >> 24ll) == 0x41ll) {
-            long long soi = header.ToNumber<2>(24);
-            long long marker = header.ToNumber<2>(26);
-
-            //auto markerSize = header.ToNumber<short>(28);
-            //auto four = header.ToNumber<int>(30);
-
-            if ((soi == 0xD8FFll && marker == 0xE0FFll) || marker == 0xE1FFll)
-                return JPG;
-            return DDS;
-        }
-
-        // Ogg and Wav check
-        if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
-            return OGG;
-        if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
-            return WAV;
-
-        return UNKNOWN;
-    }
-};

+ 0 - 180
lib/src/Subfile.cpp

@@ -1,180 +0,0 @@
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-                                                  // will be recognized as incorrect and passed.
-                                                  // This should be done because of not completely correct implementation
-                                                  // of Subfiles and Subdirectories search in DatFile.
-namespace LOTRO_DAT {
-
-    Subfile::Subfile() = default;
-
-    Subfile::Subfile(DatFile *dat, const BinaryData &header) {
-        category = 0;
-
-        dat_ = dat;
-
-        unknown1_ = header.ToNumber<4>(0); // unknown1
-        file_id_ = header.ToNumber<4>(4); // file_id
-        file_offset_ = header.ToNumber<4>(8); // file_offset
-        file_size_ = header.ToNumber<4>(12); // block_size
-        timestamp_ = header.ToNumber<4>(16); // timestamp
-        version_ = header.ToNumber<4>(20); // version
-        block_size_ = header.ToNumber<4>(24); // block_size
-        unknown2_ = header.ToNumber<4>(28); // unknown2
-    }
-
-    Subfile::Subfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2) :
-            category(0), dat_(dat), dictionary_offset_(dictionary_offset), unknown1_(unknown1), file_id_(file_id),
-            file_offset_(file_offset),
-            file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size), unknown2_(unknown2) {
-
-        if (file_size_ > MAXSIZE) {
-            LOG(ERROR) << "Bad Subfile::Subfile() - File size of file " << file_id << " with offset " << file_offset
-                       <<" is too much... Maybe it's incorrect..?";
-            file_id_ = -1;
-            return;
-        }
-    }
-
-    /// Typical getters of private fields, if there's need for getting information about SubFile from outside class.
-
-
-    long long Subfile::dictionary_offset() const {
-        return dictionary_offset_;
-    }
-
-    long long Subfile::unknown1() const {
-        return unknown1_;
-    }
-
-    long long Subfile::file_id() const {
-        return file_id_;
-    }
-
-    long long Subfile::file_offset() const {
-        return file_offset_;
-    }
-
-    long long Subfile::file_size() const {
-        return file_size_;
-    }
-
-    long long Subfile::timestamp() const {
-        return timestamp_;
-    }
-
-    long long Subfile::version() const {
-        return version_;
-    }
-
-    long long Subfile::block_size() const {
-        return block_size_;
-    }
-
-    long long Subfile::unknown2() const {
-        return unknown2_;
-    }
-
-    /// bool Subfile::FileType(...);
-    /// Virtual function, can (and should) be redefined in child class, otherwise an exception will be thrown while exporting/importing file.
-    /// Returns enum FILE_TYPE value, which is declared in DatFile.h
-
-    FILE_TYPE Subfile::FileType() const {
-        LOG(ERROR) << "INCORRECT IMPLEMENTATION!";
-        return UNKNOWN;
-    }
-
-    /// std::string Subfile::Extension()
-    /// Virtual function, can (and should) be redefined in child class, otherwise an exception will be thrown while exporting/importing file.
-    /// Returns std::string with extension, beggined with '.', ex. ".jpg", ".txt" and so on;
-
-    std::string Subfile::Extension() const {
-        LOG(ERROR) << "INCORRECT IMPLEMENTATION!";
-        return ".subfile";
-    }
-
-    /// bool Subfile::PrepareForExport(...);
-    /// Virtual function, can be redefined in child class, otherwise an exception will be thrown while exporting file.
-    /// Takes constant BinaryData& file_data, which contains all file data in .dat file, except first 8 bytes before file_id.
-    /// Takes references to export_size - amount of exported files/strings, and content of exported data such as:
-    ///  1) field binary_data - exported as RAW data
-    ///  2) field text_data - UTF-16 text, exporting in UTF-8
-    ///  3) field options - YAML field, which consists of some parameters of file such as file_id, extension and so on.
-    /// Returns true if preparation was success. Otherwise returns false;
-
-    SubfileData Subfile::PrepareForExport(const BinaryData &) {
-        LOG(ERROR) << "INCORRECT IMPLEMENTATION!";
-        return SubfileData();
-    }
-
-
-    /// BinaryData Subfile::PrepareForImport(...);
-    /// Virtual function, can be redefined in child class, otherwise an exception will be thrown while importing file.
-    /// Takes constant BinaryData& file_data, which contains all file data in .dat file, including first 8 bytes befire file_id.
-    ///  1) const field binary_data - exported as RAW data
-    ///  2) const field text_data - UTF-16 text, exporting in UTF-8
-    ///  3) const field options - YAML field, which consists of some parameters of file such as file_id, extension and so on.
-    /// Returns BinaryData - bytes array, prepared for writing in .dat file
-
-    BinaryData Subfile::MakeForImport(const BinaryData &, const SubfileData &) {
-        LOG(ERROR) << "INCORRECT IMPLEMENTATION!";
-        return BinaryData(0);
-    }
-
-    BinaryData Subfile::MakeHeaderData() const {
-        BinaryData header = BinaryData::FromNumber<4>(unknown1_)
-                            + BinaryData::FromNumber<4>(file_id_)
-                            + BinaryData::FromNumber<4>(file_offset_)
-                            + BinaryData::FromNumber<4>(file_size_)
-                            + BinaryData::FromNumber<4>(timestamp_)
-                            + BinaryData::FromNumber<4>(version_)
-                            + BinaryData::FromNumber<4>(block_size_)
-                            + BinaryData::FromNumber<4>(unknown2_);
-        return header;
-    }
-
-
-    bool Subfile::operator==(const Subfile &b) const {
-        return unknown1_ == b.unknown1_
-               && file_id_ == b.file_id_
-               && file_offset_ == b.file_offset_
-               && file_size_ == b.file_size_
-               && timestamp_ == b.timestamp_
-               && version_ == b.version_
-               && block_size_ == b.block_size_
-               && unknown2_ == b.unknown2_;
-    }
-
-    bool Subfile::operator!=(const Subfile &b) const {
-        return !(*this == b);
-    }
-
-    Subfile &Subfile::operator=(const Subfile &b) {
-        if (*this == b)
-            return *this;
-
-        category = b.category;
-        dat_ = b.dat_;
-        unknown1_ = b.unknown1_; // unknown1
-        file_id_ = b.file_id_; // file_id
-        file_offset_ = b.file_offset_; // file_offset
-        file_size_ = b.file_size_; // block_size
-        timestamp_ = b.timestamp_; // timestamp
-        version_ = b.version_; // version
-        block_size_ = b.block_size_; // block_size
-        unknown2_ = b.unknown2_; // unknown2
-        return *this;
-    }
-};

+ 0 - 165
lib/src/Subfiles/DdsSubfile.cpp

@@ -1,165 +0,0 @@
-///
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/DdsSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-namespace LOTRO_DAT {
-    DdsSubfile::DdsSubfile() = default;
-
-    DdsSubfile::DdsSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE DdsSubfile::FileType() const {
-        return DDS;
-    }
-
-    std::string DdsSubfile::Extension() const {
-        return ".dds";
-    }
-
-    SubfileData DdsSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty() || file_data.size() < 256) {
-            return SubfileData();
-        }
-
-        BinaryData data = file_data;
-        if (data.CheckCompression())
-            data = data.DecompressData(4);
-
-        BinaryData ddsData(data.size() - 24 + 128);
-        for (int i = 0; i < 128; i++)
-            ddsData[i] = 0;
-
-        memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-        ddsData[0] = 0x44; // D
-        ddsData[1] = 0x44; // D
-        ddsData[2] = 0x53; // S
-        ddsData[3] = 0x20;
-        ddsData[4] = 0x7C;
-
-        ddsData[8] = 7;
-        ddsData[9] = 0x10;
-
-        // width, height
-        ddsData[12] = data[12];
-        ddsData[13] = data[13];
-        ddsData[14] = data[14];
-        ddsData[15] = data[15];
-
-        ddsData[16] = data[8];
-        ddsData[17] = data[9];
-        ddsData[18] = data[10];
-        ddsData[19] = data[11];
-
-        long long compression = data.ToNumber<4>(0x10);
-
-        switch (compression) {
-            case 20:        // 14 00 00 00 - 888 (R8G8B8)
-                ddsData[0x4C] = 0x20;  // ?
-                ddsData[0x50] = 0x40;  // compressed or not
-
-                ddsData[0x58] = 0x18;  // bytes per pixel
-                ddsData[0x5E] = 0xFF;
-                ddsData[0x61] = 0xFF;
-                ddsData[0x64] = 0xFF;
-                break;
-            case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-                ddsData[0x4C] = 0x20;  // ?
-                ddsData[0x50] = 0x40;  // compressed or not
-
-                ddsData[0x58] = 0x20;  // bytes per pixel
-                ddsData[0x5E] = 0xFF;
-                ddsData[0x61] = 0xFF;
-                ddsData[0x64] = 0xFF;
-                ddsData[0x6B] = 0xFF;
-                break;
-            case 28:        // 1C 00 00 00 - 332 (?)
-                ddsData[0x4C] = 0x20;  // ?
-                ddsData[0x50] = 0x40;  // compressed or not
-
-                ddsData[0x58] = 0x08;  // bytes per pixel
-                ddsData[0x5E] = 0xFF;
-                ddsData[0x61] = 0xFF;
-                ddsData[0x64] = 0xFF;
-                break;
-            case 827611204: // 44 58 54 31 - DXT1
-                ddsData[76] = 32;
-                ddsData[80] = 4;
-
-                ddsData[84] = 68;
-                ddsData[85] = 88;
-                ddsData[86] = 84;
-                ddsData[87] = 49;
-                break;
-            case 861165636: // 44 58 54 33 - DXT3
-                ddsData[22] = 1;
-                ddsData[76] = 32;
-                ddsData[80] = 4;
-
-                ddsData[84] = 68;
-                ddsData[85] = 88;
-                ddsData[86] = 84;
-                ddsData[87] = 51;
-
-                ddsData[108] = 8;
-                ddsData[109] = 16;
-                ddsData[110] = 64;
-                break;
-            case 894720068: // 44 58 54 35 - DXT5
-                ddsData[10] = 8;
-                ddsData[22] = 1;
-                ddsData[28] = 1;
-                ddsData[76] = 32;
-                ddsData[80] = 4;
-
-                ddsData[84] = 68;
-                ddsData[85] = 88;
-                ddsData[86] = 84;
-                ddsData[87] = 53;
-
-                ddsData[88] = 32;
-                ddsData[94] = 255;
-                ddsData[97] = 255;
-                ddsData[100] = 255;
-                ddsData[107] = 255;
-                ddsData[109] = 16;
-                break;
-            default:
-                LOG(ERROR) << "Unknown header format.";
-                return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = ddsData;
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData DdsSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "Invalid options data!";
-            return BinaryData(0);
-        }
-        // TODO: COMPRESSED TEXTURES
-        if (old_data.CheckCompression())
-            return old_data.CutData(0, 4) +
-                   (old_data.DecompressData(12).CutData(12, 16) + data.binary_data.CutData(128)).CompressData();
-        else {
-            BinaryData file_size = BinaryData::FromNumber<4>(data.binary_data.size() - 128);
-            return old_data.CutData(0, 28) + file_size + data.binary_data.CutData(128);
-        }
-    }
-};

+ 0 - 50
lib/src/Subfiles/FontSubfile.cpp

@@ -1,50 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/FontSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-namespace LOTRO_DAT {
-    FontSubfile::FontSubfile() = default;
-
-    FontSubfile::FontSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE FontSubfile::FileType() const {
-        return FONT;
-    }
-
-    std::string FontSubfile::Extension() const {
-        return ".fontbin";
-    }
-
-    SubfileData FontSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = file_data;
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData FontSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "invalid options data!";
-            return BinaryData(0);
-        }
-        return old_data.CutData(0, 16) + data.binary_data.CutData(8);
-    }
-};

+ 0 - 50
lib/src/Subfiles/JpgSubfile.cpp

@@ -1,50 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/JpgSubfile.h"
-#include "EasyLogging++/easylogging++.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-
-namespace LOTRO_DAT {
-    JpgSubfile::JpgSubfile() = default;
-
-    JpgSubfile::JpgSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE JpgSubfile::FileType() const {
-        return JPG;
-    }
-
-    std::string JpgSubfile::Extension() const {
-        return std::string(".jpg");
-    }
-
-    SubfileData JpgSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = file_data.CutData(24);
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData JpgSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "invalid options data!";
-            return BinaryData(0);
-        }
-        BinaryData file_size = BinaryData::FromNumber<4>(data.binary_data.size());
-        return old_data.CutData(0, 28) + file_size + data.binary_data;
-    }
-};

+ 0 - 53
lib/src/Subfiles/OggSubfile.cpp

@@ -1,53 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/OggSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-namespace LOTRO_DAT {
-    OggSubfile::OggSubfile() = default;
-
-    OggSubfile::OggSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE OggSubfile::FileType() const {
-        return OGG;
-    }
-
-    std::string OggSubfile::Extension() const {
-        return ".ogg";
-    }
-
-    SubfileData OggSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = file_data.CutData(8);
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData OggSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "invalid options data!";
-            return BinaryData(0);
-        }
-        BinaryData file_size = BinaryData::FromNumber<4>(data.binary_data.size() - 8);
-        BinaryData file_id = BinaryData::FromNumber<4>(this->file_id());
-
-        return old_data.CutData(0, 8) + file_id + file_size + data.binary_data;
-    }
-};

+ 0 - 426
lib/src/Subfiles/TextSubfile.cpp

@@ -1,426 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/TextSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-#include <codecvt>
-#include <locale>
-
-std::u16string to_utf16(long long x) {
-    std::u16string res;
-    while (x > 0) {
-        res += char16_t(u'0' + x % 10);
-        x /= 10ll;
-    }
-    std::reverse(res.begin(), res.end());
-    return res;
-}
-
-long long from_utf16(const std::u16string &num) {
-    long long res = 0;
-    for (auto c : num) {
-        res = res * 10ll + (c - u'0');
-    }
-    return res;
-}
-
-std::string argumentsFromUtf16(const std::u16string &args) {
-    std::string res;
-
-    size_t pointer = 0;
-    while (pointer < args.length()) {
-        size_t pointer1 = args.find(u'-', pointer);
-        if (pointer1 == std::u16string::npos)
-            pointer1 = args.length();
-        if (!res.empty())
-            res += "-";
-        res += std::to_string(from_utf16(args.substr(pointer, pointer1 - pointer)));
-        pointer = pointer1 + 1;
-    }
-
-    return res;
-}
-
-namespace LOTRO_DAT {
-    TextSubfile::TextSubfile() = default;
-
-    TextSubfile::TextSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE TextSubfile::FileType() const {
-        return TEXT;
-    }
-
-    std::string TextSubfile::Extension() const {
-        return std::string(".txt");
-    }
-
-    SubfileData TextSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-        long long text_fragment_num = file_data.ToNumber<1>(offset);
-        if ((text_fragment_num & 0x80) != 0) {
-            text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | file_data.ToNumber<1>(offset + 1));
-            offset += 1;
-        }
-        offset += 1;
-
-        for (long long i = 0; i < text_fragment_num; i++) {
-            long long fragment_id = file_data.ToNumber<8>(offset);
-            offset += 8;
-
-            std::vector<std::u16string> text_pieces = MakePieces(file_data, offset);
-            std::vector<long long> arg_references = MakeArgumentReferences(file_data, offset);
-            std::vector<std::vector<BinaryData>> arg_strings = MakeArgumentStrings(file_data, offset);
-
-            std::u16string text = u"[";
-            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::u16string arguments;
-            for (size_t j = 0; j + 1 < arg_references.size(); j++)
-                arguments += to_utf16(arg_references[j]) + u"-";
-            if (!arg_references.empty())
-                arguments += to_utf16(arg_references[arg_references.size() - 1]);
-
-            if (result.text_data.length() > 0)
-                result.text_data += u"|||";
-
-            result.text_data += to_utf16(fragment_id) + u":::";
-            result.text_data += arguments + u":::";
-            result.text_data += text;
-        }
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        LOG(DEBUG) << "Preparing text file " << file_id() << " for import.";
-        std::unordered_map<long long, SubfileData> patch_fragments = ParsePatchFragments(data);
-
-        BinaryData new_data;
-
-        if (file_size() <= 10 + 8) // File is empty, nothing to do;
-            return old_data;
-
-        long long offset = 9 + 8; // first 8 bytes - file_info. After them:
-        // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-        long long text_fragment_num = old_data.ToNumber<1>(offset);
-        if ((text_fragment_num & 0x80) != 0) {
-            text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | old_data.ToNumber<1>(offset + 1));
-            offset += 1;
-        }
-        offset += 1;
-
-        new_data = new_data + old_data.CutData(0, offset); // Adding file info
-
-        for (long long i = 0; i < text_fragment_num; i++) {
-            long long fragment_id = old_data.ToNumber<8>(offset);
-            offset += 8;
-
-            new_data = new_data + old_data.CutData(offset - 8, offset);
-
-            if (patch_fragments.count(fragment_id) == 0) {
-                // Retrieving old pieces
-                new_data = new_data + GetPieceData(old_data, offset);
-                // Retrieving old references
-                new_data = new_data + GetArgumentReferenceData(old_data, offset);
-                // Retrieving old ref_strings
-                new_data = new_data + GetArgumentStringsData(old_data, offset);
-            } else {
-                // Making and adding new pieces
-                new_data = new_data + BuildPieces(old_data, patch_fragments[fragment_id], offset);
-                // Making and adding new references
-                new_data = new_data + BuildArgumentReferences(old_data, patch_fragments[fragment_id], offset);
-                // Making and adding new strings
-                new_data = new_data + BuildArgumentStrings(old_data, patch_fragments[fragment_id], offset);
-            }
-        }
-        new_data = new_data + old_data.CutData(offset); // Adding elapsed file data
-        return new_data;
-    }
-
-    std::unordered_map<long long, SubfileData> TextSubfile::ParsePatchFragments(const SubfileData &data) {
-        LOG(DEBUG) << "Started parsing patch fragments";
-        std::unordered_map<long long, SubfileData> res;
-        std::u16string text = data.text_data;
-
-        size_t pointer = 0;
-        while (pointer < text.length()) {
-            // Parsing fragment_id
-            size_t pointer1 = text.find(u":::", pointer);
-            if (pointer1 == std::u16string::npos) {
-                LOG(ERROR) << "Unable to parse fragment id! Cannot find '...' divider. File_id = " << file_id_;
-                return res;
-            }
-            long long fragment_id = from_utf16(text.substr(pointer, pointer1 - pointer));
-            pointer = pointer1 + 3;
-            res[fragment_id] = SubfileData();
-            res[fragment_id].options["gid"] = fragment_id;
-
-            // Parsing arguments
-            pointer1 = text.find(u":::", pointer);
-            if (pointer1 == std::u16string::npos) {
-                LOG(ERROR) << "Unable to parse arguments! Cannot find '...' divider. File_id = " << file_id_;
-                return res;
-            }
-            std::u16string arguments = text.substr(pointer, pointer1 - pointer);
-            pointer = pointer1 + 3;
-            if (arguments.length() > 0) {
-                res[fragment_id].options["args"] = argumentsFromUtf16(arguments);
-            }
-
-            // Parsing text
-            pointer1 = text.find(u"|||", pointer);
-            if (pointer1 == std::u16string::npos)
-                pointer1 = text.length();
-            std::u16string text_data = text.substr(pointer, pointer1 - pointer);
-            pointer = pointer1  + 3;
-            res[fragment_id].text_data = text_data;
-        }
-        LOG(DEBUG) << "Finished parsing text patch fragments";
-        return res;
-    }
-
-    // Make pieces/arguments/argument strings functions
-
-    std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
-        LOG(DEBUG) << "Started making pieces";
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-
-            BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
-            std::u16string piece;
-
-            for (long long k = 0; k < piece_size; k++) {
-                char16_t c = char16_t(
-                        ((short(piece_data[2 * unsigned(k) + 1])) << 8) | (short(piece_data[2 * unsigned(k)])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-        LOG(DEBUG) << "Finished making pieces";
-        return text_pieces;
-    }
-
-    std::vector<long long> TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) {
-        LOG(DEBUG) << "Started making argument references";
-        std::vector<long long> arg_references;
-
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_references; j++) {
-            arg_references.emplace_back(data.ToNumber<4>(offset));
-            offset += 4;
-        }
-        LOG(DEBUG) << "Finished making argument references";
-        return arg_references;
-    }
-
-    std::vector<std::vector<BinaryData>> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) {
-        LOG(DEBUG) << "Started making argument strings";
-        std::vector<std::vector<BinaryData> > arg_strings;
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            arg_strings.emplace_back();
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
-
-                arg_strings[unsigned(j)].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
-        }
-        LOG(DEBUG) << "Finished making argument strings";
-        return arg_strings;
-    }
-
-    // Build pieces/arguments/argument strings functions from fragment SubfileData
-
-    BinaryData TextSubfile::BuildPieces(const BinaryData &data, const SubfileData &new_data, long long &offset) {
-        LOG(DEBUG) << "Started building pieces";
-        // Moving &offset pointer in &data
-        GetPieceData(data, offset);
-
-        // Deleting '[' and ']' brackets
-        std::u16string text_data = new_data.text_data.substr(1, new_data.text_data.size() - 2);
-        std::vector<std::u16string> pieces;
-
-        const std::u16string DNT = u"<--DO_NOT_TOUCH!-->";
-        size_t prev = 0;
-        size_t next = text_data.find(DNT, prev);
-
-        while (next != std::string::npos) {
-            std::u16string piece = text_data.substr(prev, next - prev);
-            pieces.emplace_back(piece);
-            prev = next + DNT.length();
-            next = text_data.find(DNT, prev);
-        }
-
-        pieces.emplace_back(text_data.substr(prev));
-
-        // Building BinaryData from pieces
-        BinaryData result;
-        BinaryData temp_data = BinaryData::FromNumber<4>(pieces.size());
-        result = result + temp_data;
-
-        for (auto piece : pieces) {
-            long long piece_size = piece.length();
-            if (piece_size < 128) {
-                temp_data = BinaryData::FromNumber<1>(piece_size);
-            } else {
-                temp_data = BinaryData::FromNumberRAW<2>((piece_size | 32768));
-            }
-            result = result + temp_data;
-
-            for (long long j = 0; j < piece_size; j++) {
-                temp_data = BinaryData::FromNumber<2>(short(piece[j]));
-                result = result + temp_data;
-            }
-        }
-        LOG(DEBUG) << "Pieces built successfully";
-        return result;
-    }
-
-    BinaryData TextSubfile::BuildArgumentReferences(const BinaryData &data, const SubfileData &new_data,
-                                                    long long &offset) {
-        LOG(DEBUG) << "Started building argument refs";
-        // Moving &offset pointer in &data
-        GetArgumentReferenceData(data, offset);
-
-        // If there are no args - making 4 null-bytes and return;
-        if (!new_data.options["args"]) {
-            BinaryData result = BinaryData::FromNumber<4>(0);
-            return result;
-        }
-
-        // Parsing arguments from list in options["args"]
-        std::string args_list = new_data.options["args"].as<std::string>();
-        std::vector<long long> arguments;
-
-        size_t prev = 0;
-        size_t next = args_list.find('-', prev);
-        while (next != std::string::npos) {
-            std::string argument = args_list.substr(prev, next - prev);
-            arguments.push_back(std::stoll(argument));
-            prev = next + 1;
-            next = args_list.find('-', prev);
-        }
-        std::string argument = args_list.substr(prev);
-        arguments.push_back(std::stoll(argument));
-
-        BinaryData result;
-        BinaryData temp_data = BinaryData::FromNumber<4>(arguments.size());
-        result = result + temp_data;
-        for (auto arg_reference : arguments) {
-            temp_data = BinaryData::FromNumber<4>(arg_reference);
-            result = result + temp_data;
-        }
-        LOG(DEBUG) << "Argument refs built successfully";
-        return result;
-    }
-
-    BinaryData TextSubfile::BuildArgumentStrings(const BinaryData &data, const SubfileData &, long long &offset) {
-        LOG(DEBUG) << "Started building argument strings";
-        LOG(DEBUG) << "Built arg strings successfully";
-        return GetArgumentStringsData(data, offset);
-    }
-
-    // Get BinaryData contents of pieces/arguments/argument strings
-
-    BinaryData TextSubfile::GetPieceData(const BinaryData &data, long long &offset) const {
-        LOG(DEBUG) << "Started getting piece data";
-        long long old_offset = offset;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-            offset += piece_size * 2;
-        }
-        LOG(DEBUG) << "Got piece data";
-        return data.CutData(old_offset, offset);
-    }
-
-    BinaryData TextSubfile::GetArgumentReferenceData(const BinaryData &data, long long &offset) const {
-        LOG(DEBUG) << "Started getting arg refs data";
-        long long old_offset = offset;
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-        offset += 4 * num_references;
-        LOG(DEBUG) << "Finished getting arg refs data";
-        return data.CutData(old_offset, offset);
-    }
-
-    BinaryData TextSubfile::GetArgumentStringsData(const BinaryData &data, long long &offset) const {
-        LOG(DEBUG) << "Started getting arg strings data";
-        long long old_offset = offset;
-
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
-                offset += string_size * 2;
-            }
-        }
-        LOG(DEBUG) << "Finished getting arg strings data";
-        return data.CutData(old_offset, offset);
-    }
-
-};

+ 0 - 50
lib/src/Subfiles/UnknownSubfile.cpp

@@ -1,50 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/UnknownSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-namespace LOTRO_DAT {
-    UnknownSubfile::UnknownSubfile() = default;
-
-    UnknownSubfile::UnknownSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE UnknownSubfile::FileType() const {
-        return UNKNOWN;
-    }
-
-    std::string UnknownSubfile::Extension() const {
-        return std::string(".unknown");
-    }
-
-    SubfileData UnknownSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = file_data;
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData UnknownSubfile::MakeForImport(const BinaryData &, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "invalid options data!";
-            return BinaryData(0);
-        }
-        return data.binary_data;
-    }
-};

+ 0 - 50
lib/src/Subfiles/WavSubfile.cpp

@@ -1,50 +0,0 @@
-//
-// Created by Иван_Архипов on 24.11.2017.
-//
-
-#include "Subfiles/WavSubfile.h"
-
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "SubfileData.h"
-#include "EasyLogging++/easylogging++.h"
-
-namespace LOTRO_DAT {
-    WavSubfile::WavSubfile() = default;
-
-    WavSubfile::WavSubfile(DatFile *dat, long long dictionary_offset, 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, long long unknown2)
-            : Subfile(dat, dictionary_offset, unknown1, file_id, file_offset, file_size,
-                      timestamp, version, block_size, unknown2) {
-    }
-
-    FILE_TYPE WavSubfile::FileType() const {
-        return WAV;
-    }
-
-    std::string WavSubfile::Extension() const {
-        return ".wav";
-    }
-
-    SubfileData WavSubfile::PrepareForExport(const BinaryData &file_data) {
-        if (file_data.Empty()) {
-            return SubfileData();
-        }
-
-        SubfileData result;
-        result.binary_data = file_data.CutData(8);
-        result.options["fid"] = file_id();
-        result.options["ext"] = Extension();
-        return result;
-    }
-
-    BinaryData WavSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
-        if (!data.options["ext"] || data.options["ext"].as<std::string>() != Extension() ||
-            !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
-            LOG(ERROR) << "invalid options data!";
-            return BinaryData(0);
-        }
-        return old_data.CutData(0, 24) + data.binary_data;
-    }
-};

+ 2 - 2
mainwindow.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>900</width>
-    <height>782</height>
+    <width>448</width>
+    <height>303</height>
    </rect>
   </property>
   <property name="windowTitle">

+ 8 - 3
network.cpp

@@ -211,6 +211,11 @@ void ANetwork::getPaths(){
             } else {
                 qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Патч отсутствует: ", app->helper->stringToChar(s));
                 version = "100";
+                QLabel* obj = app->window->ui->mainbox->findChild<QLabel*>(s + "sStatus");
+                if (obj != nullptr) {
+                    obj->setText("Оригинал");
+                }
+
             }
             query.addQueryItem(s, version);
         }
@@ -273,15 +278,15 @@ QString ANetwork::getMicroPath(int timestamp){
     if(!dir.exists()) QDir().mkdir(microfolder);
     QString baseurl = app->config->getValue("Network", "update");
     QString url = baseurl + "/" + QString::number(timestamp);
-    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Стартуем загрузку ", app->helper->stringToChar(url));
+    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Стартуем загрузку ", app->helper->stringToChar(url + "/1"));
     QNetworkAccessManager m_NetworkMngr;
-    QNetworkReply *reply= m_NetworkMngr.get(QNetworkRequest(url));
+    QNetworkReply *reply= m_NetworkMngr.get(QNetworkRequest(url + "/1"));
     QEventLoop loop;
     QObject::connect(reply, SIGNAL(finished()),&loop, SLOT(quit()));
     loop.exec();
     QUrl aUrl(url);
     QFileInfo fileInfo=aUrl.path();
-    QString filename = microfolder + fileInfo.fileName() + ".db";
+    QString filename = micropatch;
     QFile file(filename);
     file.open(QIODevice::WriteOnly);
     file.write(reply->readAll());

+ 3 - 3
ui_mainwindow.h

@@ -151,7 +151,7 @@ public:
     {
         if (MainWindow->objectName().isEmpty())
             MainWindow->setObjectName(QStringLiteral("MainWindow"));
-        MainWindow->resize(900, 782);
+        MainWindow->resize(508, 307);
         MainWindow->setStyleSheet(QStringLiteral(""));
         centralWidget = new QWidget(MainWindow);
         centralWidget->setObjectName(QStringLiteral("centralWidget"));
@@ -645,7 +645,7 @@ public:
         fontsStatus->setText(QApplication::translate("MainWindow", "\320\236\321\200\320\270\320\263\320\270\320\275\320\260\320\273", Q_NULLPTR));
         videosStatus->setText(QApplication::translate("MainWindow", "\320\241\320\272\320\276\321\200\320\276 \320\277\320\276\321\217\320\262\320\270\321\202\321\201\321\217", Q_NULLPTR));
         label_3->setText(QApplication::translate("MainWindow", "\320\237\320\265\321\200\320\265\320\262\320\276\320\264 \321\202\320\265\320\272\321\201\321\202\320\276\320\262 \320\276\321\202 \320\272\320\276\320\274\320\260\320\275\320\264\321\213 \320\235\320\260\321\201\320\273\320\265\320\264\320\270\321\217", Q_NULLPTR));
-        label->setText(QApplication::translate("MainWindow", "\320\240\321\203\321\201\321\201\320\272\320\270\320\265 \320\267\320\262\321\203\320\272\320\276\320\262\321\213\320\265 \321\204\320\260\320\271\320\273\321\213 \320\276\321\202 Mail.ru", Q_NULLPTR));
+        label->setText(QApplication::translate("MainWindow", "\320\240\321\203\321\201\320\270\321\204\320\270\321\206\320\270\321\200\320\276\320\262\320\260\320\275\320\275\321\213\320\265 \320\267\320\262\321\203\320\272\320\276\320\262\321\213\320\265 \321\204\320\260\320\271\320\273\321\213", Q_NULLPTR));
         label_4->setText(QApplication::translate("MainWindow", "\320\240\321\203\321\201\321\201\320\272\320\270\320\265 \320\272\320\260\321\200\321\202\321\213 \320\276\321\202 \320\275\320\260\321\210\320\265\320\271 \320\272\320\276\320\274\320\260\320\275\320\264\321\213", Q_NULLPTR));
         label_8->setText(QApplication::translate("MainWindow", "\320\235\320\260\321\210\320\260 \320\262\320\265\321\200\321\201\320\270\321\217 \320\267\320\260\321\201\321\202\320\260\320\262\320\276\321\207\320\275\321\213\321\205 \321\215\320\272\321\200\320\260\320\275\320\276\320\262", Q_NULLPTR));
         label_6->setText(QApplication::translate("MainWindow", "\320\222\321\200\320\265\320\274\320\265\320\275\320\275\320\260\321\217 \320\262\320\265\321\200\321\201\320\270\321\217 \321\210\321\200\320\270\321\204\321\202\320\276\320\262 \320\264\320\273\321\217 U22", Q_NULLPTR));
@@ -730,7 +730,7 @@ public:
         goTitle->setText(QApplication::translate("MainWindow", "\320\222\320\276 \321\207\321\202\320\276 \320\261\321\203\320\264\320\265\320\274 \320\270\320\263\321\200\320\260\321\202\321\214 \321\201\320\265\320\263\320\276\320\264\320\275\321\217?", Q_NULLPTR));
         goHeader->setText(QApplication::translate("MainWindow", "\320\227\320\260\320\277\321\203\321\201\320\272 \320\270\320\263\321\200\321\213", Q_NULLPTR));
         goHint->setText(QApplication::translate("MainWindow", "\320\237\320\276\320\264\320\263\320\276\321\202\320\276\320\262\320\272\320\260 \321\204\320\260\320\271\320\273\320\276\320\262 \320\273\320\276\320\272\320\260\320\273\320\270\320\267\320\260\321\206\320\270\320\270 ...", Q_NULLPTR));
-        labelVersion->setText(QApplication::translate("MainWindow", "\320\235\320\260\321\201\320\273\320\265\320\264\320\270\320\265: v1.0.0", Q_NULLPTR));
+        labelVersion->setText(QApplication::translate("MainWindow", "\320\235\320\260\321\201\320\273\320\265\320\264\320\270\320\265: v1.0.1", Q_NULLPTR));
         designButton->setText(QApplication::translate("MainWindow", "\320\236\320\261\320\275\320\276\320\262\320\270\321\202\321\214", Q_NULLPTR));
         mainTitle->setText(QApplication::translate("MainWindow", "\320\222\320\273\320\260\321\201\321\202\320\265\320\273\320\270\320\275 \320\272\320\276\320\273\320\265\321\206 \320\236\320\275\320\273\320\260\320\271\320\275: \320\235\320\260\321\201\320\273\320\265\320\264\320\270\320\265", Q_NULLPTR));
     } // retranslateUi