Browse Source

Writing locales info in dat file

Ivan Arkhipov 6 years ago
parent
commit
3213271add

+ 3 - 1
include/BinaryData.h

@@ -19,7 +19,7 @@ namespace LOTRO_DAT
     public:
         BinaryData();
         BinaryData(const BinaryData &d);
-        explicit BinaryData(char* data, unsigned int size);
+        explicit BinaryData(const char* data, unsigned int size);
         explicit BinaryData(unsigned int size);
         ~BinaryData();
 
@@ -29,6 +29,8 @@ namespace LOTRO_DAT
         bool operator == (const BinaryData &b) const;
         bool operator != (const BinaryData &b) const;
 
+        void Append(const BinaryData &b, size_t offset = 0);
+
         template <int T>
         long long ToNumber(const long long &pos) const;
 

+ 3 - 5
include/DatFile.h

@@ -88,7 +88,7 @@ namespace LOTRO_DAT {
 
         bool PatchFile(const char *filename, YAML::Node options);
 
-        bool PatchFile(const SubfileData &data);
+        bool PatchFile(const SubfileData &data, bool rewrite_original = false);
 
         bool PatchAllDatabase(Database *db);
 
@@ -120,7 +120,7 @@ namespace LOTRO_DAT {
 
         // PATCH SECTION
 
-        void ApplyFilePatch(Subfile *file, const BinaryData &data);
+        void ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original = false);
 
         std::vector<std::pair<long long, long long> > GetFragmentationJournal();
 
@@ -132,9 +132,7 @@ namespace LOTRO_DAT {
 
         // LOCALE MANAGING SECTION
     private:
-        void InitLocale(LOCALE locale, const char* dict_name);
-
-        void SaveLocale(LOCALE locale, const char* filename);
+        void InitLocales();
 
         void CommitLocales();
 

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 7 - 1
src/BinaryData.cpp

@@ -23,7 +23,7 @@ namespace LOTRO_DAT {
         memcpy(data_, d.data_, size_);
     }
 
-    BinaryData::BinaryData(char* data, unsigned int size) {
+    BinaryData::BinaryData(const char* data, unsigned int size) {
         size_ = size;
         data_ = new unsigned char[size_];
         memcpy(data_, data, size_);
@@ -252,6 +252,12 @@ namespace LOTRO_DAT {
         return !(*this == b);
     }
 
+    void BinaryData::Append(const BinaryData &b, size_t append_offset) {
+        if (append_offset + b.size() > size())
+            throw DatException("Bad Binary:Data::Append() - data for appending has more bytes than BinaryData size!", DATA_EXCEPTION);
+        memcpy(data_ + append_offset, b.data_, b.size_);
+    }
+
 
     template long long BinaryData::ToNumber<1>(long long const&) const;
     template long long BinaryData::ToNumber<2>(long long const&) const;

+ 110 - 67
src/DatFile.cpp

@@ -39,20 +39,7 @@ namespace LOTRO_DAT {
             MakeDirectories();
             MakeDictionary();
 
-            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;
-            }
+            InitLocales();
 
             if (dat_state_ == SUCCESS_DICTIONARY)
                 dat_state_ = READY;
@@ -243,7 +230,7 @@ namespace LOTRO_DAT {
     }
 
     // TODO: Write description and make asserts
-    bool DatFile::PatchFile(const SubfileData &data) {
+    bool DatFile::PatchFile(const SubfileData &data, bool rewrite_original) {
         if (dat_state_ <  READY) {
             throw DatException("Bad DatFile::PatchFile() - invalid DatFile state!", EXPORT_EXCEPTION);
         }
@@ -258,7 +245,7 @@ namespace LOTRO_DAT {
 
         BinaryData old_data = GetFileData(file);
         BinaryData patch_data = file->MakeForImport(old_data, data);
-        ApplyFilePatch(dictionary_[file_id], patch_data);
+        ApplyFilePatch(dictionary_[file_id], patch_data, rewrite_original);
         return true;
     }
 
@@ -472,18 +459,18 @@ namespace LOTRO_DAT {
     /// Special functions used by patch process.
     /// Shouldn't be used by any external class.
 
-    void DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data) {
+    void DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original) {
         if (patched_list.count(file->file_id()) != 0) {
-            fprintf(stderr, "Warning: DatFile::ApplyFilePatch - found 2 files in patch with the same file_id. Passing last...\n");
+            fprintf(stderr, "Warning: DatFile::ApplyFilePatch - found 2 files in patch with the same file_id = %lld. Passing last...\n", file->file_id());
             return;
         }
-        if (current_locale() != PATCHED) {
+        if (current_locale() != PATCHED && !rewrite_original) {
             std::cout << "Changing locale to RU in order to patch file" << std::endl;
             SetLocale(PATCHED);
         }
         dat_state_ = UPDATED;
 
-        if (orig_dict_.count(file->file_id()) == 0) {
+        if (orig_dict_.count(file->file_id()) == 0 && !rewrite_original) {
             orig_dict_[file->file_id()] = new Subfile(this, dictionary_[file->file_id()]->MakeHeaderData());
         }
 
@@ -494,7 +481,7 @@ namespace LOTRO_DAT {
 
         file->file_size_ = data.size() - 8;
 
-        if (patch_dict_.count(file->file_id()) == 0 || data.size() > file->block_size()) {
+        if ((patch_dict_.count(file->file_id()) == 0 && !rewrite_original) || data.size() > file->block_size()) {
             file->file_offset_ = journal[0].second;
             file->block_size_ = std::max(data.size(), 256u);
 
@@ -520,8 +507,10 @@ namespace LOTRO_DAT {
         auto file_id = file->file_id();
         patched_list.insert(file_id);
 
-        patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
-        patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
+        if (!rewrite_original) {
+            patch_dict_.erase(file_id); // Удалили старое значение в русском словаре
+            patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
+        }
 
         UpdateFragmentationJournal(journal);
     }
@@ -564,6 +553,9 @@ namespace LOTRO_DAT {
                 return true;
             std::cout << "There are some updated files. Rewriting dictionary..." << std::endl << std::flush;
 
+            std::cout << "Updating locales..." << std::endl;
+            CommitLocales();
+
             auto journal = GetFragmentationJournal();
             if (!patched_list.empty()) {
                 journal[0].second = file_size_;
@@ -579,8 +571,7 @@ namespace LOTRO_DAT {
             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;
@@ -627,30 +618,66 @@ namespace LOTRO_DAT {
 
     // LOCALE MANAGING SECTION
 
-    void DatFile::InitLocale(LOCALE locale, const char* filename) {
-        auto dict = GetLocaleDictReference(locale);
-        dict->clear();
+    void DatFile::InitLocales() {
+        std::cout << "Initialising locales..." << std::endl;
+        BinaryData dicts_data = GetFileData(dictionary_[2013266257]);
+
+        if (dicts_data.size() < 29) {
+            fprintf(stderr, "WARNING: DatFile::InitLocales() - locales file is empty.. Initialising locale dicts as empty\n");
+            std::cout << "Could't find locales file... Continuing without them" << std::endl;;
+            return;
+        }
 
-        FILE *dict_file = fopen(filename, "rb");
+        BinaryData hi_data = dicts_data.CutData(14, 29) + BinaryData("\0", 1);
+        std::string hi = std::string((char*)(hi_data.data()));
+        std::cout << hi << std::endl;
 
-        if (dict_file == nullptr) {
-            fprintf(stderr, "WARNING!!! DatFile::InitLocale() - cannot open .dat locale file %s\n", filename);
+        if (hi != "Hi from Gi1dor!") {
+            fprintf(stderr, "WARNING: DatFile::InitLocales() - Didn't receive 'hi' from Gi1dor... Initialising locale dicts as empty\n");
+            std::cout << "Could't init locales' file... Continuing without them" << std::endl;
             return;
         }
 
-        size_t size;
-        fread(&size, sizeof(size_t), 1, dict_file);
+        int offset = 29;
+        BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
+        std::string locale((char*)(current_locale_data.data()));
+        offset += 4;
+        std::cout << locale << std::endl;
+
+        if (locale != "PATC" && locale != "ORIG") {
+            fprintf(stderr, "WARNING: DatFile::InitLocales() - Incorrect locale... Initialising locale dicts as empty\n");
+            std::cout << "Could't recognize locale... Continuing without locales" << std::endl;;
+            return;
+        }
+        current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
 
-        std::cout << "There are " << size << " files in " << std::string(filename) << " dictionary...\n";
+        // 14 bytes for old data
+        // 15 bytes for "Hi from Gi1dor"
+        // 4 bytes for LOCALE
+        // 4 bytes for orig_dict.size()
+        // 32 * orig_dict.size() bytes for orig_dict data
+        // 4 bytes for patch_dict.size()
+        // 32 * patch_dict.size() bytes for patch_dict data
 
-        for (size_t i = 0; i < size; i++) {
-            BinaryData header(32);
-            fread(header.data(), unsigned(header.size()), 1, dict_file);
-            auto file = new Subfile(this, header);
-            (*dict)[file->file_id()] = file;
+        size_t orig_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
+        offset += 4;
+        for (size_t i = 0; i < orig_dict_size; i++) {
+            auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
+            orig_dict_[file->file_id()] = file;
+            offset += 32;
         }
 
-        fclose(dict_file);
+
+        size_t patch_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
+        offset += 4;
+        for (size_t i = 0; i < patch_dict_size; i++) {
+            auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
+            patch_dict_[file->file_id()] = file;
+            offset += 32;
+        }
+
+        std::cout << "There are " << patch_dict_.size() << " files in patch locale dictionary" << std::endl;
+        std::cout << "There are " << orig_dict_.size() << " files in original locale dictionary" << std::endl;
     }
 
     std::unordered_map<long long, Subfile *> *DatFile::GetLocaleDictReference(LOCALE locale) {
@@ -708,20 +735,6 @@ namespace LOTRO_DAT {
         }
     }
 
-    void DatFile::SaveLocale(LOCALE locale, const char *filename) {
-        auto dict = GetLocaleDictReference(locale);
-        FILE *dict_file = fopen(filename, "wb");
-
-        size_t count = size_t(dict->size());
-        fwrite(&count, sizeof(size_t), 1, dict_file);
-
-        for (auto file : *dict) {
-            BinaryData header = file.second->MakeHeaderData();
-            fwrite(header.data(), unsigned(header.size()), 1, dict_file);
-        }
-        fclose(dict_file);
-    }
-
     bool DatFile::CheckIfUpdatedByGame() {
         return false;
     }
@@ -744,20 +757,50 @@ namespace LOTRO_DAT {
 
     void DatFile::CommitLocales() {
         std::cout << "Commiting locales..." << std::endl;
-        std::cout << "Saving patched locale..." << std::endl;
-        SaveLocale(PATCHED, (std::string(filename_) + std::string("patched.dbgm")).c_str());
-        std::cout << "Saving original locale..." << std::endl;
-        SaveLocale(ORIGINAL,(std::string(filename_) + std::string("original.dbgm")).c_str());
-
-        std::cout << "Writing current locale" << std::endl;
-        FILE *locale = fopen((std::string(filename_) + ".dbgm").c_str(), "w");
-        if (current_locale_ == ORIGINAL)
-            fprintf(locale, "EN");
-        else
-            fprintf(locale, "RU");
-        fclose(locale);
+        SubfileData data = dictionary_[2013266257]->PrepareForExport(GetFileData(dictionary_[2013266257]));
+        data.options["fid"] = "2013266257";
+        data.options["ext"] = ".unknown";
+
+        BinaryData old_data = BinaryData(GetFileData(dictionary_[2013266257u]));
+
+        // 14 bytes for old data
+        // 15 bytes for "Hi from Gi1dor"
+        // 4 bytes for LOCALE
+        // 4 bytes for orig_dict.size()
+        // 32 * orig_dict.size() bytes for orig_dict data
+        // 4 bytes for patch_dict.size()
+        // 32 * patch_dict.size() bytes for patch_dict data
+
+        data.binary_data = BinaryData(14 + 15 + 4 + 4 + orig_dict_.size() * 32 + 4 + patch_dict_.size() * 32);
+
+        size_t current_size = 0;
+        data.binary_data.Append(GetFileData(dictionary_[2013266257u]).CutData(0, 14), current_size);
+        current_size += 14;
+
+        data.binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
+        current_size += 15;
+
+        data.binary_data.Append(BinaryData((current_locale_ == ORIGINAL ? "ORIG" : "PATC"), 4), current_size);
+        current_size += 4;
+
+        data.binary_data.Append(BinaryData::FromNumber<4>(orig_dict_.size()), current_size);
+        current_size += 4;
+
+        for (auto file : orig_dict_) {
+            data.binary_data.Append(file.second->MakeHeaderData(), current_size);
+            current_size += 32;
+        }
+
+        data.binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
+        current_size += 4;
+
+        for (auto file : patch_dict_) {
+            data.binary_data.Append(file.second->MakeHeaderData(), current_size);
+            current_size += 32;
+        }
+
+        PatchFile(data, true);
         std::cout << "Done!" << std::endl;
     }
-
 }
 }

+ 7 - 7
src/Examples/extractor_example.cpp

@@ -24,14 +24,14 @@ const bool exportImagesToFiles = false;
 const bool exportFontsToFiles = false;
 const bool exportSoundsToFiles = false;
 const bool exportTexturesToFiles = false;
-const bool exportUnknownToFiles = false;
+const bool exportUnknownToFiles = true;
 
 // Change these variables to true if you want export catecory to databases.
-const bool exportTextsToDb = true;
-const bool exportImagesToDb = true;
-const bool exportFontsToDb = true;
-const bool exportSoundsToDb = true;
-const bool exportTexturesToDb = true;
+const bool exportTextsToDb = false;
+const bool exportImagesToDb = false;
+const bool exportFontsToDb = false;
+const bool exportSoundsToDb = false;
+const bool exportTexturesToDb = false;
 const bool exportUnknownToDb = false;
 // There is no need to change anything else
 
@@ -129,7 +129,7 @@ int main() {
 
     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;
+        std::cout << "Extracted " << a.ExtractAllFilesByType(UNKNOWN, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
     }
 
     a.CloseDatFile();

+ 4 - 0
src/Examples/patcher_example.cpp

@@ -141,6 +141,10 @@ int main() {
         if (cmd == 3) {
             std::cout << "Current locale is " << (file.current_locale() == PATCHED ? "RU" : "Original") << endl << endl;
         }
+
+        if (cmd == 4) {
+
+        }
     }
     file.CloseDatFile();
 

+ 1 - 1
src/Subfiles/UnknownSubfile.cpp

@@ -40,6 +40,6 @@ namespace LOTRO_DAT {
             !data.options["fid"] || data.options["fid"].as<long long>() != file_id()) {
             throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-        return old_data.CutData(0, 16) + data.binary_data;
+        return data.binary_data;
     }
 };