Browse Source

Refactor - most functions of DatFile and Database return true/false (true - if no error caused and false otherwise). Added some additional cheks

Ivan Arkhipov 6 years ago
parent
commit
55ec1be5e1

+ 1 - 1
CMakeLists.txt

@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 11)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 0.1.0)
 
-SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O2" )
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O2 -Wall -Wextra" )
 SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
 
 if (MSVS)

+ 1 - 1
include/DatException.h

@@ -57,7 +57,7 @@ namespace LOTRO_DAT
             return "DatException";
         }
 
-        const DAT_EXCEPTION_TYPE type() const
+        DAT_EXCEPTION_TYPE type() const
         {
             return type_;
         }

+ 3 - 3
include/DatFile.h

@@ -72,7 +72,7 @@ namespace LOTRO_DAT {
     public:
         DatFile();
 
-        void InitDatFile(const std::string &filename, int dat_id);
+        bool InitDatFile(const std::string &filename, int dat_id);
 
         DAT_STATE DatFileState() const;
 
@@ -98,9 +98,9 @@ namespace LOTRO_DAT {
 
         BinaryData GetFileData(const Subfile *file, long long offset = 0);
 
-        void CommitChanges();
+        bool CommitChanges();
 
-        void CloseDatFile();
+        bool CloseDatFile();
 
     private:
         // INIT SECTION

+ 5 - 5
include/Database.h

@@ -22,17 +22,17 @@ namespace LOTRO_DAT
 
         ~Database();
 
-        void InitDatabase(const std::string &filename);
+        bool InitDatabase(const std::string &filename);
 
-        void CloseDatabase();
+        bool CloseDatabase();
 
-        void PushFile(const SubfileData &data);
+        bool PushFile(const SubfileData &data);
 
         SubfileData GetNextFile();
 
-        void RemoveDatabase();
+        bool RemoveDatabase();
 
-        void ClearDatabase();
+        bool ClearDatabase();
 
         size_t CountRows();
 

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 2 - 2
src/BinaryData.cpp

@@ -31,7 +31,7 @@ namespace LOTRO_DAT {
 
     BinaryData::BinaryData(unsigned int size) {
         data_ = new unsigned char[size];
-        for (int i = 0; i < size; i++)
+        for (size_t i = 0; i < size; i++)
             data_[i] = 0;
         size_ = size;
     }
@@ -242,7 +242,7 @@ namespace LOTRO_DAT {
     bool BinaryData::operator==(const BinaryData &b) const {
         if (size() != b.size())
             return false;
-        for (int i = 0; i < size(); i++)
+        for (size_t i = 0; i < size(); i++)
             if (data_[i] != b.data_[i])
                 return false;
         return true;

+ 105 - 78
src/DatFile.cpp

@@ -16,51 +16,61 @@
 extern "C++"
 {
 namespace LOTRO_DAT {
-    DatFile::DatFile() : dat_state_(CLOSED), root_directory_(nullptr), file_handler_(nullptr) {}
-
-    void DatFile::InitDatFile(const std::string &filename, int dat_id) {
-        if (dat_state_ != CLOSED)
-            CloseDatFile();
-
-        dat_id_ = dat_id;
+    DatFile::DatFile() {
         dat_state_ = CLOSED;
         root_directory_ = nullptr;
         file_handler_ = nullptr;
+    }
 
-        filename_ = filename;
+    bool DatFile::InitDatFile(const std::string &filename, int dat_id) {
+        try {
+            if (dat_state_ != CLOSED)
+                CloseDatFile();
 
-        OpenDatFile(filename.c_str());
-        ReadSuperBlock();
-        MakeDirectories();
+            dat_id_ = dat_id;
+            dat_state_ = CLOSED;
+            root_directory_ = nullptr;
+            file_handler_ = nullptr;
 
-        try {
-            MakeDictionary();
-        } catch (std::exception &e) {
-            fprintf(stderr, "Caught %s exception.", e.what());
-            fprintf(stderr, "Unable to make dictionary!! Unable to init DatFile!!!");
-            return;
-        }
+            filename_ = filename;
 
-        InitLocale(PATCHED, (filename + "patched.dbgm").c_str());
-        InitLocale(ORIGINAL,(filename + "original.dbgm").c_str());
+            OpenDatFile(filename.c_str());
+            ReadSuperBlock();
+            MakeDirectories();
 
-        FILE *locale = fopen((filename + ".dbgm").c_str(), "r");
-        if (locale == nullptr)
-            current_locale_ = ORIGINAL;
-        else {
-            auto loc = new char[10];
-            fscanf(locale, "%s", loc);
-            if (std::string(loc) == "RU")
-                current_locale_ = PATCHED;
-            if (std::string(loc) == "EN")
+            try {
+                MakeDictionary();
+            } catch (std::exception &e) {
+                fprintf(stderr, "Caught %s exception.", e.what());
+                fprintf(stderr, "Unable to make dictionary!! Unable to init DatFile!!!");
+                return false;
+            }
+
+            InitLocale(PATCHED, (filename + "patched.dbgm").c_str());
+            InitLocale(ORIGINAL, (filename + "original.dbgm").c_str());
+
+            FILE *locale = fopen((filename + ".dbgm").c_str(), "r");
+            if (locale == nullptr)
                 current_locale_ = ORIGINAL;
-        }
+            else {
+                auto loc = new char[10];
+                fscanf(locale, "%s", loc);
+                if (std::string(loc) == "RU")
+                    current_locale_ = PATCHED;
+                if (std::string(loc) == "EN")
+                    current_locale_ = ORIGINAL;
+            }
 
-        if (dat_state_ == SUCCESS_DICTIONARY)
-            dat_state_ = READY;
-        else
-            throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
-                               INIT_EXCEPTION);
+            if (dat_state_ == SUCCESS_DICTIONARY)
+                dat_state_ = READY;
+            else
+                throw DatException("Bad DatFile initialization! Not all init states were successfully passed!",
+                                   INIT_EXCEPTION);
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad DatFile::InitDatFile() - caught exception %s\n", e.what());
+            return false;
+        }
+        return true;
     }
 
     DAT_STATE DatFile::DatFileState() const {
@@ -512,7 +522,7 @@ namespace LOTRO_DAT {
         auto file_id = file->file_id();
         patched_list.insert(file_id);
 
-        delete patch_dict_[file_id]; // Удалили старое значение в русском словаре
+        patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
         patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
 
         UpdateFragmentationJournal(journal);
@@ -550,58 +560,71 @@ namespace LOTRO_DAT {
         }
     }
 
-    void DatFile::CommitChanges() {
-        if (dat_state_ != UPDATED)
-            return;
-        std::cout << "There are some updated files. Rewriting dictionary..." << std::endl << std::flush;
-
-        auto journal = GetFragmentationJournal();
-        if (!patched_list.empty()) {
-            journal[0].second = file_size_;
-            BinaryData nulls(size_t(journal[0].first));
-            WriteData(nulls, nulls.size(), file_size_);
-            file_size_ += journal[0].first;
+    bool DatFile::CommitChanges() {
+        try {
+            if (dat_state_ != UPDATED)
+                return true;
+            std::cout << "There are some updated files. Rewriting dictionary..." << std::endl << std::flush;
+
+            auto journal = GetFragmentationJournal();
+            if (!patched_list.empty()) {
+                journal[0].second = file_size_;
+                BinaryData nulls(size_t(journal[0].first));
+                WriteData(nulls, nulls.size(), file_size_);
+                file_size_ += journal[0].first;
+            }
+            UpdateFragmentationJournal(journal);
+            std::cout << "Updated fragmentation journal..." << std::endl << std::flush;
+
+            UpdateHeader();
+            std::cout << "Updated header..." << std::endl << std::flush;
+            UpdateSubdirectories();
+            std::cout << "Updated subdirectories..." << std::endl << std::flush;
+            std::cout << "Changed " << patched_list.size() << " files..." << std::endl << std::flush;
+            std::cout << "Updating locales..." << std::endl;
+            CommitLocales();
+            std::cout << "Done!" << std::endl;
+            patched_list.clear();
+            dat_state_ = READY;
+            return true;
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad DatFile::CommitChanges - caught exception %s\n", e.what());
+            return false;
         }
-        UpdateFragmentationJournal(journal);
-        std::cout << "Updated fragmentation journal..." << std::endl << std::flush;
-
-        UpdateHeader();
-        std::cout << "Updated header..." << std::endl << std::flush;
-        UpdateSubdirectories();
-        std::cout << "Updated subdirectories..." << std::endl << std::flush;
-        std::cout << "Changed " << patched_list.size() << " files..." << std::endl << std::flush;
-        std::cout << "Updating locales..." << std::endl;
-        CommitLocales();
-        std::cout << "Done!" << std::endl;
-        patched_list.clear();
-        dat_state_ = READY;
     }
 
-    void DatFile::CloseDatFile() {
-        if (dat_state_ == CLOSED)
-            return;
-
-        if (dat_state_ == UPDATED) {
-            CommitChanges();
+    bool DatFile::CloseDatFile() {
+        if (dat_state_ == CLOSED) {
+            fprintf(stderr, "DatFile::CloseDatFile() - dat state is already closed. Nothing to do\n");
+            return true;
         }
+        try {
+            if (dat_state_ == UPDATED) {
+                CommitChanges();
+            }
 
-        orig_dict_.clear();
-        patched_list.clear();
-        pending_patch_.clear();
+            orig_dict_.clear();
+            patched_list.clear();
+            pending_patch_.clear();
 
-        current_locale_ = ORIGINAL;
-        filename_.clear();
+            current_locale_ = ORIGINAL;
+            filename_.clear();
 
-        if (file_handler_ != nullptr)
-            fclose(file_handler_);
-        delete file_handler_;
+            if (file_handler_ != nullptr)
+                fclose(file_handler_);
+            delete file_handler_;
 
-        delete root_directory_;
+            delete root_directory_;
 
-        patched_list.clear();
-        dictionary_.clear();
+            patched_list.clear();
+            dictionary_.clear();
 
-        dat_state_ = CLOSED;
+            dat_state_ = CLOSED;
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad DatFile::CloseDatFile() - caught exception %s\n", e.what());
+            return false;
+        }
+        return true;
     }
 
     // LOCALE MANAGING SECTION
@@ -704,6 +727,10 @@ namespace LOTRO_DAT {
     }
 
     LOCALE DatFile::current_locale() {
+        if (current_locale_ != PATCHED && current_locale_ != ORIGINAL) {
+            fprintf(stderr, "Bad DatFile::current_locale() - locale has incorrect value. Setting it to original\n");
+            current_locale_ = ORIGINAL;
+        }
         return current_locale_;
     }
 

+ 129 - 85
src/Database.cpp

@@ -14,43 +14,57 @@ namespace LOTRO_DAT {
         db_ = nullptr;
     }
 
-    void Database::CloseDatabase() {
-        if (db_ != nullptr) {
-            ExecSql("COMMIT TRANSACTION");
-            sqlite3_finalize(insert_request_);
-            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_));
-            db_ = nullptr;
+    bool Database::CloseDatabase() {
+        try {
+            if (db_ != nullptr) {
+                ExecSql("COMMIT TRANSACTION");
+                sqlite3_finalize(insert_request_);
+                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_));
+                db_ = nullptr;
+            }
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::CloseDatabase() - caught exception %s\n", e.what());
+            return false;
         }
+        return true;
     }
 
     Database::~Database() {
         CloseDatabase();
     }
 
-    void Database::InitDatabase(const std::string &filename) {
-        CloseDatabase();
-        if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
-            sqlite3_close(db_);
-            throw DatException("Bad Database::InitDatabase() - sqlite3_open returned an error..."
-                    , DATABASE_EXCEPTION);
+    bool Database::InitDatabase(const std::string &filename) {
+        try {
+            CloseDatabase();
+            if (sqlite3_open(filename.c_str(), &db_) != SQLITE_OK) {
+                sqlite3_close(db_);
+                throw DatException("Bad Database::InitDatabase() - sqlite3_open returned an error...",
+                                   DATABASE_EXCEPTION);
+            }
+
+            ExecSql("PRAGMA synchronous = OFF");
+            ExecSql("PRAGMA count_changes = OFF");
+            ExecSql("PRAGMA journal_mode = MEMORY");
+            ExecSql("PRAGMA temp_store = MEMORY");
+            ExecSql("PRAGMA encoding = \"UTF-8\";");
+
+            ExecSql(CreateTableCommand_);
+
+            sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
+            sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr);
+            sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(),
+                               &get_rows_number_request_, nullptr);
+
+            ExecSql("BEGIN TRANSACTION");
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::InitDatabase() - caught exception %s\n", e.what());
+            return false;
         }
-
-		ExecSql("PRAGMA synchronous = OFF");
-		ExecSql("PRAGMA count_changes = OFF");
-		ExecSql("PRAGMA journal_mode = MEMORY");
-		ExecSql("PRAGMA temp_store = MEMORY");
-		ExecSql("PRAGMA encoding = \"UTF-8\";");
-
-        ExecSql(CreateTableCommand_);
-
-		sqlite3_prepare_v2(db_, InsertFileCommand_.c_str(), InsertFileCommand_.length(), &insert_request_, nullptr);
-		sqlite3_prepare_v2(db_, FetchOneCommand.c_str(), FetchOneCommand.length(), &fetch_one_request_, nullptr);
-		sqlite3_prepare_v2(db_, GetRowsNumberCommand_.c_str(), GetRowsNumberCommand_.length(), &get_rows_number_request_, nullptr);
-
-        ExecSql("BEGIN TRANSACTION");
+        return true;
     }
 
 	void Database::ExecSql(const std::string &sql) {
@@ -65,75 +79,105 @@ namespace LOTRO_DAT {
 		}
 	}
 
-    void Database::PushFile(const SubfileData &data) {
-        if (db_ == nullptr)
-            throw DatException("Bad Database::PushFile() - database hasn't been opened!", DATABASE_EXCEPTION);
-
-        std::stringstream options_;
-        options_ << data.options;
-
-        sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
-        sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
-        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);
+    bool Database::PushFile(const SubfileData &data) {
+        try {
+            if (db_ == nullptr)
+                throw DatException("Bad Database::PushFile() - database hasn't been opened!", DATABASE_EXCEPTION);
+
+            std::stringstream options_;
+            options_ << data.options;
+
+            sqlite3_bind_blob(insert_request_, 1, data.binary_data.data(), data.binary_data.size(), SQLITE_TRANSIENT);
+            sqlite3_bind_text16(insert_request_, 2, data.text_data.c_str(), -1, SQLITE_TRANSIENT);
+            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);
+            }
+
+            sqlite3_reset(insert_request_);
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::PushFile() - caught exception %s\n", e.what());
+            return false;
         }
-
-        sqlite3_reset(insert_request_);
+        return true;
     }
 
     SubfileData Database::GetNextFile() {
-        SubfileData data;
-        if (db_ == nullptr)
-            throw DatException("Bad Database::GetNexFile() - database hasn't been opened!", DATABASE_EXCEPTION);
-
-        int result = sqlite3_step(fetch_one_request_);
-
-        if (result == SQLITE_ROW) {
-            data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
-                                     unsigned(sqlite3_column_bytes(fetch_one_request_, 0)));
-
-            data.text_data = std::u16string((char16_t *)sqlite3_column_text16(fetch_one_request_, 1));
-
-            std::string _options = std::string((char *)sqlite3_column_text(fetch_one_request_, 2),
-                                               unsigned(sqlite3_column_bytes(fetch_one_request_, 2)));
-            data.options = YAML::Load(_options);
-            return data;
+        try {
+            SubfileData data;
+            if (db_ == nullptr)
+                throw DatException("Bad Database::GetNexFile() - database hasn't been opened!", DATABASE_EXCEPTION);
+
+            int result = sqlite3_step(fetch_one_request_);
+
+            if (result == SQLITE_ROW) {
+                data.binary_data = BinaryData((char *) sqlite3_column_blob(fetch_one_request_, 0),
+                                              unsigned(sqlite3_column_bytes(fetch_one_request_, 0)));
+
+                data.text_data = std::u16string((char16_t *) sqlite3_column_text16(fetch_one_request_, 1));
+
+                std::string _options = std::string((char *) sqlite3_column_text(fetch_one_request_, 2),
+                                                   unsigned(sqlite3_column_bytes(fetch_one_request_, 2)));
+                data.options = YAML::Load(_options);
+                return data;
+            }
+
+            if (result == SQLITE_DONE) {
+                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);
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::GetNextFile() - caught exception %s\n", e.what());
+            return SubfileData();
         }
-
-        if (result == SQLITE_DONE) {
-            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);
     }
 
-    void Database::RemoveDatabase() {
-        if (db_ == nullptr)
-            throw DatException("Bad Database::RemoveDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
-        throw DatException("Database::RemoveDatabase() haven't been implemented yet...", DATABASE_EXCEPTION);
-        // TODO: Implement function
+    bool Database::RemoveDatabase() {
+        try {
+            if (db_ == nullptr)
+                throw DatException("Bad Database::RemoveDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
+            throw DatException("Database::RemoveDatabase() haven't been implemented yet...", DATABASE_EXCEPTION);
+            // TODO: Implement function
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::RemoveDatabase() - caught exception %s\n", e.what());
+            return false;
+        }
     }
 
-    void Database::ClearDatabase() {
-        if (db_ == nullptr)
-            throw DatException("Bad Database::ClearDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
-        ExecSql(ClearTableCommand_);
+    bool Database::ClearDatabase() {
+        try {
+            if (db_ == nullptr)
+                throw DatException("Bad Database::ClearDatabase() - database hasn't been opened!", DATABASE_EXCEPTION);
+            ExecSql(ClearTableCommand_);
+            return true;
+        }  catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::ClearDatabase() - caught exception %s\n", e.what());
+            return false;
+        }
     }
 
     size_t Database::CountRows() {
-        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_));
+        try {
+            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_));
+                return 0;
+            }
+            long long res = sqlite3_column_int64(get_rows_number_request_, 0);
+            sqlite3_reset(get_rows_number_request_);
+            return size_t(res);
+        } catch (std::exception &e) {
+            fprintf(stderr, "Bad Database::CountRows() - caught exception %s\n", e.what());
             return 0;
         }
-        long long res = sqlite3_column_int64(get_rows_number_request_, 0);
-        sqlite3_reset(get_rows_number_request_);
-        return size_t(res);
     }
 }

+ 77 - 74
src/Examples/extractor_example.cpp

@@ -56,81 +56,84 @@ int main() {
     setbuf(stderr, NULL);
     setvbuf (stdout, NULL, _IONBF, BUFSIZ);
     setvbuf (stderr, NULL, _IONBF, BUFSIZ);
-    try {
-        std::cout << "Starting search...\n" << std::flush;
-        DatFile a;
-        a.InitDatFile(path + filename, 0);
-        std::cout << "Total files found: " << a.files_number() << std::endl << std::flush;
-        a.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;
-
-        Database output_db;
-
-        if (exportImagesToDb) {
-            output_db.InitDatabase(output_dir + std::string("Images.db"));
-            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, &output_db) << " .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 " << a.ExtractAllFilesByType(WAV, &output_db) << " .wav files to Sounds.db" << std::endl << std::flush;
-            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, &output_db) << " .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 " << a.ExtractAllFilesByType(TEXT, &output_db) << " 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 " << a.ExtractAllFilesByType(FONT, &output_db) << " 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 " << a.ExtractAllFilesByType(DDS, &output_db) << " .dds files to Textures.db" << std::endl << std::flush;
-            output_db.CloseDatabase();
-        }
-
-        if (exportImagesToFiles) {
-            mkdir((output_dir + "jpg").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl << std::flush;
-        }
-
-        if (exportTexturesToFiles) {
-            mkdir((output_dir + "dds").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl << std::flush;
-        }
-
-        if (exportSoundsToFiles) {
-            mkdir((output_dir + "wav").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
-            mkdir((output_dir + "ogg").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl << std::flush;
-        }
-
-        if (exportFontsToFiles) {
-            mkdir((output_dir + "fonts").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl << std::flush;
-        }
-
-        if (exportUnknownToFiles) {
-            mkdir((output_dir + "unknown").c_str(), 744);
-            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
-        }
-
-        a.CloseDatFile();
-    } catch (std::exception &e) {
-        fprintf(stderr, "Caught %s exception.", e.what());
-        printf("Some critical errors occured. Need to stop execution. See information in errors.log file\n");
-        fprintf(stderr, "Some critical errors occured. Need to stop execution now...\n");
+
+    std::cout << "Starting search...\n" << std::flush;
+
+    DatFile a;
+
+    if (!a.InitDatFile(path + filename, 0)) {
+        std::cout << "Unable to initialize .dat file in " << path + filename << std::endl;
+        system("pause");
+        return 0;
+    }
+
+    std::cout << "Total files found: " << a.files_number() << std::endl << std::flush;
+    a.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;
+
+    Database output_db;
+
+    if (exportImagesToDb) {
+        output_db.InitDatabase(output_dir + std::string("Images.db"));
+        std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, &output_db) << " .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 " << a.ExtractAllFilesByType(WAV, &output_db) << " .wav files to Sounds.db" << std::endl << std::flush;
+        std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, &output_db) << " .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 " << a.ExtractAllFilesByType(TEXT, &output_db) << " 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 " << a.ExtractAllFilesByType(FONT, &output_db) << " 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 " << a.ExtractAllFilesByType(DDS, &output_db) << " .dds files to Textures.db" << std::endl << std::flush;
+        output_db.CloseDatabase();
+    }
+
+    if (exportImagesToFiles) {
+        mkdir((output_dir + "jpg").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl << std::flush;
+    }
+
+    if (exportTexturesToFiles) {
+        mkdir((output_dir + "dds").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl << std::flush;
+    }
+
+    if (exportSoundsToFiles) {
+        mkdir((output_dir + "wav").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
+        mkdir((output_dir + "ogg").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl << std::flush;
+    }
+
+    if (exportFontsToFiles) {
+        mkdir((output_dir + "fonts").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl << std::flush;
+    }
+
+    if (exportUnknownToFiles) {
+        mkdir((output_dir + "unknown").c_str(), 744);
+        std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
+    }
+
+    a.CloseDatFile();
+
     fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
             float(clock() - begin_time) / CLOCKS_PER_SEC);
     system("pause");

+ 99 - 132
src/Examples/patcher_example.cpp

@@ -25,157 +25,124 @@ int main() {
    // setvbuf (stdout, NULL, _IONBF, BUFSIZ);
     setvbuf (stderr, NULL, _IONBF, BUFSIZ);
 
-    try {
-        std::cout << "Hello! I'm a basic shell version of .dat file patcher.\n";
-        DatFile file;
-        
-        ifstream in("dat_file_path.txt");
-        if (!in.fail()) {
-            std::string filename;
-            getline(in, filename);
-            try {
-                std::cout << "Using .dat file from dat_file_path.txt...\n";
-                std::cout << "Opening file " << filename << std::endl;
-                file.InitDatFile(filename, 0);
-            } catch (DatException &e) {
-                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();
-            }
+    std::cout << "Hello! I'm a basic shell version of .dat file patcher.\n";
+    DatFile file;
+
+    ifstream in("dat_file_path.txt");
+    if (!in.fail()) {
+        std::string filename;
+        getline(in, filename);
+
+        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();
         }
+    }
 
-        while (file.DatFileState() == CLOSED) {
-            std::cout << "Please, tell, where the .dat file is\n";
-            std::cout << "Enter path to file (including filename): ";
-            std::string filename;
-            std::getline(std::cin, filename);
-
-            std::cout << "Opening file " << filename << std::endl;
-
-            try {
-                file.InitDatFile(filename.c_str(), 0);
-            } catch (DatException &e) {
-                if (e.type() == NOFILE_EXCEPTION)
-                    std::cout << "Cannot find file... Could you enter .dat filename once more?" << std::endl;
-                else
-                    std::cout << "Some error caused while opening the file... "
-                            "Could you enter .dat filename once more?" << std::endl;
-                file.CloseDatFile();
-            }
+    while (file.DatFileState() == CLOSED) {
+        std::cout << "Please, tell, where the .dat file is\n";
+        std::cout << "Enter path to file (including filename): ";
+        std::string filename;
+        std::getline(std::cin, filename);
+
+        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();
         }
+    }
 
-        std::cout << "Great! File initialised successfully!\n";
-        std::cout << "Files number: " << file.files_number() << std::endl;
+    std::cout << "Great! File initialised successfully!\n";
+    std::cout << "Files number: " << file.files_number() << std::endl;
 
-        while (true) {
-            std::cout << "Please, choose, what should I do. I can patch datfile from database to .dat file (enter 1), "
-                    "change locale (enter 2), print current locale (enter 3) or exit (enter -1)\n";
-            int cmd = 0;
-            std::cout << "Enter number of command (1-4): ";
-            std::cin >> cmd;
+    while (true) {
+        std::cout << "Please, choose, what should I do. I can patch datfile from database to .dat file (enter 1), "
+                "change locale (enter 2), print current locale (enter 3) or exit (enter -1)\n";
+        int cmd = 0;
+        std::cout << "Enter number of command (1-4): ";
+        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;
-            }
-            if (cmd == 1) {
-                std::cout << "You've chosen to patch database! Write name of database file (it should be in the same "
-                        "directory), of enter 0 to return to main dialogue.\n";
-                while (true) {
-                    std::cout << "Enter name of file or 0: ";
-                    std::string dbname;
-                    std::getline(std::cin, dbname);
-
-                    if (dbname == std::to_string(0)) {
-                        std::cout << "Okay, returning back...\n\n";
-                        break;
-                    }
+        if (cmd == -1) {
+            std::cout << "Exiting. Thanks for using me!\n";
+            break;
+        }
 
-                    Database db;
-                    try {
-                        std::cout << "Opening database... " << dbname << std::endl;
-                        db.InitDatabase(dbname);
-                        if (db.CountRows() == 0) {
-                            std::cout << "There are no files in database or database doesn't exist. "
-                                    "Please, try again!\n";
-                            continue;
-                        }
-                        std::cout << "There are " << db.CountRows() << " files in database." << std::endl;
-                    } catch (DatException &e) {
-                        std::cout << "Unfortunately, I cannot open this database. Could you try again please?\n";
-                        continue;
-                    }
+        if (cmd == 1) {
+            std::cout << "You've chosen to patch database! Write name of database file (it should be in the same "
+                    "directory), of enter 0 to return to main dialogue.\n";
+            while (true) {
+                std::cout << "Enter name of file or 0: ";
+                std::string dbname;
+                std::getline(std::cin, dbname);
+
+                if (dbname == std::to_string(0)) {
+                    std::cout << "Okay, returning back...\n\n";
+                    break;
+                }
 
-                    std::cout << "Successfully opened database! Beginning patching...\n";
-                    const clock_t begin_time = clock();
-                    size_t all = db.CountRows();
-                    size_t now = 0;
+                Database db;
 
-                    SubfileData subfile;
+                std::cout << "Opening database... " << dbname << std::endl;
 
-                    try {
-                        subfile = db.GetNextFile();
-                    } catch (std::exception &e) {
-                        fprintf(stderr, "Caught %s exception.\n", e.what());
-                        fprintf(stderr, "DatFile::PatchAllDatabase() error! Caught exception while fetching "
-                                "file from database! Stopping...\n");
-                        return false;
-                    }
-                    while (!subfile.Empty()) {
-                        try {
-                            file.PatchFile(subfile);
-                        } catch (std::exception &e) {
-                            fprintf(stderr, "Caught %s exception.\n", e.what());
-                            fprintf(stderr, "DatFile::PatchAllDatabase() error! Caught exception while "
-                                    "patching file! Passing...\n");
-                        }
-
-                        try {
-                            subfile = db.GetNextFile();
-                        } catch (std::exception &e) {
-                            fprintf(stderr, "Caught %s exception.\n", e.what());
-                            fprintf(stderr,"DatFile::PatchAllDatabase() error! Caught exception while fetching "
-                                            "file from database! Stopping...\n");
-                            break;
-                        }
-                        ++now;
-                        if (now * 100 / all > (now - 1) * 100 / all)
-                            std::cout << now * 100 / all << "%\n";
-                    }
+                if (!db.InitDatabase(dbname)) {
+                    std::cout << "Unfortunately, I cannot open this database. Could you try again please?\n";
+                    continue;
+                };
+                if (db.CountRows() == 0) {
+                    std::cout << "There are no files in database or database doesn't exist. "
+                            "Please, try again!\n";
+                    continue;
+                }
+                std::cout << "There are " << db.CountRows() << " files in database." << std::endl;
 
-                    db.CloseDatabase();
-                    file.CommitChanges();
+                std::cout << "Successfully opened database! Beginning patching...\n";
+                const clock_t begin_time = clock();
+                size_t all = db.CountRows();
+                size_t now = 0;
 
-                    fprintf(stdout, "Spent %f seconds on patching! Thank you for your patience!\n",
-                            float(clock() - begin_time) / CLOCKS_PER_SEC);
+                SubfileData subfile = db.GetNextFile();
+                while (!subfile.Empty()) {
+                    if (!file.PatchFile(subfile)) {
+                        fprintf(stderr, "Error! Caught exception while patching file! Passing it\n");
+                    }
 
-                    std::cout << "Great! File was patched successfully!\n\n";
-                    break;
+                    subfile = db.GetNextFile();
+                    ++now;
+                    if (now * 100 / all > (now - 1) * 100 / all)
+                        std::cout << now * 100 / all << "%\n";
                 }
-            }
-            if (cmd == 2) {
-                std::cout << "Old locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl;
-                std::cout << "Changing locale..." << std::endl;
-                file.SetLocale(file.current_locale() == PATCHED ? ORIGINAL : PATCHED);
-                std::cout << "New locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
-            }
 
-            if (cmd == 3) {
-                std::cout << "Current locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
+                db.CloseDatabase();
+                file.CommitChanges();
+
+                fprintf(stdout, "Spent %f seconds on patching! Thank you for your patience!\n",
+                        float(clock() - begin_time) / CLOCKS_PER_SEC);
+
+                std::cout << "Great! File was patched successfully!\n\n";
+                break;
             }
         }
-        file.CloseDatFile();
-    } catch (std::exception &e) {
-        fprintf(stderr, "Caught %s exception.", e.what());
-        printf("Caught %s exception.", e.what());
-        fflush(stdout);
-
-        printf("Some critical errors occured. Need to stop execution. See information in errors.log file\n");
-        fprintf(stderr, "Some critical errors occured. Need to stop execution now...\n");
+        if (cmd == 2) {
+            std::cout << "Old locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl;
+            std::cout << "Changing locale..." << std::endl;
+            file.SetLocale(file.current_locale() == PATCHED ? ORIGINAL : PATCHED);
+            std::cout << "New locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
+        }
+
+        if (cmd == 3) {
+            std::cout << "Current locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
+        }
     }
+    file.CloseDatFile();
 
     system("pause");
     return 0;

+ 2 - 4
src/SubDirectory.cpp

@@ -22,10 +22,8 @@ namespace LOTRO_DAT {
     }
 
     SubDirectory::~SubDirectory() {
-        for (Subfile* file : subfiles_)
-            delete file;
-        for (SubDirectory *directory : subdirs_)
-            delete directory;
+        subfiles_.clear();
+        subdirs_.clear();
     }
 
     SubDirectory::SubDirectory(long long offset, DatFile *dat, long long max_subdirs) :