123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- #include <DatSubsystems/DatLocaleManager.h>
- #include <EasyLogging++/easylogging++.h>
- #include <DatFile.h>
- #include <SubFile.h>
- #define DAT_LOCALE_DICT_VERSION 102
- namespace LOTRO_DAT {
- DatLocaleManager::DatLocaleManager(DatFile *datFilePtr) : dat(datFilePtr), current_locale_(ORIGINAL) {
- }
-
- DatOperationResult<> DatLocaleManager::Init() {
- if (!dat)
- return DatOperationResult<>(ERROR, "LOCALEINIT: no connection with Dat (dat is nullptr)");
- orig_dict_.clear();
- patch_dict_.clear();
- inactive_categories.clear();
- current_locale_ = ORIGINAL;
- LOG(INFO) << "Initialising locales...";
- BinaryData locale_offset_data(4);
- dat->GetIO().ReadData(locale_offset_data, 4, 300);
- long long locale_offset = locale_offset_data.ToNumber<4>(0);
- if (locale_offset == 0 || locale_offset + 8 >= dat->GetIO().GetActualDatSize().value) {
- if (CheckLocaleCorrect()) {
- LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
- return DatOperationResult<>();
- } else {
- return DatOperationResult<>(ERROR,
- "Locale dict is incorrect, through patched mark is standing. Dat file may be corrupted");
- }
- }
- BinaryData locale_info(16);
- dat->GetIO().ReadData(locale_info, 16, locale_offset);
- long long dict_size = locale_info.ToNumber<4>(0);
- long long dict_version = locale_info.ToNumber<4>(4);
- long long patched_file_end = locale_info.ToNumber<4>(8);
- long long dat_file_header_hash = locale_info.ToNumber<4>(12);
- if (dict_version != DAT_LOCALE_DICT_VERSION) {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
- if (CheckLocaleCorrect())
- return DatOperationResult<>(SUCCESS);
- else
- return DatOperationResult<>(ERROR,
- "Version of locales' dictionary is incorrect, through patched mark is standing. Dat file may be corrupted");
- }
- if (dat_file_header_hash != dat->GetIO().GetHeaderHash()) {
- LOG(INFO) << "Header hash, written after last patch apply doesn't match current hash. Seems like dat-file was modified somewhere else, so removing all patch data";
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
- if (CheckLocaleCorrect())
- return DatOperationResult<>(SUCCESS);
- else
- return DatOperationResult<>(ERROR,
- "Version of locales' dictionary is incorrect, through patched mark is standing. Dat file may be corrupted");
- }
- BinaryData dicts_data = BinaryData((unsigned) dict_size);
- dat->GetIO().ReadData(dicts_data, dict_size - 16, locale_offset + 16);
- if (dicts_data.size() < 15) {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
- return DatOperationResult<>(ERROR, "INITLOCALE: Data in locales' dictionary is incorrect.");
- }
- BinaryData hi_data = dicts_data.CutData(0, 15) + BinaryData("\0", 1);
- std::string hi = std::string((char *) (hi_data.data()));
- if (hi != "Hi from Gi1dor!")
- return DatOperationResult<>(ERROR,
- "INITLOCALE: Data in locales' dictionary is incorrect (couldn't receive 'Hello').");
- int offset = 15;
- BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
- std::string locale((char *) (current_locale_data.data()));
- offset += 4;
- if (locale != "PATC" && locale != "ORIG")
- return DatOperationResult<>(ERROR,
- "INITLOCALE: Data in locales' dictionary is incorrect (current locale mark is invalid).");
- current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
- 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 = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
- file.category = dicts_data.ToNumber<4>(offset + 32);
- orig_dict_[file.file_id()] = file;
- offset += 36;
- }
- 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 = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
- file.category = dicts_data.ToNumber<4>(offset + 32);
- patch_dict_[file.file_id()] = file;
- offset += 36;
- }
- size_t inactive_categories_set_size = size_t(dicts_data.ToNumber<4>(offset));
- offset += 4;
- for (size_t i = 0; i < inactive_categories_set_size; i++) {
- size_t category_id = size_t(dicts_data.ToNumber<4>(offset));
- inactive_categories.insert(category_id);
- offset += 4;
- }
- LOG(INFO) << "There are " << patch_dict_.size() << " files in patch locale dictionary";
- LOG(INFO) << "There are " << orig_dict_.size() << " files in original locale dictionary";
- LOG(INFO) << "There are " << inactive_categories.size() << " categories inactive: ";
- LOG(INFO) << "Finished initialising locales";
- if (CheckLocaleCorrect()) {
- dat->GetFileSystem().patched_file_end = patched_file_end;
- LOG(INFO) << "Locales initialisation success. Dictionary size is " << dict_size << ". Version is "
- << dict_version << ". Localed .dat size = " << patched_file_end;
- return DatOperationResult<>(SUCCESS);
- } else {
- orig_dict_.clear();
- patch_dict_.clear();
- inactive_categories.clear();
- current_locale_ = ORIGINAL;
- return DatOperationResult<>(ERROR,
- "Locale dict is incorrect, through patched mark is standing. Dat file may be corrupted");
- }
- }
-
- DatOperationResult<> DatLocaleManager::SetLocale(DatLocaleManager::LOCALE locale) {
- if (dat->GetStatusModule().GetStatus() == DatStatus::E_FREE)
- dat->GetStatusModule().SetStatus(DatStatus::E_COMMITING);
- dat->GetStatusModule().SetDebugMessage("Changing locale to " +
- (locale == PATCHED ? std::string(" patched version")
- : std::string(" original version")));
- LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
- if (!dat)
- return DatOperationResult<>(ERROR, "SETLOCALE: no connection with Dat (dat is nullptr)");
- if (current_locale_ == locale) {
- LOG(INFO) << "Locale is already " << locale << ", nothing to do.";
- if (dat->GetStatusModule().GetStatus() == DatStatus::E_COMMITING)
- dat->GetStatusModule().SetDefaultStatus();
- return DatOperationResult<>(SUCCESS);
- }
- std::map<long long, SubFile> &dict = GetLocaleDictReference(locale);
- size_t files_total = dict.size();
- size_t files_proceeded = 0;
- dat->GetStatusModule().SetTotalParts(files_total);
- for (const auto &file : dict) {
- ++files_proceeded;
- dat->GetStatusModule().SetFinishedParts(files_proceeded);
- if (CategoryIsInactive(file.second.category) && locale == PATCHED)
- continue;
- long long file_id = file.first;
- auto dict_file_result = dat->GetFileSystem().GetFile(file_id);
- if (dict_file_result.result != SUCCESS) {
- LOG(WARNING) << "Unable to get file with id = " << file_id << "from datFileSystem!";
- dict.erase(file_id);
- continue;
- }
- std::shared_ptr<SubFile> dict_file = dict_file_result.value;
- if (dict_file->MakeHeaderData().CutData(8, 16) == file.second.MakeHeaderData().CutData(8, 16))
- continue;
- dat->GetFileSystem().UpdateFileInfo(file.second);
- }
- current_locale_ = locale;
- if (dat->GetStatusModule().GetStatus() == DatStatus::E_COMMITING)
- dat->GetStatusModule().SetDefaultStatus();
- return DatOperationResult<>(SUCCESS);
- }
-
- DatLocaleManager::LOCALE DatLocaleManager::GetCurrentLocale() {
- return current_locale_;
- }
-
- DatOperationResult<> DatLocaleManager::DeInit() {
- LOG(INFO) << "Committing locales...";
- if (!dat)
- return DatOperationResult<>(ERROR, "LOCALEDEINIT: no connection with Dat (dat is nullptr)");
- auto result = CommitLocales();
- ClearData();
- return result;
- }
-
- void DatLocaleManager::UpdateLocaleFile(DatLocaleManager::LOCALE locale, const SubFile &file) {
- std::map<long long, SubFile> &dict = GetLocaleDictReference(locale);
- dict[file.file_id()] = file;
- }
-
- DatOperationResult<SubFile> DatLocaleManager::GetLocaleFile(long long file_id, DatLocaleManager::LOCALE locale) {
- std::map<long long, SubFile> &dict = GetLocaleDictReference(locale);
- if (dict.count(file_id) == 0)
- return DatOperationResult<SubFile>(SubFile(), ERROR,
- "GETLOCFILE: cannot get file with id = " + std::to_string(file_id) +
- " from dict " + std::to_string(locale));
- return DatOperationResult<SubFile>(dict[file_id], SUCCESS);
- }
-
- std::map<long long, SubFile> &DatLocaleManager::GetLocaleDictReference(DatLocaleManager::LOCALE locale) {
- return locale == PATCHED ? patch_dict_ : orig_dict_;
- }
-
- void DatLocaleManager::PrintInformaion(FILE *file) {
- fprintf(file, "========= Locales info ========\n");
- BinaryData locale_offset_data(4);
- dat->GetIO().ReadData(locale_offset_data, 4, 300);
- long long locale_offset = locale_offset_data.ToNumber<4>(0);
- fprintf(file, "Locales' dictionary offset = %lld\n", locale_offset);
- BinaryData locale_status_data(4);
- dat->GetIO().ReadData(locale_status_data, 4, 296);
- long long locale_status = locale_offset_data.ToNumber<4>(0);
- fprintf(file, "Locale status = %lld\n", locale_status);
- if (locale_offset != 0) {
- BinaryData locale_info(16);
- dat->GetIO().ReadData(locale_info, 16, locale_offset);
- long long dict_size = locale_info.ToNumber<4>(0);
- long long dict_version = locale_info.ToNumber<4>(4);
- fprintf(file, "Locales' dictionary size = %lld, version = %lld\n", dict_size, dict_version);
- }
- fprintf(file, "Current locale id = %d\n", current_locale_);
- fprintf(file, "Patch dictionary size = %d\n", patch_dict_.size());
- fprintf(file, "Original dictionary size = %d\n", orig_dict_.size());
- }
-
- bool DatLocaleManager::CheckLocaleCorrect() {
- BinaryData locale_info(4);
- dat->GetIO().ReadData(locale_info, 4, 296);
- long long locale_status = locale_info.ToNumber<4>(0);
- BinaryData locale_offset_data(4);
- dat->GetIO().ReadData(locale_offset_data, 4, 300);
- long long locale_offset = locale_offset_data.ToNumber<4>(0);
- if (locale_offset == 0 || locale_offset + 8 >= dat->GetIO().GetActualDatSize().value)
- return locale_status == 0;
- BinaryData dicts_data = BinaryData(4);
- auto operation = dat->GetIO().ReadData(dicts_data, 4, locale_offset + 16 + 15);
- if (operation.result == ERROR)
- return locale_status == 0;
- BinaryData locale_data = dicts_data + BinaryData("\0", 1);
- std::string locale((char *) (locale_data.data()));
- LOCALE dat_locale = (locale == "PATC" ? PATCHED : ORIGINAL);
- if ((locale_status == 0 && dat_locale == PATCHED) || (locale_status != 0 && dat_locale == ORIGINAL)) {
- LOG(ERROR) << "CHCKLOCALECORRECT: Locale status and current_locale doesn't match!";
- return false;
- }
- if (locale_status != 0 && locale_status != dat->GetIO().GetHeaderHash()){
- LOG(ERROR) << "CHCKLOCALECORRECT: Locale hash doesn't match!";
- return false;
- }
- return true;
- }
-
- bool DatLocaleManager::CategoryIsInactive(long long category) {
- return inactive_categories.count(category) > 0;
- }
-
- void DatLocaleManager::UpdateCategory(long long file_id, long long category) {
- if (orig_dict_.count(file_id))
- orig_dict_[file_id].category = category;
- if (patch_dict_.count(file_id))
- patch_dict_[file_id].category = category;
- }
-
- const std::set<long long> &DatLocaleManager::GetInactiveCategories() {
- return inactive_categories;
- }
-
- DatOperationResult<> DatLocaleManager::CommitLocales() {
- if (!dat->Initialized())
- return DatOperationResult<>(SUCCESS);
- if (patch_dict_.empty()) {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
- return DatOperationResult<>(SUCCESS);
- }
- BinaryData binary_data = BinaryData(4 + 4 + 4 + 4 + 14 + 15 + 4
- + 4 + (32 + 4) * orig_dict_.size()
- + 4 + (32 + 4) * patch_dict_.size()
- + 4 + 4 * inactive_categories.size());
-
- size_t current_size = 16;
- binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
- current_size += 15;
- binary_data.Append(BinaryData((current_locale_ == ORIGINAL ? "ORIG" : "PATC"), 4), current_size);
- current_size += 4;
- binary_data.Append(BinaryData::FromNumber<4>(orig_dict_.size()), current_size);
- current_size += 4;
- for (const auto &file : orig_dict_) {
- binary_data.Append(file.second.MakeHeaderData(), current_size);
- current_size += 32;
- binary_data.Append(BinaryData::FromNumber<4>(file.second.category), current_size);
- current_size += 4;
- }
- binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
- current_size += 4;
- for (const auto &file : patch_dict_) {
- binary_data.Append(file.second.MakeHeaderData(), current_size);
- current_size += 32;
- binary_data.Append(BinaryData::FromNumber<4>(file.second.category), current_size);
- current_size += 4;
- }
- binary_data.Append(BinaryData::FromNumber<4>(inactive_categories.size()), current_size);
- current_size += 4;
- for (auto patch_id : inactive_categories) {
- binary_data.Append(BinaryData::FromNumber<4>(patch_id), current_size);
- current_size += 4;
- }
- BinaryData dicts_data(4);
- dat->GetIO().ReadData(dicts_data, 4, 300);
- long long dict_offset = dicts_data.ToNumber<4>(0);
- dat->GetIO().ReadData(dicts_data, 4, dict_offset);
- long long dict_size = dicts_data.ToNumber<4>(0);
- if (binary_data.size() > dict_size || dict_offset == 0) {
- long long new_dict_offset = dat->GetFileSystem().patched_file_end + 16;
-
- binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 0);
- binary_data.Append(BinaryData::FromNumber<4>(DAT_LOCALE_DICT_VERSION), 4);
- binary_data.Append(
- BinaryData::FromNumber<4>(dat->GetFileSystem().patched_file_end + binary_data.size() + 20 * 1024 * 1024), 8);
- binary_data.Append(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 12);
- auto operation = dat->GetIO().WriteData(binary_data, binary_data.size(), new_dict_offset);
- if (operation.result != SUCCESS) {
- return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales");
- }
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(new_dict_offset), 4, 300);
- if (current_locale_ == PATCHED) {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 4, 296);
- } else {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
- }
- dat->GetFileSystem().patched_file_end += binary_data.size();
- LOG(INFO) << "Writing 20 mbytes to " << dat->GetFileSystem().patched_file_end;
- BinaryData nulls(unsigned(20 * 1024 * 1024));
- dat->GetIO().WriteData(nulls, nulls.size(), dat->GetFileSystem().patched_file_end);
- dat->GetFileSystem().patched_file_end += nulls.size();
- } else {
- binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)), 0);
- binary_data.Append(BinaryData::FromNumber<4>(DAT_LOCALE_DICT_VERSION), 4);
- binary_data.Append(BinaryData::FromNumber<4>(dat->GetFileSystem().patched_file_end), 8);
- binary_data.Append(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 12);
- if (current_locale_ == PATCHED) {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(dat->GetIO().GetHeaderHash()), 4, 296);
- } else {
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
- }
- auto operation = dat->GetIO().WriteData(binary_data, binary_data.size(), dict_offset);
- if (operation.result != SUCCESS) {
- return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales. ERRMSG: " + operation.msg);
- }
- }
- LOG(INFO) << "Locales committed successfully";
- return DatOperationResult<>(SUCCESS);
- }
- void DatLocaleManager::ClearData() {
- orig_dict_.clear();
- patch_dict_.clear();
- inactive_categories.clear();
- current_locale_ = LOCALE(-1);
- }
- DatOperationResult<> DatLocaleManager::EnableCategory(long long category) {
- inactive_categories.erase(category);
- dat->GetStatusModule().SetStatus(DatStatus::E_COMMITING);
-
- size_t files_count = patch_dict_.size();
- size_t files_processed = 0;
- dat->GetStatusModule().SetTotalParts(files_count);
- for (const auto& entry : patch_dict_) {
- SubFile file = entry.second;
- ++files_processed;
- dat->GetStatusModule().SetFinishedParts(files_processed);
- if (file.category == category) {
- dat->GetFileSystem().UpdateFileInfo(file);
- }
- }
- dat->GetStatusModule().SetDefaultStatus();
- return DatOperationResult<>(SUCCESS);
- }
- DatOperationResult<> DatLocaleManager::DisableCategory(long long category) {
- inactive_categories.insert(category);
- dat->GetStatusModule().SetStatus(DatStatus::E_COMMITING);
- dat->GetStatusModule().SetFinishedParts(0);
- size_t files_count = orig_dict_.size();
- size_t files_processed = 0;
- dat->GetStatusModule().SetTotalParts(files_count);
- for (const auto& entry : orig_dict_) {
- SubFile file = entry.second;
- ++files_processed;
- dat->GetStatusModule().SetFinishedParts(files_processed);
- if (file.category == category) {
- dat->GetFileSystem().UpdateFileInfo(file);
- }
- }
- dat->GetStatusModule().SetDefaultStatus();
- return DatOperationResult<>(SUCCESS);
- }
- }
|