Prechádzať zdrojové kódy

Completed Extractor module

Ivan Arkhipov 5 rokov pred
rodič
commit
cbf605f415

+ 2 - 2
CMakeLists.txt

@@ -97,9 +97,9 @@ add_library(LotroDat_static STATIC ${SOURCE_FILES} ${HEADER_FILES})
 # SHARED LIBRARY
 add_library(LotroDat SHARED ${SOURCE_FILES} ${HEADER_FILES})
 # CONSOLE EXTRACTOR TOOL
-add_executable(LotRO_dat_extractor ${SOURCE_FILES} ${HEADER_FILES} ${CMAKE_SOURCE_DIR}/src/Examples/extractor_example.cpp)
+add_executable(LotRO_dat_extractor ${CMAKE_SOURCE_DIR}/src/Examples/extractor_example.cpp ${SOURCE_FILES} ${HEADER_FILES})
 # CONSOLE PATCHER TOOL
-add_executable(LotRO_dat_patcher ${SOURCE_FILES} ${HEADER_FILES} ${CMAKE_SOURCE_DIR}/src/Examples/patcher_example.cpp)
+add_executable(LotRO_dat_patcher ${CMAKE_SOURCE_DIR}/src/Examples/patcher_example.cpp ${SOURCE_FILES} ${HEADER_FILES})
 # FILE INFO GATHERER
 add_executable(LotRO_dat_info_gatherer ${SOURCE_FILES} ${HEADER_FILES} ${CMAKE_SOURCE_DIR}/src/Examples/info_gatherer.cpp)
 

BIN
bin/LotRO_dat_extractor.exe


+ 4 - 3
include/DatFile.h

@@ -50,13 +50,13 @@ namespace LOTRO_DAT {
         DatFile &operator=(DatFile &&other) = default;
 
         DatLocaleManager &getLocaleManager();
-//        DatExporter &getExporter();
+        DatExporter &getExporter();
 //        DatPatcher &getPatcher();
 //        DatBackupManager &getBackupManager();
         DatIO &getIO();
         DatFileSystem &getFileSystem();
 
-        DatOperationResult<> Initialise(const std::string &filename);
+        DatOperationResult<> Initialise(const std::string &filename, long long dat_id);
         DatOperationResult<> GatherInformation(const std::string &output_filename);
         DatOperationResult<> Deinitialize();
         bool Initialized();
@@ -66,9 +66,10 @@ namespace LOTRO_DAT {
         std::unique_ptr<DatFileSystem> fileSystem_;
         std::unique_ptr<DatLocaleManager> localeManager_;
 //        std::unique_ptr<DatPatcher> patcher_;
-//        std::unique_ptr<DatExporter> exporter_;
+        std::unique_ptr<DatExporter> exporter_;
 //        std::unique_ptr<DatBackupManager> backupManager_;
         bool initialized_;
+        long long dat_id_;
     };
 }
 }

+ 26 - 6
include/DatSubsystems/DatExporter.h

@@ -1,24 +1,44 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
 #ifndef LOTRO_DAT_LIBRARY_DATEXPORTER_H
 #define LOTRO_DAT_LIBRARY_DATEXPORTER_H
 
+#include <DatOperationResult.h>
+#include <Database.h>
+
 extern "C++" {
 namespace LOTRO_DAT {
-    class DatFile;
+
+    enum FILE_TYPE : int;
+
+    /*!
+     * \brief Модуль экспорта файлов
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Класс для экспорта файлов из dat контейнера. Позволяет извлекать файлы по их типам в базу данных или в папку.
+     * Также позволяет извлекать отдельные файлы по их id.
+     * \warning Объекты этого класса не должны создаваться отдельно! Созданием и управлением ими занимается класс DatFile
+     */
 
     class DatExporter {
     public:
         DatExporter() = delete;
+
         DatExporter(const DatExporter &other) = delete;
-        DatExporter& operator=(const DatExporter &other) = delete;
+
+        DatExporter &operator=(const DatExporter &other) = delete;
+
         ~DatExporter() = default;
 
         explicit DatExporter(DatFile *datFilePtr);
 
+        DatOperationResult<int> ExtractAllFilesByType(const FILE_TYPE &type, std::string output_directory_path);
+
+        DatOperationResult<> ExtractFileById(long long file_id, std::string output_filename);
+
+        DatOperationResult<int> ExtractAllFilesByType(const FILE_TYPE &type, Database *db);
+
     private:
+        DatOperationResult<> WriteStringToFile(const std::u16string &str, const std::string &path);
+
         DatFile *dat;
 
     };

+ 6 - 11
include/DatSubsystems/DatFileSystem.h

@@ -44,6 +44,10 @@ namespace LOTRO_DAT {
 
         DatOperationResult<> Init();
 
+        DatOperationResult<> InitAllDirectories();
+
+        DatOperationResult<> InitAllFiles();
+
         DatOperationResult<BinaryData> GetFileData(long long file_id, long long int offset);
 
         DatOperationResult<std::shared_ptr<SubFile>> GetFile(long long file_id);
@@ -56,23 +60,14 @@ namespace LOTRO_DAT {
 
         DatOperationResult<> DeInit();
 
+        DatOperationResult<> PerformOperationOnAllFiles(std::function<void (std::shared_ptr<SubFile>&)> function);
+
     private:
-        //------------------------------------------------//
-        // PRIVATE INIT SECTION
-        //------------------------------------------------//
 
         DatOperationResult<> InitSubFile(long long file_id);
 
         DatOperationResult<> InitSubDirectory(SubDirectory dir);
 
-        DatOperationResult<> InitAllDirectories();
-
-        DatOperationResult<> InitAllFiles();
-
-        //------------------------------------------------//
-        // PRIVATE DEINIT SECTION
-        //------------------------------------------------//
-
         DatOperationResult<> CommitDirectories();
 
     private:

+ 0 - 1
include/DatSubsystems/DatIO.h

@@ -24,7 +24,6 @@ namespace LOTRO_DAT {
      * \date 30.06.2018
      * Класс для работы с вводом-выводом данных в dat-контейнере. Предоставляет функции чтения/записи данных, а также
      * информацию об основных параметрах dat файла
-     * информацию об основных параметрах dat файла
      * \warning Объекты этого класса не должны создаваться отдельно! Созданием и управлением ими занимается класс DatFile
      */
 

+ 8 - 5
src/DatFile.cpp

@@ -54,7 +54,7 @@ namespace LOTRO_DAT {
         io_ = std::make_unique<DatIO>(this);
         fileSystem_ = std::make_unique<DatFileSystem>(this);
         localeManager_ = std::make_unique<DatLocaleManager>(this);
-//        exporter_ = std::make_unique<DatExporter>(this);
+        exporter_ = std::make_unique<DatExporter>(this);
 //        patcher_ = std::make_unique<DatPatcher>(this);
 //        backupManager_ = std::make_unique<DatBackupManager>(this);
     }
@@ -63,9 +63,9 @@ namespace LOTRO_DAT {
         return *localeManager_;
     }
 
-//    DatExporter &DatFile::getExporter() {
-//        return *exporter_;
-//    }
+    DatExporter &DatFile::getExporter() {
+        return *exporter_;
+    }
 //
 //    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
 //        return *patcher_;
@@ -83,7 +83,9 @@ namespace LOTRO_DAT {
         return *fileSystem_;
     }
 
-    DatOperationResult<> DatFile::Initialise(const std::string &filename) {
+    DatOperationResult<> DatFile::Initialise(const std::string &filename, long long dat_id) {
+        dat_id_ = dat_id;
+
         if (initialized_ && io_->GetFilename().result == SUCCESS && io_->GetFilename().value == filename)
             return DatOperationResult<>();
 
@@ -148,5 +150,6 @@ namespace LOTRO_DAT {
     bool DatFile::Initialized() {
         return initialized_;
     }
+
 }
 }

+ 86 - 4
src/DatSubsystems/DatExporter.cpp

@@ -1,5 +1,87 @@
-//
-// Created by kikab on 04.06.2018.
-//
+#include <DatFile.h>
+#include <DatSubsystems/DatExporter.h>
+#include <DatSubsystems/DatFileSystem.h>
+#include <BinaryData.h>
+#include <SubfileData.h>
+#include <SubFile.h>
 
-#include "DatSubsystems/DatExporter.h"
+#include <string>
+#include <fstream>
+#include <algorithm>
+
+namespace LOTRO_DAT {
+    DatExporter::DatExporter(DatFile *datFilePtr) : dat(datFilePtr) {
+    }
+
+    DatOperationResult<int> DatExporter::ExtractAllFilesByType(const FILE_TYPE &type, std::string output_directory_path) {
+        int success_exported = 0;
+
+        auto operation = dat->getFileSystem().PerformOperationOnAllFiles([&success_exported, this, type, &output_directory_path](std::shared_ptr<SubFile>& file) -> void {
+            if (file->FileType() != type || !dat->getFileSystem().CheckCorrectSubfile(file))
+                return;
+            SubfileData export_file = file->PrepareForExport(dat->getFileSystem().GetFileData(file->file_id(), 8));
+
+            bool result;
+
+            if (type == TEXT)
+                result = WriteStringToFile(export_file.text_data, output_directory_path + std::to_string(file->file_id()) + file->Extension()).result;
+            else
+                result = export_file.binary_data.WriteToFile(output_directory_path + std::to_string(file->file_id()) + file->Extension());
+
+            if (result)
+                success_exported++;
+        });
+        return DatOperationResult<int>(success_exported, SUCCESS);
+    }
+
+    DatOperationResult<> DatExporter::ExtractFileById(long long file_id, std::string output_filename) {
+        auto operation_GetFileData = dat->getFileSystem().GetFileData(file_id, 8);
+        if (operation_GetFileData.result == ERROR)
+            return DatOperationResult<>(ERROR, "EXTRACTFILEBYID: Can't get data for id = " + std::to_string(file_id));
+
+
+        auto operation_GetFilePointer = dat->getFileSystem().GetFile(file_id);
+        if (operation_GetFileData.result == ERROR)
+            return DatOperationResult<>(ERROR, "EXTRACTFILEBYID: Can't get pointer for id = " + std::to_string(file_id));
+
+        SubfileData export_data = operation_GetFilePointer.value->PrepareForExport(operation_GetFileData.value);
+
+        if (export_data.Empty())
+            return DatOperationResult<>(ERROR, "EXTRACTFILEBYID: Export data is empty for id = " + std::to_string(file_id));
+
+        if (!export_data.binary_data.WriteToFile(output_filename + export_data.options["ext"].as<std::string>()))
+            return DatOperationResult<>(ERROR, "EXTRACTFILEBYID: Cannot write to file" + output_filename);
+
+        return DatOperationResult<>(SUCCESS);
+    }
+
+    DatOperationResult<int> DatExporter::ExtractAllFilesByType(const FILE_TYPE &type, Database *db) {
+        if (!db)
+            return DatOperationResult<int>(0, ERROR, "EXTRACTALLBYTYPETODB: database is nullptr");
+
+        int success_exported = 0;
+        auto operation = dat->getFileSystem().PerformOperationOnAllFiles([&success_exported, this, type, db](std::shared_ptr<SubFile>& file) {
+            if (!dat->getFileSystem().CheckCorrectSubfile(file))
+                return;
+
+            SubfileData export_file = file->PrepareForExport(dat->getFileSystem().GetFileData(file->file_id(), 8));
+
+            bool result = db->PushFile(export_file);
+
+            if (result)
+                success_exported++;
+        });
+        return DatOperationResult<int>(success_exported, SUCCESS);
+    }
+
+    DatOperationResult<> DatExporter::WriteStringToFile(const std::u16string &str, const std::string &path) {
+        FILE* file = fopen(path.c_str(), "w");
+        if (!file)
+            return DatOperationResult<>(ERROR, "WRITESTRINGTOFILE: cant open file " + path);
+
+        fprintf(file, "%s", (char *) str.c_str());
+        fclose(file);
+        return DatOperationResult<>();
+    }
+
+};

+ 18 - 0
src/DatSubsystems/DatFileSystem.cpp

@@ -5,6 +5,8 @@
 #include <SubFile.h>
 #include <SubDirectory.h>
 
+#include <functional>
+
 namespace LOTRO_DAT {
 
 
@@ -469,4 +471,20 @@ namespace LOTRO_DAT {
     }
 
 
+    /*!
+     * \author Gi1dor
+     * \date 03.07.2018
+     * Выполнение функции function для всех обнаруженных файлов в dat контейнере.
+     *
+     * \param[in] function Функтор, принимающий в качестве аргумента указатель на объект файла std::shared_ptr<SubFile>
+     */
+
+    DatOperationResult<> DatFileSystem::PerformOperationOnAllFiles(std::function<void (std::shared_ptr<SubFile>&)> function) {
+        InitAllFiles();
+        for (const auto &file_pair: dictionary_) {
+            auto file = file_pair.second;
+            function(file);
+        }
+        return DatOperationResult<>();
+    }
 }

+ 2 - 6
src/DatSubsystems/DatIO.cpp

@@ -1,15 +1,11 @@
 #include "BinaryData.h"
 #include "DatFile.h"
-#include "DatSubsystems/DatIO.h"
 #include "EasyLogging++/easylogging++.h"
-#include "SubDirectory.h"
-#include "SubFile.h"
+#include <DatOperationResult.h>
 
+#include "DatSubsystems/DatIO.h"
 #include <algorithm>
-#include <iterator>
 #include <locale>
-#include <DatOperationResult.h>
-#include <DatSubsystems/DatIO.h>
 
 #ifdef WIN32
 #define fseek _fseeki64

+ 33 - 44
src/Examples/extractor_example.cpp

@@ -45,14 +45,12 @@ int main() {
         std::cout << "Using .dat file from dat_file_path.txt...\n";
         std::cout << "Opening file " << filename << std::endl;
 
-        if (file.InitDatFile(filename, 0) == false) {
-            std::cout << "Dat file path from dat_file_path.txt - " << filename << " may be incorrect (cannot open "
-                    "DatFile due to error. See it in errors.log)\n";
-            file.CloseDatFile();
-        }
+        auto operation = file.Initialise(filename, 0);
+        if (operation.result == false)
+            std::cout << "Dat initialisation failed. Error message: " << operation.msg << "\n";
     }
 
-    while (file.DatFileState() == CLOSED) {
+    while (!file.Initialized()) {
         std::cout << "Please, tell, where the .dat file is\n";
         std::cout << "Enter path to file (including filename): ";
         std::string filename;
@@ -60,25 +58,15 @@ int main() {
 
         std::cout << "Opening file " << filename << std::endl;
 
-        if (file.InitDatFile(filename, 0) == false) {
-            std::cout << "Some error caused while opening the file... "
-                    "Could you enter .dat filename once more?" << std::endl;
-            file.CloseDatFile();
-        }
+        auto operation = file.Initialise(filename, 0);
+        if (operation.result == false)
+            std::cout << "Dat initialisation failed. Error message: " << operation.msg << "\nTo try again enter path to .dat file\n";
     }
 
     std::cout << "Great! File initialised successfully!\n";
-    if (file.CheckIfNotPatched())
-        std::cout << "MESSAGE: Dat file is new and haven't been patched yet\n";
-
-    if (file.CheckIfPatchedByOldLauncher())
-        std::cout << "MESSAGE: Dat file was patched by old launcher. Capability isn't guaranteed! Some functions may not work properly!!!\n";
-
-    if (file.CheckIfUpdatedByGame())
-        std::cout << "MESSAGE: .dat file was updated by game! Need to repair patches with functions RepairPatches() and FinishRepairingPatches()\n";
-
-    std::cout << "Files number: " << file.files_number() << std::endl;
-
+    std::cout << "Gathering file information...";
+    file.GatherInformation("dat_info.log");
+    
     int cmd = 0;
     while (true) {
         std::cout << "Please, choose, what should I do. I can extract .dat file to files (press 1), "
@@ -107,13 +95,13 @@ int main() {
             memcpy(out_time, ttime, 24);
             out_time[24] = '\0';
 
-            std::string output_dir = std::string("Extracted data\\") + file.filename().substr(file.filename().length() - 16, 16) + " " + std::string(out_time) + "\\";
+            std::string filename = file.getIO().GetFilename().value;
+            
+            std::string output_dir = std::string("Extracted data\\") + filename.substr(filename.length() - 16, 16) + " " + std::string(out_time) + "\\";
             std::replace(output_dir.begin(), output_dir.end(), ':', '-');
 
             mkdir(output_dir.c_str(), 744);
             
-            std::cout << "Total files found: " << file.files_number() << std::endl << std::flush;
-            file.WriteUnorderedDictionary(output_dir);
             std::cout << "Beginning unpacking... Please, wait for some minutes."
                     "\nMaybe it's a good idea to have a cup of tea, while unpacker is working...\n" << std::flush;
 
@@ -121,63 +109,63 @@ int main() {
 
             if (exportImagesToDb) {
                 output_db.InitDatabase(output_dir + std::string("Images.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(JPG, &output_db) << " .jpg files to Images.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(JPG, &output_db).value << " .jpg files to Images.db" << std::endl << std::flush;
                 output_db.CloseDatabase();
             }
 
             if (exportSoundsToDb) {
                 output_db.InitDatabase(output_dir + std::string("Sounds.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(WAV, &output_db) << " .wav files to Sounds.db" << std::endl << std::flush;
-                std::cout << "Extracted " << file.ExtractAllFilesByType(OGG, &output_db) << " .ogg files to Sounds.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(WAV, &output_db).value << " .wav files to Sounds.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(OGG, &output_db).value << " .ogg files to Sounds.db" << std::endl << std::flush;
                 output_db.CloseDatabase();
             }
 
             if (exportTextsToDb) {
                 output_db.InitDatabase(output_dir + std::string("Texts.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(TEXT, &output_db) << " text files to Texts.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(TEXT, &output_db).value << " text files to Texts.db" << std::endl << std::flush;
                 output_db.CloseDatabase();
             }
 
             if (exportFontsToDb) {
                 output_db.InitDatabase(output_dir + std::string("Fonts.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(FONT, &output_db) << " font files to Fonts.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(FONT, &output_db).value << " font files to Fonts.db" << std::endl << std::flush;
                 output_db.CloseDatabase();
             }
 
             if (exportTexturesToDb) {
                 output_db.InitDatabase(output_dir + std::string("Textures.db"));
-                std::cout << "Extracted " << file.ExtractAllFilesByType(DDS, &output_db) << " .dds files to Textures.db" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(DDS, &output_db).value << " .dds files to Textures.db" << std::endl << std::flush;
                 output_db.CloseDatabase();
             }
 
             if (exportImagesToFiles) {
                 mkdir((output_dir + "jpg").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(JPG, output_dir + "jpg\\").value << " .jpg files to directory" << std::endl << std::flush;
             }
 
             if (exportTexturesToFiles) {
                 mkdir((output_dir + "dds").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(DDS, output_dir + "dds\\").value << " .dds files to directory" << std::endl << std::flush;
             }
 
             if (exportSoundsToFiles) {
                 mkdir((output_dir + "wav").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(WAV, output_dir + "wav\\").value << " .wav files to directory" << std::endl << std::flush;
                 mkdir((output_dir + "ogg").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(OGG, output_dir + "ogg\\").value << " .ogg files to directory" << std::endl << std::flush;
             }
 
             if (exportFontsToFiles) {
                 mkdir((output_dir + "fonts").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(FONT, output_dir + "fonts\\").value << " font files to directory" << std::endl << std::flush;
             }
 
             if (exportUnknownToFiles) {
                 mkdir((output_dir + "unknown").c_str(), 744);
-                std::cout << "Extracted " << file.ExtractAllFilesByType(UNKNOWN, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
+                std::cout << "Extracted " << file.getExporter().ExtractAllFilesByType(UNKNOWN, output_dir + "unknown\\").value << " unknown files to directory" << std::endl << std::flush;
             }
 
-            file.CloseDatFile();
+            file.Deinitialize();
 
             fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
                     float(clock() - begin_time) / CLOCKS_PER_SEC);
@@ -185,10 +173,9 @@ int main() {
 
         if (cmd == 2) {
             std::cout << "Closing file...\n";
-            if (!file.CloseDatFile())
-                std::cout << "An error occured while closing the file!!!\n";
+            file.Deinitialize();
 
-            while (file.DatFileState() == CLOSED) {
+            while (!file.Initialized()) {
                 std::cout << "Please, tell, where the .dat file is\n";
                 std::cout << "Enter path to file (including filename): ";
                 std::string filename;
@@ -196,10 +183,12 @@ int main() {
 
                 std::cout << "Opening file " << filename << std::endl;
 
-                if (file.InitDatFile(filename, 0) == false) {
+                auto operation = file.Initialise(filename, 0);
+                if (operation.result == false) {
                     std::cout << "Some error caused while opening the file... "
                             "Could you enter .dat filename once more?" << std::endl;
-                    file.CloseDatFile();
+                    std::cout << "Error message: " << operation.msg << std::endl;
+                    file.Deinitialize();
                 }
             }
         }
@@ -275,7 +264,7 @@ int main() {
             }
         }
     }
-    file.CloseDatFile();
+    file.Deinitialize();
     system("pause");
     return 0;
 }