|
@@ -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);
|