Ver Fonte

Minor fixes in FileSystem module. Improved and documented IO module

Ivan Arkhipov há 6 anos atrás
pai
commit
258908170d

+ 9 - 0
include/DatSubsystems/DatFileSystem.h

@@ -22,6 +22,15 @@ namespace LOTRO_DAT {
     class BinaryData;
     class SubDirectory;
 
+
+    /*!
+     * \brief Модуль файловой системы
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Класс для работы с внутренними файлами в dat-контейнере. Позволяет найти и извлечь данные необходимого файла
+     * или изменить информацию о нём
+     */
+
     class DatFileSystem {
 
     public:

+ 15 - 9
src/DatSubsystems/DatFileSystem.cpp

@@ -1,7 +1,3 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
 #include <DatSubsystems/DatFileSystem.h>
 #include <EasyLogging++/easylogging++.h>
 #include <BinaryData.h>
@@ -10,6 +6,16 @@
 #include <SubDirectory.h>
 
 namespace LOTRO_DAT {
+
+
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Конструктор объекта модуля. Вызывается только из класса DatFile. Создаёт указатель но объект DatFile, но
+     * не инициализирует модуль. Инизиализация происходит в функции Init
+     * \param[in] datFilePtr Указатель на объект управляющего класса DatFile
+     */
+
     DatFileSystem::DatFileSystem(DatFile *datFilePtr) : dat(datFilePtr) {
         LOG(INFO) << "Initialization of empty DatFileSystem";
     }
@@ -190,7 +196,7 @@ namespace LOTRO_DAT {
     /*!
      * \author Gi1dor
      * \date 29.06.2018
-     * Подготавливает файловую систему для работы 
+     * Инициализация модуля. Подготавливает файловую систему для работы
      */
 
     DatOperationResult<> DatFileSystem::Init() {
@@ -398,6 +404,7 @@ namespace LOTRO_DAT {
     DatOperationResult<> DatFileSystem::InitSubDirectory(SubDirectory dir) {
         if (!dat)
             return DatOperationResult<>(ERROR, "DATFSINITSUBDIR: no connection with Dat (dat is nullptr)");
+
         BinaryData subdir_data(63 * 8 + 4 + 32 * 64);
         auto operation = dat->getIO().ReadData(subdir_data, 63 * 8 + 4 + 32 * 64, dir.offset());
         if (operation.result == ERROR)
@@ -409,10 +416,9 @@ namespace LOTRO_DAT {
 
         // Subfiles section
         long long subfiles_number = subdir_data.ToNumber<4>(63 * 8);
-        if (subfiles_number >= 64)
+        if (subfiles_number > 64)
             return DatOperationResult<>(ERROR, "DATINITSUBDIR: incorrect subdir: files number > 64");
 
-
         // Subdirs section
         for (unsigned i = 8; i < 63 * 8; i += 8) {
             if (subdir_data.ToNumber<4>(i) == 0 || subdir_data.ToNumber<4>(i + 4) == 0)
@@ -431,7 +437,7 @@ namespace LOTRO_DAT {
             subdir_init_queue_.insert(SubDirectory(unknown, offset));
         }
 
-        // Subfiles' section
+        // Subfiles section
 
         for (int i = 0; i < subfiles_number; i++) {
             long long header_start = 63 * 8 + 4 + 32 * i;
@@ -452,7 +458,7 @@ namespace LOTRO_DAT {
             if (file.version() == 0 || file.unknown2() != 0)
                 continue;
 
-            if (visited_subfiles_ids_.count(file.file_id()))
+            if (visited_subfiles_ids_.count(file.file_id()) || file.file_id() == -1)
                 break;
 
             visited_subfiles_ids_.insert(file.file_id());

+ 128 - 42
src/DatSubsystems/DatIO.cpp

@@ -1,7 +1,3 @@
-//
-// Created by kikab on 04.06.2018.
-//
-
 #include "BinaryData.h"
 #include "DatFile.h"
 #include "DatSubsystems/DatIO.h"
@@ -15,7 +11,6 @@
 #include <DatOperationResult.h>
 #include <DatSubsystems/DatIO.h>
 
-
 #ifdef WIN32
 #define fseek _fseeki64
 #define ftell _ftelli64
@@ -25,6 +20,14 @@ extern "C++"
 {
 namespace LOTRO_DAT {
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Конструктор объекта модуля. Вызывается только из класса DatFile. Создаёт указатель но объект DatFile, но
+     * не инициализирует модуль. Инизиализация происходит в функции Init
+     * \param[in] datFile Указатель на объект управляющего класса DatFile
+     */
+
     DatIO::DatIO(DatFile *datFile) : dat(datFile), file_handler_(nullptr), filename_(),
                                              actual_dat_size_(0) {
     }
@@ -34,6 +37,17 @@ namespace LOTRO_DAT {
     // INIT SECTION
     //------------------------------------------------//
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Инициализация модуля. Открывает файл на чтение и блокирует его для доступа из других программ.
+     * Читает заголовочную информацию, необходимую для инициализации остальных модулей. Не должна вызываться где-либо,
+     * кроме как из управляющего объекта DatFile.
+     * \param[in] filename имя файла для открытия (включая путь)
+     * \return Возвращает result = ERROR в случае, если не удалось открыть файл или файл некорректный
+     */
+
+
     DatOperationResult<> DatIO::Init(const std::string &filename) {
         LOG(INFO) << "Initializing IO: " << filename;
 
@@ -57,6 +71,13 @@ namespace LOTRO_DAT {
         return DatOperationResult<>(SUCCESS, "DatIO initialized successfully");
     }
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Открытие файла, имя которого записано в переменной file_handler_
+     * \return Возвращает result = ERROR в случае, если не удалось открыть файл
+     */
+
     DatOperationResult<> DatIO::OpenDatFile() {
         LOG(DEBUG) << "DatIO: Started opening DatFile";
 
@@ -75,6 +96,30 @@ namespace LOTRO_DAT {
         return DatOperationResult<>(SUCCESS, std::string("Successfully opened file " + filename_));
     }
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Инициализация основных переменных файла, располагающихся в начале.
+     *
+     * Известные переменные (каждая по 4 байта):
+     *
+     * Офсет - описание переменной
+     * =========
+     * 0x100 - константа, одинаковая для всех .dat файлов
+     * 0x140 - ещё одна константа, одинаковая для всех .dat файлов
+     * 0x14C - Первая переменная версии .dat файла
+     * 0x148 - размер .dat файла. Указывает на начало свободного места. Необязательно должен являться физическим концом
+     * 0x150 - Вторая переменная версии dat файла
+     * 0x154 - Положение журнала фрагментации (который представляет собой список свободных блоков в dat-файле, куда можно писать новые данные
+     * 0x158 - Позиция окончания журнала фрагментации (?)
+     * 0x15C - Кол-во записей в журнале фрагментации (?)
+     * 0x160 - Офсет корневой папки
+     * 0x19C - Свободное место в dat файле (?)
+     *
+     * \return Возвращает result = ERROR в случае, если константы не совпадают с требуемыми значениями
+     */
+
+
     DatOperationResult<> DatIO::ReadSuperBlock() {
         LOG(INFO) << "DatIO: Started reading superblock";
 
@@ -92,19 +137,14 @@ namespace LOTRO_DAT {
         root_directory_offset = data.ToNumber<4>(0x160);
         free_dat_size = data.ToNumber<4>(0x19C);
 
-        if (constant1 != 0x4C5000) {
-            LOG(ERROR) << "Variable at position 0x100 is not equal to .dat file constant!";
+        if (constant1 != 0x4C5000)
             return DatOperationResult<>(ERROR, std::string("Variable at position 0x100 is not equal to .dat file constant!"));
-        }
-        if (constant2 != 0x5442) {
-            LOG(ERROR) << "Variable at position 0x140 is not equal to .dat file constant!";
+
+        if (constant2 != 0x5442)
             return DatOperationResult<>(ERROR, std::string("Variable at position 0x140 is not equal to .dat file constant!"));
-        }
 
-        if (file_size != actual_dat_size_) {
+        if (file_size != actual_dat_size_)
             LOG(INFO) << "Variable at 0x148 position is not equal to .dat file size!";
-            //return CORRUPTED_FILE_WARNING;
-        }
 
         LOG(INFO) << "DatIO: Superblock read successfully";
         return DatOperationResult<>(SUCCESS, std::string("Superblock read successfully."));
@@ -115,55 +155,69 @@ namespace LOTRO_DAT {
     // PUBLIC READ/WRITE SECTION
     //------------------------------------------------//
 
+
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Чтение бинарных данных из файла. Считает size байт dat файла, начиная с положения offset, и запишет их в
+     * объект data, причём положение первого байта считанных данных будет равно значению data_offset
+     *
+     * \param[in, out] data Объект класса BinaryData, в который будут считаны данные
+     * \param[in] size Количество байт, которые будут считаны
+     * \param[in] offset Положение начала данных в dat файле, откуда считать
+     * \param[in] data_offset Положение записи. Считанные данные будут записаны с отступом data_offset в data
+     *
+     * \return Возвращает result = ERROR в случае, если считать не удалось (неверные входные данные)
+     */
+
     DatOperationResult<>
     DatIO::ReadData(BinaryData &data, long long size, long long offset, long long data_offset) const {
-        if (file_handler_ == nullptr) {
-            LOG(ERROR) << "IOError: file handler is null pointer on reading data.";
-            data = BinaryData(0);
-            return DatOperationResult<>(ERROR, "IOError: file handler is null pointer on reading data.");
-        }
+        if (file_handler_ == nullptr)
+            return DatOperationResult<>(ERROR, "IOREADDATA: file handler is null pointer on reading data.");
 
-        if (data_offset + size > data.size()) {
-            LOG(ERROR) << "Trying to read more than BinaryData size: Reading " << size << " bytes from " << offset
-                       << " position.";
-            data = BinaryData(0);
-            return DatOperationResult<>(ERROR, "IOError: Parameters: offset, size are out of range.");
-        }
+        if (data_offset + size > data.size())
+            return DatOperationResult<>(ERROR, "IOREADDATA: Parameters: offset, size are out of range.");
 
-        if (offset + size > actual_dat_size_) {
-            LOG(ERROR) << "Trying to read more than DatFile size elapsed: Reading " << size << " bytes from " << offset
-                       << " position.";
-            data = BinaryData(0);
-            return DatOperationResult<>(ERROR, "IOError: Reading from end of file.");
-        }
+        if (offset + size > actual_dat_size_)
+            return DatOperationResult<>(ERROR, "IOREADDATA: Reading more than DatFile size elapsed.");
 
         if (offset != ftell(file_handler_))
             fseek(file_handler_, offset, SEEK_SET);
+
         fread(data.data() + data_offset, unsigned(size), 1, file_handler_);
         return DatOperationResult<>(SUCCESS, "Read data successful.");
     }
 
+
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Запись бинарных данных в dat файл. Запишет size байт данных из data, начиная с позиции data_offset,
+     * в позицию offset .dat файла.
+     *
+     * \param[in] data Объект класса BinaryData, откуда будут взяты данные для записи
+     * \param[in] size Количество байт для записи
+     * \param[in] offset Положение начала данных в dat файле, куда записывать
+     * \param[in] data_offset Положение начала данных в data, от которого будет взято size байт и записано в dat файл
+     *
+     * \return Возвращает result = ERROR в случае, если записать не удалось (неверные входные данные)
+     */
+
     DatOperationResult<>
     DatIO::WriteData(const BinaryData &data, long long size, long long offset, long long data_offset) {
-        if (file_handler_ == nullptr) {
-            LOG(ERROR) << "IOError: file handler is null pointer on writing data";
-            return DatOperationResult<>(ERROR,
-                                      "IOError: file handler is null pointer on writing data.");
-        }
+        if (file_handler_ == nullptr)
+            return DatOperationResult<>(ERROR, "IOWRITEDATA: file handler is null pointer on writing data.");
 
         if (offset != ftell(file_handler_))
             fseek(file_handler_, offset, SEEK_SET);
 
-        if (data_offset + size > data.size()) {
-            LOG(ERROR) << "Trying to write more than BinaryData size";
-            return DatOperationResult<>(ERROR, "IOError: writing more than BinaryData size.");
-        }
+        if (data_offset + size > data.size())
+            return DatOperationResult<>(ERROR, "IOWRITEDATA: writing more than BinaryData size.");
 
         fwrite(data.data() + data_offset, unsigned(size), 1, file_handler_);
 
-        if (offset + size > actual_dat_size_) {
+        if (offset + size > actual_dat_size_)
             actual_dat_size_ = offset + size;
-        }
 
         return DatOperationResult<>(SUCCESS, "Data writing successful.");
     }
@@ -173,6 +227,12 @@ namespace LOTRO_DAT {
     // DEINIT SECTION
     //------------------------------------------------//
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Деинициализация модуля. Не должна вызываться где-либо, кроме как из управляющего объекта DatFile.
+     */
+
     DatOperationResult<> DatIO::DeInit() {
         if (file_handler_ != nullptr) {
             fclose(file_handler_);
@@ -238,16 +298,42 @@ namespace LOTRO_DAT {
         return DatOperationResult<>(SUCCESS, "File header patched successfully");;
     }
 
+
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Возвращает размер dat файла в байтах (может отличаться от значения внутренней переменной file_size dat файла
+     */
+
     DatOperationResult<long long> DatIO::GetActualDatSize() {
         return DatOperationResult<long long>(actual_dat_size_, SUCCESS);
     }
 
+
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Возвращает имя dat файла, которое было передано при инициализации
+     */
+
     DatOperationResult<std::string> DatIO::GetFilename() {
         return DatOperationResult<std::string>(filename_, SUCCESS);
     }
 
+    /*!
+     * \author Gi1dor
+     * \date 30.06.2018
+     * Выводит информацию о состоянии модуля в файл
+     * \param[in] file указатель на объект файла, в конец которого будет напечатана информация
+     * \warning Файл file должен быть открыт для записи
+     */
+
     void DatIO::PrintInformaion(FILE *file) {
+        if (!file)
+            return;
+
         fprintf(file, "========== IO info ==========\n");
+        fprintf(file, "Filename = %s\n", filename_.c_str());
         fprintf(file, "File header data:\n");
         fprintf(file, "constant1 = %lld\n", constant1);
         fprintf(file, "constant2 = %lld\n", constant2);

+ 42 - 0
src/Examples/info_gatherer.cpp

@@ -2,3 +2,45 @@
 // Created by kikab on 10.06.2018.
 //
 
+#include <LotroDat.h>
+using namespace LOTRO_DAT;
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <ctime>
+
+int main() {
+    std::cout << "Gi1dor's LotRO .dat patcher ver. 6.0.0" << std::endl;
+    freopen("patcher_errors.log", "w", stderr);
+
+    setbuf(stdout, nullptr);
+    setbuf(stderr, nullptr);
+
+    setvbuf (stdout, nullptr, _IONBF, BUFSIZ);
+    setvbuf (stderr, nullptr, _IONBF, BUFSIZ);
+
+    DatFile file;
+    std::ifstream in("dat_file_path.txt");
+
+    if (in.fail())
+        return 0;
+
+    std::string filename;
+    std::getline(in, filename);
+    std::cout << "Opening file " << filename << std::endl;
+    auto operation = file.Initialise(filename);
+    if (operation.result != SUCCESS) {
+        std::cout << "Unable to initialize file. DatFile message: " << operation.msg;
+        system("pause");
+        return 0;
+    }
+
+    operation = file.GatherInformation("info.txt");
+    if (operation.result != SUCCESS)
+        std::cout << "Gather information wasn't successfully completed. DatFile message: " << operation.msg;
+    else
+        std::cout << "DatFile information gathered successfully!";
+    system("pause");
+    return 0;
+}