瀏覽代碼

Major refactor improvements, part 2

Gi1dor (Ivan Arkhipov) 6 年之前
父節點
當前提交
de67d95efa

+ 27 - 3
CMakeLists.txt

@@ -1,10 +1,13 @@
 cmake_minimum_required(VERSION 3.8)
-project(LotRO_Gi1dor_dat_library)
+project(LotRO_dat_library)
 
 set(CMAKE_CXX_STANDARD 11)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 0.1.0)
 
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
+SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS} -static" )
+
 set(CMAKE_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin)
 set(CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Source)
 
@@ -33,6 +36,27 @@ set(SOURCE_FILES
 
         ${CMAKE_SOURCE_DIR}/Common/SQLite/sqlite3.c
         ${CMAKE_SOURCE_DIR}/Common/SQLite/sqlite3.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/TextSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/TextSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/JpgSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/JpgSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/DdsSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/DdsSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/OggSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/OggSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/FontSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/FontSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/WavSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/WavSubfile.h
+
+        ${CMAKE_SOURCE_DIR}/Subfiles/UnknownSubfile.cpp
+        ${CMAKE_SOURCE_DIR}/Subfiles/UnknownSubfile.h
         )
 
 
@@ -49,6 +73,6 @@ add_executable(LotRO_dat_extract_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Test
 target_link_libraries(LotRO_dat_extract_tester ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
 
 # FOR PATCHER USE NEXT LINE
-add_executable(LotRO_dat_patch_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/patch_test.cpp)
-target_link_libraries(LotRO_dat_patch_tester ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
+add_executable(LotRO_dat_pat_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/patch_test.cpp)
+target_link_libraries(LotRO_dat_pat_tester ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
 

+ 12 - 23
Source/DatFile.cpp

@@ -21,9 +21,13 @@ namespace LOTRO_DAT {
     DatFile::DatFile(const char *filename, int dat_id) {
         dat_id_ = dat_id;
         dat_state_ = CLOSED;
+        printf("state1\n");
         OpenDatFile(filename);
+        printf("state2\n");
         ReadSuperBlock();
+        printf("state3\n");
         MakeDirectories();
+        printf("end\n");
         try {
             MakeDictionary();
         } catch (...) {
@@ -37,23 +41,9 @@ namespace LOTRO_DAT {
                                INIT_EXCEPTION);
     }
 
-    DatFile::DatFile(const std::string &filename, int dat_id) {
-        dat_id_ = dat_id;
-        dat_state_ = CLOSED;
-        OpenDatFile(filename.c_str());
-        ReadSuperBlock();
-        MakeDirectories();
-        MakeDictionary();
-        if (dat_state_ == SUCCESS_DICTIONARY)
-            dat_state_ = READY;
-        else
-            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
-                               INIT_EXCEPTION);
-    }
-
     DatFile::~DatFile() {
         if (file_handler_ != nullptr)
-            fclose(file_handler_);
+		    fclose(file_handler_);
         delete file_handler_;
         delete root_directory_;
     }
@@ -141,7 +131,7 @@ namespace LOTRO_DAT {
 
     bool DatFile::PatchTextFile(long long file_id, long long gossip_id, std::string text, std::string args_order,
                                 std::string args) {
-
+        return false;
     }
 
     /// Patches .dat with text file with specific file_id and gossip_id.
@@ -150,7 +140,7 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened;
 
     bool DatFile::PatchTextFile(long long file_id, long long gossip_id, Database *db) {
-
+        return false;
     }
 
     /// Patches .dat with binary file with specific file_id.
@@ -159,7 +149,7 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened;
 
     bool DatFile::PatchBinaryFile(long long file_id, std::string file_path) {
-
+        return false;
     }
 
     /// Patches .dat with binary file with specific file_id.
@@ -168,7 +158,7 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened;
 
     bool DatFile::PatchBinaryFile(long long file_id, Database *db) {
-
+        return false;
     }
 
     void DatFile::OpenDatFile(const char *dat_name) {
@@ -184,9 +174,9 @@ namespace LOTRO_DAT {
             throw DatException(err.c_str(), INIT_EXCEPTION);
         }
 
-        _fseeki64(file_handler_, 0, SEEK_END);
-        file_size_ = _ftelli64(file_handler_);
-        _fseeki64(file_handler_, 0, SEEK_SET);
+        fseek(file_handler_, 0, SEEK_END);
+        file_size_ = ftell(file_handler_);
+        fseek(file_handler_, 0, SEEK_SET);
 
         dat_state_ = SUCCESS_OPENED;
     }
@@ -203,7 +193,6 @@ namespace LOTRO_DAT {
         version1_ = data.ToNumber<4>(0x14C);
         version2_ = data.ToNumber<4>(0x150);
         root_directory_offset_ = data.ToNumber<4>(0x160);
-
         auto size1 = data.ToNumber<4>(0x148);
 
         if (constant1_ != 0x4C5000)

+ 153 - 73
Source/SubDirectory.cpp

@@ -8,88 +8,168 @@
 #include "Subfile.h"
 #include "BinaryData.h"
 
-LOTRO_DAT::SubDirectory::SubDirectory() {
-    offset_ = 0;
-}
-
-LOTRO_DAT::SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
-        offset_(offset), dat_(dat), max_subdirs_(max_subdirs) {
-    try {
-        MakeSubDirectories();
-    } catch (...) {
-		fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n", offset);
-		subdirs_.clear();
-		subfiles_.clear();
-		return;
-	}
-
-    try {
-        MakeSubFiles();
-	} catch (...) {
-		fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n", offset);
-		subdirs_.clear();
-		subfiles_.clear();
-		return;
-	}
-}
-
-void LOTRO_DAT::SubDirectory::MakeSubDirectories() {
-    BinaryData data(1024);
-    dat_->ReadData(data, 63 * 8, offset_);
-    if (data.ToNumber<4>(0) != 0 || data.ToNumber<4>(4) != 0) {
-        std::string err =
-                std::string("Bad SubDirectory::MakeSubDirectories - first 8 bytes are not equal to 0 at offset ")
-                + std::to_string(offset_);
-        throw DatException(err.c_str(), SUBDIR_EXCEPTION);
+#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 {
+    SubDirectory::SubDirectory() {
+        offset_ = 0;
     }
 
-    for (unsigned int i = 8; i < 63 * 8; i += 8) {
-        if (data.ToNumber<4>(i) == 0 || data.ToNumber<4>(i + 4) == 0)
-            break;
+    SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
+            offset_(offset), dat_(dat), max_subdirs_(max_subdirs) {
+        try {
+            MakeSubDirectories();
+        }catch (...) {
+            fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n",
+                    offset);
+            subdirs_.clear();
+            subfiles_.clear();
+            return;
+        }
 
         try {
-            subdirs_.emplace_back(
-                    SubDirectory(
-                            data.ToNumber<4>(i + 4),
-                            dat_
+            MakeSubFiles();
+        }catch (...) {
+            fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n",
+                    offset);
+            subdirs_.clear();
+            subfiles_.clear();
+            return;
+        }
+    }
+
+    void SubDirectory::MakeSubDirectories() {
+        BinaryData data(1024);
+        dat_->ReadData(data, 63 * 8, offset_);
+        if (data.ToNumber<4>(0) != 0 || data.ToNumber<4>(4) != 0) {
+            std::string err =
+                    std::string("Bad SubDirectory::MakeSubDirectories - first 8 bytes are not equal to 0 at offset ")
+                    + std::to_string(offset_);
+            throw DatException(err.c_str(), SUBDIR_EXCEPTION);
+        }
+
+        for (unsigned int i = 8; i < 63 * 8; i += 8) {
+            if (data.ToNumber<4>(i) == 0 || data.ToNumber<4>(i + 4) == 0)
+                break;
+
+            try {
+                subdirs_.emplace_back(
+                        SubDirectory(
+                                data.ToNumber<4>(i + 4),
+                                dat_
+                        )
+                );
+
+            }catch (...) {
+                fprintf(stderr, "Making SubDirectory at offset %lld failed, continuing\n", data.ToNumber<4>(i + 4));
+            }
+        }
+    }
+
+    void SubDirectory::MakeSubFiles() {
+        BinaryData data(64 * 32);
+        dat_->ReadData(data, 64 * 32, offset_ + 63 * 8);
+
+        for (unsigned int i = 0; i < 61 * 32; i += 32) {
+            if (data.ToNumber<4>(i + 8) < 0x32 || data.ToNumber<4>(i + 12) < 0x32)
+                continue;
+            subfiles_.emplace_back(
+                    MakeSubfile(
+                            data.ToNumber<4>(i), // fragments_count
+                            data.ToNumber<4>(i + 4), // unknown1
+                            data.ToNumber<4>(i + 8), // file_id
+                            data.ToNumber<4>(i + 12), // file_offset
+                            data.ToNumber<4>(i + 16), // block_size
+                            data.ToNumber<4>(i + 20), // timestamp
+                            data.ToNumber<4>(i + 24), // version
+                            data.ToNumber<4>(i + 28) // block_size
                     )
             );
-
-        } catch (...) {
-            fprintf(stderr, "Making SubDirectory at offset %lld failed, continuing\n",  data.ToNumber<4>(i + 4));
         }
     }
-}
-
-void LOTRO_DAT::SubDirectory::MakeSubFiles() {
-    BinaryData data(64 * 32);
-    dat_->ReadData(data, 64 * 32, offset_ + 63 * 8);
-
-    for (unsigned int i = 0; i < 61 * 32; i += 32) {
-        if (data.ToNumber<4>(i + 8) < 0x32 || data.ToNumber<4>(i + 12) < 0x32)
-            continue;
-        subfiles_.emplace_back(
-            Subfile(
-                    dat_,
-                    data.ToNumber<4>(i), // fragments_count
-                    data.ToNumber<4>(i + 4), // unknown1
-                    data.ToNumber<4>(i + 8), // file_id
-                    data.ToNumber<4>(i + 12), // file_offset
-                    data.ToNumber<4>(i + 16), // block_size
-                    data.ToNumber<4>(i + 20), // timestamp
-                    data.ToNumber<4>(i + 24), // version
-                    data.ToNumber<4>(i + 28) // block_size
-            )
-        );
+
+    void SubDirectory::MakeDictionary(std::unordered_map<long long, Subfile *> &dict) {
+        for (Subfile *i : subfiles_) {
+            if (dict.count(i->file_id()) == 0 || dict[i->file_id()]->timestamp() < i->timestamp())
+                dict[i->file_id()] = i;
+        }
+
+        for (SubDirectory &i : subdirs_)
+            i.MakeDictionary(dict);
     }
-}
 
-void LOTRO_DAT::SubDirectory::MakeDictionary(std::unordered_map<long long, Subfile *> &dict) {
-    for (Subfile &i : subfiles_) {
-        if (dict.count(i.file_id()) == 0 || dict[i.file_id()]->timestamp() < i.timestamp())
-			dict[i.file_id()] = &i;
+    Subfile *SubDirectory::MakeSubfile(long long fragments_count, long long unknown1, long long file_id,
+                                       long long file_offset, long long file_size, long long timestamp,
+                                       long long version, long long block_size) {
+
+        FILE_TYPE type = GetSubfileType(file_id, file_offset);
+
+        switch (type) {
+            case TEXT:
+                return dynamic_cast<Subfile *>(new TextSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            case JPG:
+                return dynamic_cast<Subfile *>(new JpgSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            case DDS:
+                return dynamic_cast<Subfile *>(new DdsSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            case WAV:
+                return dynamic_cast<Subfile *>(new WavSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            case OGG:
+                return dynamic_cast<Subfile *>(new OggSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            case FONT:
+                return dynamic_cast<Subfile *>(new FontSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+            default:
+                return dynamic_cast<Subfile *>(new UnknownSubfile(fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
+        }
     }
 
-    for (SubDirectory &i : subdirs_)
-        i.MakeDictionary(dict);
-}
+    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);
+        try {
+            dat_->ReadData(header, 64, (unsigned) file_offset + 8);
+        }catch (DatException &e) {
+            if (e.type() == READ_EXCEPTION) {
+                std::string err =
+                        "Bad Subfile::getExtension() - unable to read header of file with id = " +
+                        std::to_string(file_id) +
+                        " and offset = " + std::to_string(file_offset);
+                throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+            } else
+                throw e;
+        }
+
+        // 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;
+    }
+};

+ 6 - 1
Source/SubDirectory.h

@@ -13,6 +13,7 @@ extern "C++"
 {
 namespace LOTRO_DAT
 {
+    enum FILE_TYPE : int;
     class DatFile;
     class DatException;
     class BinaryData;
@@ -29,11 +30,15 @@ namespace LOTRO_DAT
         void MakeSubDirectories();
         void MakeSubFiles();
 
+        Subfile* MakeSubfile(long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                             long long file_size, long long timestamp, long long version, long long block_size);
+        FILE_TYPE GetSubfileType(long long file_id, long long file_offset) const;
+
         DatFile *dat_;
         long long offset_;
         long long max_subdirs_;
         std::vector<SubDirectory> subdirs_;
-        std::vector<Subfile> subfiles_;
+        std::vector<Subfile *> subfiles_;
     };
 }
 };

+ 47 - 478
Source/Subfile.cpp

@@ -14,506 +14,75 @@
 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
-
-LOTRO_DAT::Subfile::Subfile() {
-	ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-		throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-	ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
-
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
-
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
+namespace LOTRO_DAT {
+    Subfile::Subfile() {}
+
+    Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id,
+                                long long file_offset,
+                                long long file_size, long long timestamp, long long version, long long block_size) :
+            dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id),
+            file_offset_(file_offset),
+            file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+        if (file_size_ > MAXSIZE)
+            throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?",
+                               SUBFILE_EXCEPTION);
     }
 
-    // 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;
+    long long Subfile::fragments_count() const {
+        return fragments_count_;
     }
 
-    // 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;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::ext() const {
-	return ext_;
-}
-
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-	switch (ext)
-	{
-	case LOTRO_DAT::TEXT:
-		return ".txt";
-	case LOTRO_DAT::JPG:
-		return ".jpg";
-	case LOTRO_DAT::DDS:
-		return ".dds";
-	case LOTRO_DAT::WAV:
-		return ".wav";
-	case LOTRO_DAT::OGG:
-		return ".ogg";
-	case LOTRO_DAT::FONT:
-		return ".fontbin";
-	case LOTRO_DAT::UNKNOWN:
-		return ".unk";
-	default:
-		return "";
-	}
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
-
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
+    long long Subfile::unknown1() const {
+        return unknown1_;
     }
 
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
-        return true;
+    long long Subfile::file_id() const {
+        return file_id_;
     }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-    , IMPORT_EXCEPTION);
-    return true;
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-	try {
-        BinaryData data;
-
-		switch (ext_)
-		{
-		case LOTRO_DAT::TEXT:
-            return false;
-		case LOTRO_DAT::JPG:
-			data = PrepareAsJPG(); break;
-		case LOTRO_DAT::DDS:
-			data = PrepareAsDDS(); break;
-		case LOTRO_DAT::WAV:
-			data = PrepareAsWAV(); break;
-		case LOTRO_DAT::OGG:
-			data = PrepareAsOGG(); break;
-		case LOTRO_DAT::FONT:
-			data = PrepareAsFont(); break;
-		case LOTRO_DAT::UNKNOWN:
-			data = PrepareAsUnk(); break;
-		default:
-			break;
-		}
-
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-	}
-	catch (DatException &e) {
-		fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-		fprintf(stderr, "%s\n", e.what());
-        return false;
-	}
-}
 
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        db->PushBinaryFile(file_id_, data);
-        return true;
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
+    long long Subfile::file_offset() const {
+        return file_offset_;
     }
-}
 
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
+    long long Subfile::file_size() const {
+        return file_size_;
     }
 
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
-
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-	long long text_fragment_num = data.ToNumber<1>(offset);
-	if ((text_fragment_num & 0x80) != 0) {
-		text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-		offset += 1;
-	}
-	offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
-
-        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-
-        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;
-        }
-
-        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
-        }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    long long Subfile::timestamp() const {
+        return timestamp_;
     }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
 
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
+    long long Subfile::version() const {
+        return version_;
     }
 
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
+    long long Subfile::block_size() const {
+        return block_size_;
     }
 
-    return data;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        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;
+    FILE_TYPE Subfile::FileType() const {
+        throw DatException("Bad Subfile::FileType() - function is not implemented for this type.", SUBFILE_EXCEPTION);
     }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
+    std::string Subfile::Extension() const {
+        throw DatException("Bad Subfile::Extension() - function is not implemented for this type.", SUBFILE_EXCEPTION);
+    }
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
+    bool Subfile::PrepareAsBinary(BinaryData &data) {
+        throw DatException("Bad Subfile::PrepareAsBinary() - function is not implemented for this type.", EXPORT_EXCEPTION);
+    }
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
+    bool Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+        throw DatException("Bad Subfile::PrepareAsText() - function is not implemented for this type.", EXPORT_EXCEPTION);
+    }
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
+    BinaryData& Subfile::MakeFromBinary(const BinaryData &data) {
+        throw DatException("Bad Subfile::MakeFromBinary() - function is not implemented fot this type.", EXPORT_EXCEPTION);
+    }
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
+    BinaryData& Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+        throw DatException("Bad Subfile::MakeFromText() - function is not implemented for this type.", EXPORT_EXCEPTION);
+    }
 
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
+};

+ 9 - 40
Source/Subfile.h

@@ -15,44 +15,33 @@ namespace LOTRO_DAT
     class Database;
     enum FILE_TYPE : int;
 
-
     class Subfile
     {
     public:
         Subfile();
+        Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                                    long long file_size, long long timestamp, long long version, long long block_size);
 
-        Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset, long long file_size,
-                long long timestamp, long long version, long long block_size);
-
-        bool ExportFile(const char* filename) const;
-        bool ExportFile(Database *db) const;
+        virtual FILE_TYPE FileType() const;
+        virtual std::string Extension() const;
 
-		bool ExportFileAsTXT(Database *db = nullptr) const;
+        virtual bool PrepareAsBinary(BinaryData &data);
+        virtual bool PrepareAsText(std::string &text, std::string &args, std::string &args_order);
 
-		bool PatchBinaryFile(const BinaryData &file);
-
-        bool PatchTextFile();
+        virtual BinaryData& MakeFromBinary(const BinaryData &data);
+        virtual BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order);
 
         long long fragments_count() const;
-
         long long unknown1() const;
-
         long long file_id() const;
-
         long long file_offset() const;
-
         long long file_size() const;
-
         long long timestamp() const;
-
         long long version() const;
-
         long long block_size() const;
 
-		FILE_TYPE ext() const;
-    
 	private:
-        long long fragments_count_;
+		long long fragments_count_;
         long long unknown1_;
         long long file_id_;
         long long file_offset_;
@@ -64,28 +53,8 @@ namespace LOTRO_DAT
         bool compressed_;
 
         DatFile *dat_;
-		FILE_TYPE ext_;
-
-		FILE_TYPE GetExtension() const;
-		std::string ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const;
 
 		BinaryData GetFileData(long long offset = 8) const;
-
-        // Export functions block
-		const BinaryData PrepareAsJPG() const;
-		const BinaryData PrepareAsDDS() const;
-		const BinaryData PrepareAsOGG() const;
-		const BinaryData PrepareAsFont() const;
-		const BinaryData PrepareAsWAV() const;
-		const BinaryData PrepareAsUnk() const;
-
-        // Patch functions block
-        const BinaryData MakeFromJPG(const BinaryData &file) const;
-        const BinaryData MakeFromDDS(const BinaryData &file) const;
-        const BinaryData MakeFromOGG(const BinaryData &file) const;
-        const BinaryData MakeFromFont(const BinaryData &file) const;
-        const BinaryData MakeFromWAV(const BinaryData &file) const;
-        const BinaryData MakeFromUnk(const BinaryData &file) const;
     };
 }
 };

+ 558 - 0
Source/Subfiles/DdsSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "DdsSubfile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+ */

+ 28 - 0
Source/Subfiles/DdsSubfile.h

@@ -0,0 +1,28 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_DDSSUBFILE_H
+#define LOTRO_DAT_LIBRARY_DDSSUBFILE_H
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class DdsSubfile : Subfile {
+        DdsSubfile();
+        DdsSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                                 long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+#endif //LOTRO_DAT_LIBRARY_DDSSUBFILE_H

+ 558 - 0
Source/Subfiles/FontSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "FontSubFile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+*/

+ 31 - 0
Source/Subfiles/FontSubfile.h

@@ -0,0 +1,31 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_FONTSUBFILE_H
+#define LOTRO_DAT_LIBRARY_FONTSUBFILE_H
+
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class FontSubfile : Subfile {
+        FontSubfile();
+        FontSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        virtual FILE_TYPE FileType() const override;
+        virtual std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+
+
+#endif //LOTRO_DAT_LIBRARY_FONTSUBFILE_H

+ 558 - 0
Source/Subfiles/JpgSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "JpgSubfile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+ */

+ 31 - 0
Source/Subfiles/JpgSubfile.h

@@ -0,0 +1,31 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_JPGSUBFILE_H
+#define LOTRO_DAT_LIBRARY_JPGSUBFILE_H
+
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class JpgSubfile : Subfile {
+        JpgSubfile();
+        JpgSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+
+
+#endif //LOTRO_DAT_LIBRARY_JPGSUBFILE_H

+ 558 - 0
Source/Subfiles/OggSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "OggSubfile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+ */

+ 27 - 0
Source/Subfiles/OggSubfile.h

@@ -0,0 +1,27 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_OGGSUBFILE_H
+#define LOTRO_DAT_LIBRARY_OGGSUBFILE_H
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class OggSubfile : Subfile {
+        OggSubfile();
+        OggSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+    };
+};
+
+#endif //LOTRO_DAT_LIBRARY_OGGSUBFILE_H

+ 558 - 0
Source/Subfiles/TextSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "TextSubfile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+*/

+ 31 - 0
Source/Subfiles/TextSubfile.h

@@ -0,0 +1,31 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_TEXTSUBFILE_H
+#define LOTRO_DAT_LIBRARY_TEXTSUBFILE_H
+
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class TextSubfile : Subfile {
+        TextSubfile();
+        TextSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+
+
+#endif //LOTRO_DAT_LIBRARY_TEXTSUBFILE_H

+ 5 - 0
Source/Subfiles/UnknownSubfile.cpp

@@ -0,0 +1,5 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "UnknownSubfile.h"

+ 31 - 0
Source/Subfiles/UnknownSubfile.h

@@ -0,0 +1,31 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_UNKNOWNSUBFILE_H
+#define LOTRO_DAT_LIBRARY_UNKNOWNSUBFILE_H
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class UnknownSubfile : Subfile {
+        UnknownSubfile();
+        UnknownSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+
+
+
+#endif //LOTRO_DAT_LIBRARY_UNKNOWNSUBFILE_H

+ 558 - 0
Source/Subfiles/WavSubfile.cpp

@@ -0,0 +1,558 @@
+/*
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#include "WavSubfile.h"
+
+//
+// Created by Иван_Архипов on 01.11.2017.
+//
+
+#include "Subfile.h"
+#include "BinaryData.h"
+#include "DatFile.h"
+#include "Common/DatException.h"
+#include "Database.h"
+#include "Common/CommonFunctions.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
+
+LOTRO_DAT::Subfile::Subfile() {
+    ext_ = UNKNOWN;
+    compressed_ = false;
+}
+
+LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                            long long file_size, long long timestamp, long long version, long long block_size) :
+        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
+        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+
+    if (file_size_ > MAXSIZE)
+        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
+    ext_ = GetExtension();
+
+    BinaryData header(20);
+    dat_->ReadData(header, 10, file_offset_ + 8);
+    compressed_ = header.CheckCompression();
+}
+
+long long LOTRO_DAT::Subfile::fragments_count() const {
+    return fragments_count_;
+}
+
+long long LOTRO_DAT::Subfile::unknown1() const {
+    return unknown1_;
+}
+
+long long LOTRO_DAT::Subfile::file_id() const {
+    return file_id_;
+}
+
+long long LOTRO_DAT::Subfile::file_offset() const {
+    return file_offset_;
+}
+
+long long LOTRO_DAT::Subfile::file_size() const {
+    return file_size_;
+}
+
+long long LOTRO_DAT::Subfile::timestamp() const {
+    return timestamp_;
+}
+
+long long LOTRO_DAT::Subfile::version() const {
+    return version_;
+}
+
+long long LOTRO_DAT::Subfile::block_size() const {
+    return block_size_;
+}
+
+LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() 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);
+    try {
+        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
+    } catch (DatException &e) {
+        if (e.type() == READ_EXCEPTION) {
+            std::string err =
+                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
+                    " and offset = " + std::to_string(file_offset());
+            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
+        } else
+            throw e;
+    }
+
+    // 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;
+}
+
+std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
+    switch (ext)
+    {
+        case LOTRO_DAT::TEXT:
+            return ".txt";
+        case LOTRO_DAT::JPG:
+            return ".jpg";
+        case LOTRO_DAT::DDS:
+            return ".dds";
+        case LOTRO_DAT::WAV:
+            return ".wav";
+        case LOTRO_DAT::OGG:
+            return ".ogg";
+        case LOTRO_DAT::FONT:
+            return ".fontbin";
+        case LOTRO_DAT::UNKNOWN:
+            return ".unk";
+        default:
+            return "";
+    }
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
+    LOTRO_DAT::BinaryData data;
+
+    // Making data for placing in .dat, depending on file extension
+    switch (ext_)
+    {
+        case LOTRO_DAT::TEXT:
+            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
+        case LOTRO_DAT::JPG:
+            data = MakeFromJPG(file); break;
+        case LOTRO_DAT::DDS:
+            data = MakeFromDDS(file); break;
+        case LOTRO_DAT::WAV:
+            data = MakeFromWAV(file); break;
+        case LOTRO_DAT::OGG:
+            data = MakeFromOGG(file); break;
+        case LOTRO_DAT::FONT:
+            data = MakeFromFont(file); break;
+        case LOTRO_DAT::UNKNOWN:
+            data = MakeFromUnk(file); break;
+        default:
+            break;
+    }
+
+    if (block_size() >= data.size() + 8) {
+        dat_->WriteData(data, data.size(), file_offset() + 8);
+        return true;
+    }
+    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
+            , IMPORT_EXCEPTION);
+    return true;
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
+    try {
+        BinaryData data;
+
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return false;
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
+        return data.WriteToFile(s);
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
+    try {
+        BinaryData data;
+        switch (ext_)
+        {
+            case LOTRO_DAT::TEXT:
+                return ExportFileAsTXT(db);
+            case LOTRO_DAT::JPG:
+                data = PrepareAsJPG(); break;
+            case LOTRO_DAT::DDS:
+                data = PrepareAsDDS(); break;
+            case LOTRO_DAT::WAV:
+                data = PrepareAsWAV(); break;
+            case LOTRO_DAT::OGG:
+                data = PrepareAsOGG(); break;
+            case LOTRO_DAT::FONT:
+                data = PrepareAsFont(); break;
+            case LOTRO_DAT::UNKNOWN:
+                data = PrepareAsUnk(); break;
+            default:
+                break;
+        }
+
+        db->PushBinaryFile(file_id_, data);
+        return true;
+    }
+    catch (DatException &e) {
+        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
+        fprintf(stderr, "%s\n", e.what());
+        return false;
+    }
+}
+
+bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
+    if (db == nullptr) {
+        return false;
+    }
+
+    if (file_size() == 10) // File is empty, nothing to do;
+        return false;
+
+    BinaryData data = GetFileData();
+
+    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
+
+    long long text_fragment_num = data.ToNumber<1>(offset);
+    if ((text_fragment_num & 0x80) != 0) {
+        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
+        offset += 1;
+    }
+    offset += 1;
+
+    for (long long i = 0; i < text_fragment_num; i++) {
+        long long fragment_id = data.ToNumber<8>(offset);
+        offset += 8;
+
+        long long num_pieces = data.ToNumber<4>(offset);
+        offset += 4;
+
+        std::vector<std::u16string> text_pieces;
+        std::vector<long long> arg_references;
+        std::vector<std::vector<BinaryData> > arg_strings;
+
+        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 * k + 1])) << 8) | (short(piece_data[2 * k])));
+                piece += c;
+            }
+
+            text_pieces.push_back(piece);
+            offset += piece_size * 2;
+        }
+
+        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;
+        }
+
+        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[j].emplace_back(data.CutData(offset, offset + string_size * 2));
+                offset += string_size * 2;
+            }
+        }
+
+        std::u16string text = u"[";
+        for (int i = 0; i + 1 < text_pieces.size(); i++)
+            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
+        text += text_pieces[text_pieces.size() - 1] + u"]";
+
+        std::string arguments;
+        for (int i = 0; i + 1 < arg_references.size(); i++)
+            arguments += std::to_string(arg_references[i]) + "-";
+        if (arg_references.size() >= 1)
+            arguments += std::to_string(arg_references[arg_references.size() - 1]);
+
+        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
+    }
+    return true;
+}
+
+LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
+    BinaryData mfile_id(4);
+    dat_->ReadData(mfile_id, 4, file_offset() + 8);
+    if (file_id() != mfile_id.ToNumber<4>(0))
+        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
+
+    BinaryData data((unsigned)(file_size()));
+    if (block_size() >= file_size() + 8) {
+        dat_->ReadData(data, file_size(), file_offset() + offset);
+        return data;
+    }
+
+    BinaryData fragments_count(4);
+    dat_->ReadData(fragments_count, 4, file_offset());
+
+    long long fragments_number = fragments_count.ToNumber<4>(0);
+
+    long long current_block_size = block_size() - offset - 8 * fragments_number;
+
+    dat_->ReadData(data, current_block_size , file_offset() + offset);
+
+    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
+    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + 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);
+        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
+        current_block_size += fragment_size;
+    }
+
+    return data;
+}
+
+LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
+    return nullptr;
+}
+
+bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
+    return false;
+}
+
+bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
+    return false;
+}
+
+LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
+    return <#initializer#>;
+}
+
+LOTRO_DAT::BinaryData &
+LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
+    return <#initializer#>;
+}
+
+*/
+/*
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
+    return GetFileData().CutData(24);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
+    BinaryData data = GetFileData();
+    if (compressed_)
+        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;
+    }
+	return ddsData;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
+    return GetFileData().CutData(8);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
+    return GetFileData();
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
+    return GetFileData().CutData(0, 24) + file;
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
+}
+
+const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
+    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
+}
+ */

+ 29 - 0
Source/Subfiles/WavSubfile.h

@@ -0,0 +1,29 @@
+//
+// Created by Иван_Архипов on 24.11.2017.
+//
+
+#ifndef LOTRO_DAT_LIBRARY_WAVSUBFILE_H
+#define LOTRO_DAT_LIBRARY_WAVSUBFILE_H
+
+#include "../Subfile.h"
+
+namespace LOTRO_DAT {
+    class WavSubfile : Subfile {
+        WavSubfile();
+        WavSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
+                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        FILE_TYPE FileType() const override;
+        std::string GetExtension() const override;
+
+        bool PrepareAsBinary(BinaryData &data) override;
+        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+
+        BinaryData& MakeFromBinary(const BinaryData &data) override;
+        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+
+    };
+};
+
+
+#endif //LOTRO_DAT_LIBRARY_WAVSUBFILE_H

+ 2 - 2
Source/Tests/extract_test.cpp

@@ -16,7 +16,7 @@ using namespace LOTRO_DAT;
 
 
 // Change these 2 variables to your path and name of .dat file
-const std::string path = "E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
+const std::string path = "";//"E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
 const std::string filename = "client_local_English.dat";
 
 // Change these variables to true if you want export catecory to files.
@@ -55,7 +55,7 @@ int main() {
 
     try {
         std::cout << "Starting search...\n";
-        DatFile a(path + filename, 0);
+        DatFile a((path + filename).c_str(), 0);
         std::cout << "Total files found: " << a.files_number() << std::endl;
 
         std::cout << "Writing unordered dictionary:\n";

+ 9 - 9
Source/Tests/patch_test.cpp

@@ -15,7 +15,7 @@
 using namespace LOTRO_DAT;
 
 // Change these 2 variables to your path and name of .dat file
-const std::string path = "E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
+const std::string path = "";//"E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
 const std::string filename = "client_local_English.dat";
 
 const std::string patch_filename = "image.jpg";
@@ -24,19 +24,19 @@ const int file_id = 0;
 int main() {
     const clock_t begin_time = clock();
 
-    freopen("patch_errors.log", "w", stderr);
+    freopen("errors.log", "w", stderr);
     try {
-        std::cout << "Starting search...\n";
-        DatFile a(path + filename, 0);
-        std::cout << "Total files found: " << a.files_number() << std::endl;
-
-        fprintf(stdout, "Spent %f seconds on running patcher! Thank you for your patience!\n",
-                float(clock() - begin_time) / CLOCKS_PER_SEC);
-        system("pause");
+        std::cout << "Starting magic...\n";
+        DatFile a((path + filename).c_str(), 0);
+        std::cout << "Magic number: " << a.files_number() << std::endl;
     } catch (...) {
         printf("Some critical errors occured. Need to stop execution. See information in errors.log file");
         fprintf(stderr, "Some critical errors occured. Need to stop execution now...");
     }
+
+    fprintf(stdout, "Spent %f seconds on performing magic! Thank you for your patience!\n",
+            float(clock() - begin_time) / CLOCKS_PER_SEC);
+    system("pause");
     return 0;
 }