Jelajahi Sumber

Added new log messages for most important functions

Ivan Arkhipov 6 tahun lalu
induk
melakukan
a3b3ef7137
10 mengubah file dengan 170 tambahan dan 80 penghapusan
  1. TEMPAT SAMPAH
      bin/LotRO_dat_extractor.exe
  2. TEMPAT SAMPAH
      bin/LotRO_dat_patcher.exe
  3. 1 1
      include/DatException.h
  4. TEMPAT SAMPAH
      lib/libLotroDat.dll.a
  5. TEMPAT SAMPAH
      lib/libLotroDat_static.a
  6. 68 16
      src/DatFile.cpp
  7. 45 26
      src/Database.cpp
  8. 5 12
      src/Examples/extractor_example.cpp
  9. 15 10
      src/SubDirectory.cpp
  10. 36 15
      src/Subfiles/TextSubfile.cpp

TEMPAT SAMPAH
bin/LotRO_dat_extractor.exe


TEMPAT SAMPAH
bin/LotRO_dat_patcher.exe


+ 1 - 1
include/DatException.h

@@ -4,7 +4,7 @@
 #ifndef LOTRO_DAT_PATCHER_DATEXCEPTION_H
 #define LOTRO_DAT_PATCHER_DATEXCEPTION_H
 
-#define DAT_DEBUG
+//#define DAT_DEBUG
 
 #include <string>
 #include <iostream>

TEMPAT SAMPAH
lib/libLotroDat.dll.a


TEMPAT SAMPAH
lib/libLotroDat_static.a


+ 68 - 16
src/DatFile.cpp

@@ -36,14 +36,19 @@ namespace LOTRO_DAT {
         defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
         defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
         defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
-        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "20971520"); // 20MB
+        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB
         defaultConf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1"); // Flush after every one log
-        el::Loggers::reconfigureAllLoggers(defaultConf);
 
+        defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "true");
+        defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "dat_library_debug.log");
+
+        el::Loggers::reconfigureAllLoggers(defaultConf);
+        LOG(INFO) << "==================================================================";
         LOG(INFO) << "Starting new DatFile class instance";
     }
 
     DAT_RESULT DatFile::InitDatFile(const std::string &filename, int dat_id) {
+        LOG(INFO) << "Started initialisation of DatFile " << filename;
         if (dat_state_ != CLOSED && filename == filename_) {
             LOG(DEBUG) << "Trying to reopen the same file: " << filename << ". Doing nothing.";
             return SUCCESS;
@@ -124,6 +129,7 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened
 
     DAT_RESULT DatFile::ExtractFile(long long file_id, const std::string &path) {
+        LOG(DEBUG) << "Extracting file " << file_id << " to path " << path;
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
             return INCORRECT_STATE_ERROR;
@@ -146,6 +152,7 @@ namespace LOTRO_DAT {
             LOG(ERROR) << "Cannot write to file.";
             return WRITE_TO_FILE_ERROR;
         }
+        LOG(DEBUG) << "File " << file_id << " extracted successfully";
         return SUCCESS;
     }
 
@@ -157,6 +164,8 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened
 
     DAT_RESULT DatFile::ExtractFile(long long file_id, Database *db) {
+        LOG(DEBUG) << "Extracting file " << file_id << " to database.";
+
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
             return INCORRECT_STATE_ERROR;
@@ -192,6 +201,7 @@ namespace LOTRO_DAT {
             LOG(ERROR) << "Caught " << e.what() << " exception.";
             return FAILED;
         }
+        LOG(DEBUG) << "File " << file_id << " extracted successfully";
         return SUCCESS;
     }
 
@@ -203,6 +213,7 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened
 
     int DatFile::ExtractAllFilesByType(FILE_TYPE type, std::string path) {
+        LOG(INFO) << "Extracting all files to path " << path;
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
             return INCORRECT_STATE_ERROR;
@@ -215,6 +226,7 @@ namespace LOTRO_DAT {
                 success += (ExtractFile(i.second->file_id(), (path + std::to_string(i.second->file_id()))) == SUCCESS ? 1 : 0);
             }
         }
+        LOG(INFO) << "Successfully extracted " << success << " files";
         return success;
     }
 
@@ -224,6 +236,8 @@ namespace LOTRO_DAT {
     /// Throws DatException() if undefined behaviour happened
 
     int DatFile::ExtractAllFilesByType(FILE_TYPE type, Database *db) {
+        LOG(INFO) << "Extracting all files to database...";
+
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot perform extraction.";
             return INCORRECT_STATE_ERROR;
@@ -236,11 +250,13 @@ namespace LOTRO_DAT {
                 success += (ExtractFile(i.second->file_id(), db) == SUCCESS ? 1 : 0);
             }
         }
+        LOG(INFO) << "Extracted " << success << " files";
         return success;
     }
 
     // TODO: Write description and make asserts
     DAT_RESULT DatFile::PatchFile(const char *filename, YAML::Node options) {
+        LOG(DEBUG) << "Patching file with filename" << filename << " and id = " << options["fid"].as<long long>();
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
             return INCORRECT_STATE_ERROR;
@@ -270,11 +286,13 @@ namespace LOTRO_DAT {
             LOG(ERROR) << "Caught " << e.what() <<" exception.";
             return FAILED;
         }
+        LOG(DEBUG) << "Successfully patched file with filename = " << filename << " and id = " << options["fid"].as<long long>();
         return SUCCESS;
     }
 
     // TODO: Write description and make asserts
     DAT_RESULT DatFile::PatchFile(const SubfileData &data, bool rewrite_original) {
+        LOG(DEBUG) << "Patching file with id = " << data.options["fid"].as<long long>() << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
             return INCORRECT_STATE_ERROR;
@@ -315,11 +333,13 @@ namespace LOTRO_DAT {
             LOG(ERROR) << "Caught " << e.what() << " exception";
             return FAILED;
         }
+        LOG(DEBUG) << "Patched successfully file " << data.options["fid"].as<long long>() << (rewrite_original ? " REWRITING ORIGINAL FILE." : ".");
         return SUCCESS;
     }
 
     // TODO: Write description
     DAT_RESULT DatFile::PatchAllDatabase(Database *db) {
+        LOG(INFO) << "Patching all database";
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot patch.";
             return INCORRECT_STATE_ERROR;
@@ -337,7 +357,7 @@ namespace LOTRO_DAT {
         DAT_RESULT result = CommitChanges();
         if (result != SUCCESS)
             return result;
-
+        LOG(INFO) << "Successfully patched whole database";
         return SUCCESS;
     }
 
@@ -346,6 +366,7 @@ namespace LOTRO_DAT {
     /// Gets std::string path - path to directory, where the file will be written with name "dict.txt"
 
     DAT_RESULT DatFile::WriteUnorderedDictionary(std::string path) const {
+        LOG(INFO) << "Writing unordered dictionary to " << path << "dict.txt";
         FILE *f = nullptr;
         fopen_s(&f, (path + "dict.txt").c_str(), "w");
 
@@ -360,6 +381,7 @@ namespace LOTRO_DAT {
                     i.second->block_size(), i.second->Extension().c_str());
         }
         fclose(f);
+        LOG(INFO) << "Unordered dictionary was written successfully to " << path << "dict.txt";
         return SUCCESS;
     }
 
@@ -374,6 +396,7 @@ namespace LOTRO_DAT {
     /// Returns BinaryData, which contains of subfile data, made from parts of file in DatFile
     // TODO: ASSERTS
     BinaryData DatFile::GetFileData(const Subfile *file, long long int offset) {
+        LOG(DEBUG) << "Getting file " << file->file_id() << " data";
         BinaryData mfile_id(20);
         ReadData(mfile_id, 20, file->file_offset() + 8);
         if (!mfile_id.CheckCompression() && file->file_id() != mfile_id.ToNumber<4>(0))
@@ -404,7 +427,7 @@ namespace LOTRO_DAT {
             ReadData(data, std::min(fragment_size, file->file_size() - current_block_size), fragment_offset, current_block_size );
             current_block_size += fragment_size;
         }
-
+        LOG(DEBUG) << "Successfully got file " << file->file_id() << " data";
         return data;
     }
 
@@ -412,6 +435,7 @@ namespace LOTRO_DAT {
     /// Shouldn't be used by any external classes except Subfile and Subdirectory.
 
     DAT_RESULT DatFile::OpenDatFile(const char *dat_name) {
+        LOG(DEBUG) << "Started opening DatFile";
         if (dat_state_ != CLOSED) {
             CloseDatFile();
         }
@@ -428,10 +452,12 @@ namespace LOTRO_DAT {
         fseek(file_handler_, 0, SEEK_SET);
 
         dat_state_ = SUCCESS_OPENED;
+        LOG(DEBUG) << "Successfully opened DatFile";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::ReadSuperBlock() {
+        LOG(DEBUG) << "Started reading superblock";
         if (dat_state_ != SUCCESS_OPENED) {
             LOG(ERROR) << "Dat state isn't SUCCESS_OPENED. Cannot perform extraction.";
             return INCORRECT_STATE_ERROR;
@@ -463,10 +489,12 @@ namespace LOTRO_DAT {
         }
 
         dat_state_ = SUCCESS_SUPERBLOCK;
+        LOG(DEBUG) << "Superblock read successfully";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::MakeDirectories() {
+        LOG(DEBUG) << "Started making directories";
         if (dat_state_ != SUCCESS_SUPERBLOCK) {
             LOG(ERROR) << "Dat state isn't SUCCESS_SUPERBLOCK. Cannot make directories.";
             return INCORRECT_STATE_ERROR;
@@ -474,10 +502,12 @@ namespace LOTRO_DAT {
 
         root_directory_ = new SubDirectory((unsigned) root_directory_offset_, this);
         dat_state_ = SUCCESS_DIRECTORIES;
+        LOG(DEBUG) << "Directories made successfully";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::MakeDictionary() {
+        LOG(DEBUG) << "Started making dictionary";
         if (dat_state_ != SUCCESS_DIRECTORIES) {
             LOG(ERROR) << "Dat state isn't SUCCESS_DIRECTORIES. Cannot make directories.";
             return INCORRECT_STATE_ERROR;
@@ -490,6 +520,7 @@ namespace LOTRO_DAT {
 
         root_directory_->MakeDictionary(dictionary_);
         dat_state_ = SUCCESS_DICTIONARY;
+        LOG(DEBUG) << "Dictionary made successfull";
         return SUCCESS;
     }
 
@@ -531,6 +562,7 @@ namespace LOTRO_DAT {
     /// Special functions used by patch process.
     /// Shouldn't be used by any external class.
     DAT_RESULT DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original) {
+        LOG(DEBUG) << "Applying " << file->file_id() << " patch.";
         auto file_id = file->file_id();
         if (patched_list.count(file_id) != 0) {
             LOG(WARNING) << "Warning: DatFile::ApplyFilePatch - found 2 files in patch with the same file_id = "
@@ -609,24 +641,30 @@ namespace LOTRO_DAT {
             patch_dict_[file_id]->category = file->category;
 
         UpdateFragmentationJournal(journal);
+        LOG(DEBUG) << "Successfully applied file " << file->file_id() << " patch.";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::UpdateSubdirectories() {
         // TODO: asserts
+        LOG(DEBUG) << "Started updating subdirectories";
         root_directory_->UpdateDirectories(patched_list, dictionary_);
+        LOG(DEBUG) << "Finished updating subdirectories";
         return SUCCESS;
     }
 
     std::vector<std::pair<long long, long long> > DatFile::GetFragmentationJournal() {
+        LOG(DEBUG) << "Getting fragmentation journal";
         BinaryData data(8);
         ReadData(data, 8, fragmentation_journal_offset_ + 8);
         std::vector<std::pair<long long, long long> > result;
         result.emplace_back(std::make_pair(data.ToNumber<4>(0), data.ToNumber<4>(4)));
+        LOG(DEBUG) << "Finished getting fragmentation journal";
         return result;
     }
 
     DAT_RESULT DatFile::UpdateHeader() {
+        LOG(DEBUG) << "Updating header";
         WriteData(BinaryData::FromNumber<4>(constant1_), 4, 0x100);
         WriteData(BinaryData::FromNumber<4>(constant2_), 4, 0x140);
         WriteData(BinaryData::FromNumber<4>(file_size_), 4, 0x148);
@@ -634,10 +672,12 @@ namespace LOTRO_DAT {
         WriteData(BinaryData::FromNumber<4>(version2_), 4, 0x150);
         WriteData(BinaryData::FromNumber<4>(fragmentation_journal_offset_), 4, 0x154);
         WriteData(BinaryData::FromNumber<4>(root_directory_offset_), 4, 0x160);
+        LOG(DEBUG) << "Finished updating header";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::UpdateFragmentationJournal(const std::vector<std::pair<long long, long long> > &journal) {
+        LOG(DEBUG) << "Updating fragmentation journal";
         for (unsigned i = 0; i < journal.size(); i++) {
             long long size = journal[i].first;
             long long offset = journal[i].second;
@@ -645,36 +685,35 @@ namespace LOTRO_DAT {
             WriteData(BinaryData::FromNumber<4>(size), 4, fragmentation_journal_offset_ + 8 * (i + 1));
             WriteData(BinaryData::FromNumber<4>(offset), 4, fragmentation_journal_offset_ + 8 * (i + 1) + 4);
         }
+        LOG(DEBUG) << "Finished updating fragmentation journal";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::CommitChanges() {
+        LOG(INFO) << "Started commiting changes";
         if (dat_state_ != UPDATED) {
             LOG(DEBUG) << "Commiting changes to file with state != UPDATED. Nothing to do";
             return SUCCESS;
         }
 
-        LOG(DEBUG) << "There are some updated files. Rewriting dictionary...";
-        LOG(DEBUG) << "Updating locales...";
+        LOG(INFO) << "There are some updated files. Rewriting dictionary...";
         CommitLocales();
 
         auto journal = GetFragmentationJournal();
         UpdateFragmentationJournal(journal);
-        LOG(DEBUG) << "Updated fragmentation journal...";
 
         UpdateHeader();
-        LOG(DEBUG) << "Updated header...";
         UpdateSubdirectories();
-        LOG(DEBUG) << "Updated subdirectories...";
-        LOG(DEBUG) << "Changed " << patched_list.size() << " files...";
+        LOG(INFO) << "Changed " << patched_list.size() << " files...";
 
         patched_list.clear();
         dat_state_ = READY;
-        LOG(DEBUG) << "Done Commiting changes!";
+        LOG(INFO) << "Done Commiting changes!";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::CloseDatFile() {
+        LOG(INFO) << "Closing DatFile";
         if (dat_state_ == CLOSED) {
             LOG(INFO) << "DatFile is already closed. Nothing to do";
             return SUCCESS;
@@ -699,14 +738,14 @@ namespace LOTRO_DAT {
         dictionary_.clear();
 
         dat_state_ = CLOSED;
-
+        LOG(INFO) << "File closed successfully.";
         return SUCCESS;
     }
 
     // LOCALE MANAGING SECTION
 
     DAT_RESULT DatFile::InitLocales() {
-        LOG(DEBUG) << "Initialising locales...";
+        LOG(INFO) << "Initialising locales...";
         BinaryData dicts_data;
 
         if (dictionary_.count(2013266257) != 0)
@@ -791,6 +830,7 @@ namespace LOTRO_DAT {
             inactive_cat_s += std::to_string(i) + " ";
         }
         LOG(INFO) << "Unactive patches now: " << inactive_cat_s;
+        LOG(INFO) << "Finished initialising locales";
         return SUCCESS;
     }
 
@@ -807,6 +847,7 @@ namespace LOTRO_DAT {
     }
 
     DAT_RESULT DatFile::SetLocale(LOCALE locale) {
+        LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
         if (dat_state_ < READY) {
             LOG(ERROR) << "Dat state isn't READY. Cannot set locale.";
             return INCORRECT_STATE_ERROR;
@@ -844,10 +885,12 @@ namespace LOTRO_DAT {
 
         current_locale_ = locale;
         CommitChanges();
+        LOG(INFO) << "Locale set successfull";
         return SUCCESS;
     }
 
     bool DatFile::CheckIfUpdatedByGame() {
+        LOG(INFO) << "Checking if DatFile was updated by LotRO";
         if (!pending_patch_.empty())
             return true;
         if (current_locale_ == ORIGINAL)
@@ -872,11 +915,13 @@ namespace LOTRO_DAT {
             }
         }
         CommitChanges();
+        LOG(INFO) << "Dat file " << (updated ? "WAS " : "WASN'T ") << "updated by game.";
         return updated;
     }
 
     DAT_RESULT DatFile::RepairPatches(Database *db) {
         // TODO: Find errors
+        LOG(INFO) << "Repairing patches";
         SubfileData data;
         data = db->GetNextFile();
         while (!data.Empty()) {
@@ -886,10 +931,12 @@ namespace LOTRO_DAT {
             data = db->GetNextFile();
         }
         CommitChanges();
+        LOG(INFO) << "Successfully repaired with database";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::FinishRepairingPatches() {
+        LOG(INFO) << "Finishing repairing patches";
         pending_patch_.clear();
         return SUCCESS;
     }
@@ -907,7 +954,7 @@ namespace LOTRO_DAT {
     }
 
     DAT_RESULT DatFile::CommitLocales() {
-        std::cout << "Committing locales..." << std::endl;
+        LOG(INFO) << "Committing locales...";
         SubfileData data = dictionary_[2013266257]->PrepareForExport(GetFileData(dictionary_[2013266257]));
         data.options["fid"] = "2013266257";
         data.options["ext"] = ".unknown";
@@ -970,11 +1017,12 @@ namespace LOTRO_DAT {
         if (result != SUCCESS)
             return result;
 
+        LOG(INFO) << "Locales commited successfully";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::EnableCategory(int category) {
-        LOG(DEBUG) << "Enabling category " << category;
+        LOG(INFO) << "Enabling category " << category;
         if (inactive_categories.count(category) == 0)
             return SUCCESS;
 
@@ -992,11 +1040,12 @@ namespace LOTRO_DAT {
                 patched_list.insert(file_id);
             }
         }
+        LOG(INFO) << "Category " << category << " enabled successfully";
         return SUCCESS;
     }
 
     DAT_RESULT DatFile::DisableCategory(int category) {
-        LOG(DEBUG) << "Disabling category " << category;
+        LOG(INFO) << "Disabling category " << category;
         if (inactive_categories.count(category) != 0)
             return SUCCESS;
         inactive_categories.insert(category);
@@ -1013,6 +1062,7 @@ namespace LOTRO_DAT {
                 patched_list.insert(file_id);
             }
         }
+        LOG(INFO) << "Category " << category << " disabled successfully";
         return SUCCESS;
     }
 
@@ -1021,10 +1071,12 @@ namespace LOTRO_DAT {
     }
 
     bool DatFile::CheckIfNotPatched() {
+        LOG(INFO) << "DatFile " << (patch_dict_.empty() ? "HASN'T " : "HAS already") << " been patched by LEGACY launcher!";
         return patch_dict_.empty();
     }
 
     bool DatFile::CheckIfPatchedByOldLauncher() {
+        LOG(INFO) << "DatFile " << (dictionary_.count(620750000) == 0 ? "HASN'T " : "HAS already") << " been patched by OLD LAUNCHER!";
         return dictionary_.count(620750000) > 0;
     }
 

+ 45 - 26
src/Database.cpp

@@ -7,14 +7,17 @@
 #include "BinaryData.h"
 #include "CommonFunctions.h"
 #include "SubfileData.h"
+#include "EasyLogging++/easylogging++.h"
 
 
 namespace LOTRO_DAT {
     Database::Database() {
+        LOG(DEBUG) << "Initialising new Database instance.";
         db_ = nullptr;
     }
 
     bool Database::CloseDatabase() {
+        LOG(DEBUG) << "Closing database.";
         try {
             if (db_ != nullptr) {
                 ExecSql("COMMIT TRANSACTION");
@@ -22,14 +25,14 @@ namespace LOTRO_DAT {
                 sqlite3_finalize(fetch_one_request_);
                 sqlite3_finalize(get_rows_number_request_);
                 if (sqlite3_close_v2(db_) != SQLITE_OK)
-                    fprintf(stderr, "ERROR: Bad Database::CloseDatabase() - Error when closing: %s\n",
-                            sqlite3_errmsg(db_));
+                    LOG(ERROR) << "Database error when closing: " << sqlite3_errmsg(db_);
                 db_ = nullptr;
             }
         } catch (std::exception &e) {
-            fprintf(stderr, "Bad Database::CloseDatabase() - caught exception %s\n", e.what());
+            LOG(ERROR) << "caught " << e.what() << " exception";
             return false;
         }
+        LOG(DEBUG) << "Database successfully closed.";
         return true;
     }
 
@@ -38,10 +41,12 @@ namespace LOTRO_DAT {
     }
 
     bool Database::InitDatabase(const std::string &filename) {
+        LOG(DEBUG) << "Initializing database " << filename;
         try {
             CloseDatabase();
             if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
                 sqlite3_close(db_);
+                LOG(ERROR) << "sqlite3_open returned an error.";
                 throw DatException("Bad Database::InitDatabase() - sqlite3_open returned an error...",
                                    DATABASE_EXCEPTION);
             }
@@ -61,28 +66,34 @@ namespace LOTRO_DAT {
 
             ExecSql("BEGIN TRANSACTION");
         } catch (std::exception &e) {
-            fprintf(stderr, "Bad Database::InitDatabase() - caught exception %s\n", e.what());
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
             return false;
         }
+        LOG(DEBUG) << "Database " << filename << " successfully initialized";
         return true;
     }
 
 	void Database::ExecSql(const std::string &sql) {
-        if (db_ == nullptr)
-            throw DatException("Bad Database::ExecSql() - database hasn't been opened!", DATABASE_EXCEPTION);
-
+        LOG(DEBUG) << "Executing SQL request: " << sql;
+        if (db_ == nullptr) {
+            LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
+            return;
+        }
 		char *error;
 		if (sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &error) != SQLITE_OK) {
-			fprintf(stderr, "SQLite3 error: %s\n", sqlite3_errmsg(db_));
-			throw DatException((std::string("Bad Database::ExecSql() - unable to perform request")
-				+ std::string(sql)).c_str(), DATABASE_EXCEPTION);
+			LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
+			return;
 		}
+        LOG(DEBUG) << "SQL request " << sql << " executed successfully";
 	}
 
     bool Database::PushFile(const SubfileData &data) {
+        LOG(DEBUG) << "Pushing to database file with file_id " << data.options["fid"].as<long long>();
         try {
-            if (db_ == nullptr)
-                throw DatException("Bad Database::PushFile() - database hasn't been opened!", DATABASE_EXCEPTION);
+            if (db_ == nullptr) {
+                LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
+                return false;
+            }
 
             std::stringstream options_;
             options_ << data.options;
@@ -92,25 +103,27 @@ namespace LOTRO_DAT {
             sqlite3_bind_text(insert_request_, 3, options_.str().c_str(), -1, SQLITE_TRANSIENT);
 
             if (sqlite3_step(insert_request_) != SQLITE_DONE) {
-                fprintf(stderr, "SQLite3 error: %s\n", sqlite3_errmsg(db_));
-                throw DatException(
-                        (std::string("Bad Database::PushTextFile() - unable to perform push operation")).c_str(),
-                        DATABASE_EXCEPTION);
+                LOG(ERROR) << "SQLite3 error: " << sqlite3_errmsg(db_);
+                return false;
             }
 
             sqlite3_reset(insert_request_);
         } catch (std::exception &e) {
-            fprintf(stderr, "Bad Database::PushFile() - caught exception %s\n", e.what());
+            LOG(ERROR) << "Caught " << e.what() << " exception";
             return false;
         }
+        LOG(DEBUG) << "File with file_id " << data.options["fid"].as<long long>() << " pushed to database successfully.";
         return true;
     }
 
     SubfileData Database::GetNextFile() {
+        LOG(DEBUG) << "Getting next file from database..";
         try {
             SubfileData data;
-            if (db_ == nullptr)
-                throw DatException("Bad Database::GetNexFile() - database hasn't been opened!", DATABASE_EXCEPTION);
+            if (db_ == nullptr) {
+                LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
+                return data;
+            }
 
             int result = sqlite3_step(fetch_one_request_);
 
@@ -127,14 +140,14 @@ namespace LOTRO_DAT {
             }
 
             if (result == SQLITE_DONE) {
+                LOG(DEBUG) << "Next file fetched successfully.";
                 return data;
             }
 
-            fprintf(stderr, "SQLite3 fetch_one request returned %d code. SQLite message is: %s", result,
-                    sqlite3_errmsg(db_));
-            throw DatException("Bad Database::GetNextFile() - sqlite3 - error", DATABASE_EXCEPTION);
+            LOG(ERROR) << "SQLite3 fetch_one request returned " << result << " code. SQLite message is: "<< sqlite3_errmsg(db_);
+            return data;
         } catch (std::exception &e) {
-            fprintf(stderr, "Bad Database::GetNextFile() - caught exception %s\n", e.what());
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
             return SubfileData();
         }
     }
@@ -164,19 +177,25 @@ namespace LOTRO_DAT {
     }
 
     size_t Database::CountRows() {
+        LOG(INFO) << "Counting rows in database...";
         try {
+            if (db_ == nullptr) {
+                LOG(WARNING) << "Trying to execute sql query to db, which hasn't been opened yet.";
+                return 0;
+            }
+
             int result = sqlite3_step(get_rows_number_request_);
 
             if (result == SQLITE_ERROR) {
-                fprintf(stderr, "ERROR: Bad Database::CountRows() - Error when counting rows  %s\n",
-                        sqlite3_errmsg(db_));
+                LOG(ERROR) << "Error when counting rows " << sqlite3_errmsg(db_);
                 return 0;
             }
             long long res = sqlite3_column_int64(get_rows_number_request_, 0);
             sqlite3_reset(get_rows_number_request_);
+            LOG(INFO) << "Counted " << size_t(res) << " rows in database.";
             return size_t(res);
         } catch (std::exception &e) {
-            fprintf(stderr, "Bad Database::CountRows() - caught exception %s\n", e.what());
+            LOG(ERROR) << "Caught " << e.what() << "exception.";
             return 0;
         }
     }

+ 5 - 12
src/Examples/extractor_example.cpp

@@ -19,7 +19,7 @@ using namespace std;
 bool exportImagesToFiles = false;
 bool exportFontsToFiles = false;
 bool exportSoundsToFiles = false;
-bool exportTexturesToFiles = true;
+bool exportTexturesToFiles = false;
 bool exportUnknownToFiles = false;
 
 // Change these variables to true if you want export category to databases.
@@ -33,13 +33,6 @@ bool exportUnknownToDb = false;
 
 int main() {
     std::cout << "Gi1dor's LotRO .dat extractor ver. 4.0.0" << std::endl;
-    freopen("extractor_errors.log", "w", stderr);
-
-    setbuf(stdout, NULL);
-    setbuf(stderr, NULL);
-
-    setvbuf (stdout, NULL, _IONBF, BUFSIZ);
-    setvbuf (stderr, NULL, _IONBF, BUFSIZ);
 
     std::cout << "Hello! I'm a basic shell version of .dat file extractor. I can open .dat file directly, "
             "if you write path to it (with name of file) in file \"dat_file_path.txt\"\n";
@@ -95,11 +88,10 @@ int main() {
         if (cmd != 3) {
             std::cout << "Enter number of command (1-2): ";
             std::cin >> cmd;
-        }
-
-        std::string tmp;
-        std::getline(std::cin, tmp);
 
+            std::string tmp;
+            std::getline(std::cin, tmp);
+        }
         if (cmd == -1) {
             std::cout << "Exiting. Thanks for using me!\n";
             break;
@@ -242,6 +234,7 @@ int main() {
 
             if (number == -1) {
                 std::cout << "Returning to main menu..\n";
+                cmd = 0;
             } else {
                 switch (number) {
                     case 01:

+ 15 - 10
src/SubDirectory.cpp

@@ -7,6 +7,7 @@
 #include "DatException.h"
 #include "Subfile.h"
 #include "BinaryData.h"
+#include "EasyLogging++/easylogging++.h"
 
 #include "Subfiles/TextSubfile.h"
 #include "Subfiles/DdsSubfile.h"
@@ -28,25 +29,26 @@ namespace LOTRO_DAT {
 
     SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :
             dat_(dat), offset_(offset), max_subdirs_(max_subdirs) {
+        LOG(DEBUG) << "Initialising SubDirectory";
         try {
+            LOG(DEBUG) << "Processing SubDirectories";
             MakeSubDirectories();
         } catch (std::exception &e) {
-            fprintf(stderr, "Caught %s exception.", e.what());
-            
-            fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n",
-                    offset);
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
+            LOG(DEBUG) << "Unable to initialize directory at offset " << offset << ". Initializing it as empty directory...";
+
             subdirs_.clear();
             subfiles_.clear();
             return;
         }
 
         try {
+            LOG(DEBUG) << "Processing SubFiles";
             MakeSubFiles();
         } catch (std::exception &e) {
-            fprintf(stderr, "Caught %s exception.", e.what());
-            
-            fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing it as empty directory...\n",
-                    offset);
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
+            LOG(DEBUG) << "Unable to initialize directory at offset " << offset << ". Initializing it as empty directory...";
+
             subdirs_.clear();
             subfiles_.clear();
             return;
@@ -57,6 +59,7 @@ namespace LOTRO_DAT {
         BinaryData data(1024);
         dat_->ReadData(data, 63 * 8, offset_);
         if (data.ToNumber<4>(0) != 0 || data.ToNumber<4>(4) != 0) {
+            LOG(ERROR) << "first 8 bytes are not equal to 0 at offset " << offset_;
             std::string err =
                     std::string("Bad SubDirectory::MakeSubDirectories - first 8 bytes are not equal to 0 at offset ")
                     + std::to_string(offset_);
@@ -71,8 +74,8 @@ namespace LOTRO_DAT {
                 SubDirectory *subdir = new SubDirectory(data.ToNumber<4>(i + 4), dat_);
                 subdirs_.push_back(subdir);
             } catch (std::exception &e) {
-                fprintf(stderr, "Caught %s exception.\n", e.what());
-                fprintf(stderr, "Making SubDirectory at offset %lld failed, continuing\n", data.ToNumber<4>(i + 4));
+                LOG(ERROR) << "Caught " << e.what() << " exception.";
+                LOG(DEBUG) << "Making SubDirectory at offset " << data.ToNumber<4>(i + 4) << " failed, continuing";
             }
         }
     }
@@ -159,6 +162,7 @@ namespace LOTRO_DAT {
             case UNKNOWN:
                 return dynamic_cast<Subfile *>(new UnknownSubfile(dat_, dictionary_offset, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size));
         }
+        LOG(ERROR) << "Unknown file type";
         throw DatException("Bad SubDirectory::MakeSubfile() - unable to recognize file_type!", SUBFILE_EXCEPTION);
     }
 
@@ -176,6 +180,7 @@ namespace LOTRO_DAT {
             dat_->ReadData(header, 64, (unsigned) file_offset + 8);
         }catch (DatException &e) {
             if (e.type() == READ_EXCEPTION) {
+                LOG(ERROR) << "Unable to read file header. file_id = " << file_id << ", offset = " << offset_;
                 std::string err =
                         "Bad Subfile::getExtension() - unable to read header of file with id = " +
                         std::to_string(file_id) +

+ 36 - 15
src/Subfiles/TextSubfile.cpp

@@ -8,6 +8,7 @@
 #include "DatFile.h"
 #include "DatException.h"
 #include "SubfileData.h"
+#include "EasyLogging++/easylogging++.h"
 
 #include <algorithm>
 #include <codecvt>
@@ -109,6 +110,7 @@ namespace LOTRO_DAT {
     }
 
     BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const SubfileData &data) {
+        LOG(DEBUG) << "Preparing text file " << file_id() << " for import.";
         std::unordered_map<long long, SubfileData> patch_fragments = ParsePatchFragments(data);
 
         BinaryData new_data;
@@ -139,8 +141,8 @@ namespace LOTRO_DAT {
                     // Retrieving old pieces
                     new_data = new_data + GetPieceData(old_data, offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to get piece data for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to get piece data for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
 
@@ -148,8 +150,8 @@ namespace LOTRO_DAT {
                     // Retrieving old references
                     new_data = new_data + GetArgumentReferenceData(old_data, offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to get argument reference data for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to get argument reference data for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
 
@@ -157,8 +159,8 @@ namespace LOTRO_DAT {
                     // Retrieving old ref_strings
                     new_data = new_data + GetArgumentStringsData(old_data, offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to get argument string for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to get argument string for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
 
@@ -167,8 +169,8 @@ namespace LOTRO_DAT {
                     // Making and adding new pieces
                     new_data = new_data + BuildPieces(old_data, patch_fragments[fragment_id], offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to build piece data for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to build piece data for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
 
@@ -176,8 +178,8 @@ namespace LOTRO_DAT {
                     // Making and adding new references
                     new_data = new_data + BuildArgumentReferences(old_data, patch_fragments[fragment_id], offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to build argument references data for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to build argument data for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
 
@@ -185,8 +187,8 @@ namespace LOTRO_DAT {
                     // Making and adding new strings
                     new_data = new_data + BuildArgumentStrings(old_data, patch_fragments[fragment_id], offset);
                 } catch (std::exception &e) {
-                    fprintf(stderr, "Caught %s exception.\n", e.what());
-                    fprintf(stderr, "ERROR TextSubfile::MakeForImport() - unable to build argument strings data for file_id %lld and fragment_id %lld", file_id(), fragment_id);
+                    LOG(ERROR) << "Caught " << e.what() << " exception.";
+                    LOG(DEBUG) << "Unable to build argument string data for file_id " << file_id() << " and fragment_id " << fragment_id;
                     throw DatException("Bad TextSubfile::MakeForImport()", IMPORT_EXCEPTION);
                 }
             }
@@ -196,6 +198,7 @@ namespace LOTRO_DAT {
     }
 
     std::unordered_map<long long, SubfileData> TextSubfile::ParsePatchFragments(const SubfileData &data) {
+        LOG(DEBUG) << "Started parsing patch fragments";
         std::unordered_map<long long, SubfileData> res;
         std::u16string text = data.text_data;
 
@@ -228,12 +231,14 @@ namespace LOTRO_DAT {
             pointer = pointer1  + 3;
             res[fragment_id].text_data = text_data;
         }
+        LOG(DEBUG) << "Finished parsing text patch fragments";
         return res;
     }
 
     // Make pieces/arguments/argument strings functions
 
     std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
+        LOG(DEBUG) << "Started making pieces";
         long long num_pieces = data.ToNumber<4>(offset);
         offset += 4;
 
@@ -259,10 +264,12 @@ namespace LOTRO_DAT {
             text_pieces.push_back(piece);
             offset += piece_size * 2;
         }
+        LOG(DEBUG) << "Finished making pieces";
         return text_pieces;
     }
 
     std::vector<long long> TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) {
+        LOG(DEBUG) << "Started making argument references";
         std::vector<long long> arg_references;
 
         long long num_references = data.ToNumber<4>(offset);
@@ -272,11 +279,12 @@ namespace LOTRO_DAT {
             arg_references.emplace_back(data.ToNumber<4>(offset));
             offset += 4;
         }
-
+        LOG(DEBUG) << "Finished making argument references";
         return arg_references;
     }
 
     std::vector<std::vector<BinaryData>> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) {
+        LOG(DEBUG) << "Started making argument strings";
         std::vector<std::vector<BinaryData> > arg_strings;
         long long num_arg_strings = data.ToNumber<1>(offset);
         offset += 1;
@@ -298,18 +306,20 @@ namespace LOTRO_DAT {
                 offset += string_size * 2;
             }
         }
+        LOG(DEBUG) << "Finished making argument strings";
         return arg_strings;
     }
 
     // Build pieces/arguments/argument strings functions from fragment SubfileData
 
     BinaryData TextSubfile::BuildPieces(const BinaryData &data, const SubfileData &new_data, long long &offset) {
+        LOG(DEBUG) << "Started building pieces";
         try {
             // Moving &offset pointer in &data
             GetPieceData(data, offset);
         } catch (std::exception &e) {
-            fprintf(stderr, "Caught %s exception.\n", e.what());
-            fprintf(stderr, "ERROR TextSubfile::BuildPieces() - unable to get piece data for file_id %lld", file_id());
+            LOG(ERROR) << "Caught " << e.what() << " exception.";
+            LOG(DEBUG) << "Unable to get piece data for file_id " << file_id();
             throw DatException("Bad TextSubfile::BuildPieces()", IMPORT_EXCEPTION);
         }
 
@@ -349,11 +359,13 @@ namespace LOTRO_DAT {
                 result = result + temp_data;
             }
         }
+        LOG(DEBUG) << "Pieces built successfully";
         return result;
     }
 
     BinaryData TextSubfile::BuildArgumentReferences(const BinaryData &data, const SubfileData &new_data,
                                                     long long &offset) {
+        LOG(DEBUG) << "Started building argument refs";
         // Moving &offset pointer in &data
         GetArgumentReferenceData(data, offset);
 
@@ -385,17 +397,21 @@ namespace LOTRO_DAT {
             temp_data = BinaryData::FromNumber<4>(arg_reference);
             result = result + temp_data;
         }
+        LOG(DEBUG) << "Argument refs built successfully";
         return result;
     }
 
     BinaryData TextSubfile::BuildArgumentStrings(const BinaryData &data, const SubfileData &new_data,
                                                  long long &offset) {
+        LOG(DEBUG) << "Started building argument strings";
+        LOG(DEBUG) << "Built arg strings successfully";
         return GetArgumentStringsData(data, offset);
     }
 
     // Get BinaryData contents of pieces/arguments/argument strings
 
     BinaryData TextSubfile::GetPieceData(const BinaryData &data, long long &offset) const {
+        LOG(DEBUG) << "Started getting piece data";
         long long old_offset = offset;
 
         long long num_pieces = data.ToNumber<4>(offset);
@@ -410,18 +426,22 @@ namespace LOTRO_DAT {
             offset += 1;
             offset += piece_size * 2;
         }
+        LOG(DEBUG) << "Got piece data";
         return data.CutData(old_offset, offset);
     }
 
     BinaryData TextSubfile::GetArgumentReferenceData(const BinaryData &data, long long &offset) const {
+        LOG(DEBUG) << "Started getting arg refs data";
         long long old_offset = offset;
         long long num_references = data.ToNumber<4>(offset);
         offset += 4;
         offset += 4 * num_references;
+        LOG(DEBUG) << "Finished getting arg refs data";
         return data.CutData(old_offset, offset);
     }
 
     BinaryData TextSubfile::GetArgumentStringsData(const BinaryData &data, long long &offset) const {
+        LOG(DEBUG) << "Started getting arg strings data";
         long long old_offset = offset;
 
         long long num_arg_strings = data.ToNumber<1>(offset);
@@ -441,6 +461,7 @@ namespace LOTRO_DAT {
                 offset += string_size * 2;
             }
         }
+        LOG(DEBUG) << "Finished getting arg strings data";
         return data.CutData(old_offset, offset);
     }