|
@@ -35,91 +35,82 @@ namespace LOTRO_DAT {
|
|
|
* 4 * inactive_categories.size() bytes for inactive_categories data
|
|
|
* ========================================
|
|
|
* Помимо этого:
|
|
|
- * 0x128-0x12C - Флаг, установлена ли альтернативная версия (flag)
|
|
|
+ * 0x128-0x12C - 0, если .dat файл не был изменен библиотекой, обновление клиентом игры не испортит .dat file
|
|
|
+ * 1, если активна локаль ORIGINAL, обновление клиентом игры не испортит .dat file
|
|
|
+ * 2, если активна локаль PATCHED, обновление клиентом игры может испортить .dat file
|
|
|
+ *
|
|
|
* 0x12C-0x130 - Офсет начала словаря локализации (offset)
|
|
|
*
|
|
|
- * \warning Если flag != 0 и offset == 0 - то dat файл считается повреждённым. Проверка осуществляется функцией CheckLocaleCorrectж
|
|
|
+ * \warning Если flag != 0 и offset == 0 - то dat файл считается повреждённым. Проверка осуществляется функцией CheckLocaleCorrect
|
|
|
*/
|
|
|
|
|
|
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;
|
|
|
+ ClearData();
|
|
|
|
|
|
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");
|
|
|
- }
|
|
|
+
|
|
|
+ if (!CheckLocaleCorrect()) {
|
|
|
+ return DatOperationResult<>(ERROR, "LOCALEINIT: Check locale correct failed!");
|
|
|
}
|
|
|
|
|
|
+ BinaryData locale_dict_offset_data(4);
|
|
|
+ dat->GetIO().ReadData(locale_dict_offset_data, 4, 0x12C);
|
|
|
+ dict_offset_ = locale_dict_offset_data.ToNumber<4>(0);
|
|
|
+
|
|
|
BinaryData locale_info(16);
|
|
|
- dat->GetIO().ReadData(locale_info, 16, locale_offset);
|
|
|
+ auto operation = dat->GetIO().ReadData(locale_info, 16, dict_offset_);
|
|
|
+ if (!operation.result) {
|
|
|
+ ClearData();
|
|
|
+ LOG(INFO) << "LOCALEINIT: Locale offset is incorrect, skipping initialization.";
|
|
|
+ return DatOperationResult<>(SUCCESS);
|
|
|
+ }
|
|
|
|
|
|
- long long dict_size = locale_info.ToNumber<4>(0);
|
|
|
+ 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");
|
|
|
+ ClearData();
|
|
|
+ LOG(WARNING) << "LOCALEINIT: Locale dictionary version is outdated, skipping initialization.";
|
|
|
+ return DatOperationResult<>(SUCCESS);
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
+ ClearData();
|
|
|
+ LOG(WARNING) << "LOCALEINIT: Locale header hash does not match real dat file header hash, skipping initialization.";
|
|
|
+ return DatOperationResult<>(SUCCESS);
|
|
|
}
|
|
|
|
|
|
- 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 dicts_data = BinaryData((unsigned)dict_size_);
|
|
|
+ dat->GetIO().ReadData(dicts_data, dict_size_ - 16, dict_offset_ + 16);
|
|
|
|
|
|
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').");
|
|
|
+ if (hi != "Hi from Gi1dor!") {
|
|
|
+ ClearData();
|
|
|
+ LOG(WARNING) << "LOCALEINIT: couldn't receive Hello, skipping initialization.";
|
|
|
+ return DatOperationResult<>(SUCCESS);
|
|
|
+ }
|
|
|
|
|
|
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).");
|
|
|
+ if (locale != "PATC" && locale != "ORIG") {
|
|
|
+ ClearData();
|
|
|
+ LOG(WARNING) << "LOCALEINIT: locale status in dict seems incorrect, skipping initialization.";
|
|
|
+ return DatOperationResult<>(SUCCESS);
|
|
|
+ }
|
|
|
|
|
|
current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
|
|
|
-
|
|
|
+ offset += 4;
|
|
|
+
|
|
|
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);
|
|
@@ -147,21 +138,12 @@ namespace LOTRO_DAT {
|
|
|
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";
|
|
|
+ LOG(INFO) << "Successfully 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");
|
|
|
- }
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
/*!
|
|
@@ -173,16 +155,15 @@ namespace LOTRO_DAT {
|
|
|
*/
|
|
|
|
|
|
DatOperationResult<> DatLocaleManager::SetLocale(DatLocaleManager::LOCALE locale) {
|
|
|
- if (dat->GetStatusModule().GetStatus() == DatStatus::E_FREE)
|
|
|
+ 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.";
|
|
@@ -250,9 +231,6 @@ namespace LOTRO_DAT {
|
|
|
|
|
|
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;
|
|
@@ -343,6 +321,8 @@ namespace LOTRO_DAT {
|
|
|
/*!
|
|
|
* \Author Gi1dor
|
|
|
* \date 06.07.2018
|
|
|
+ * TODO: update descr
|
|
|
+ *
|
|
|
* Осуществляет проверку корректности dat файла с позиции локалей
|
|
|
* Файл считается некорректным, если активной является альтернативная локаль, причём нет возможности вернуть оригинальную (блок локалей неверный/повреждён)
|
|
|
* Байты 0x128-0x12C равны 0, если на момент пользования патчером активна оригинальная локаль, и DatIO::file_size, если нет
|
|
@@ -350,37 +330,80 @@ namespace LOTRO_DAT {
|
|
|
*/
|
|
|
|
|
|
bool DatLocaleManager::CheckLocaleCorrect() {
|
|
|
- BinaryData locale_info(4);
|
|
|
- dat->GetIO().ReadData(locale_info, 4, 296);
|
|
|
- long long locale_status = locale_info.ToNumber<4>(0);
|
|
|
+ BinaryData patch_mark_data(4);
|
|
|
+ dat->GetIO().ReadData(patch_mark_data, 4, 0x128);
|
|
|
+ uint32_t patch_mark = patch_mark_data.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;
|
|
|
+ LOG(INFO) << "CHCKLOCALECORRECT: patch mark = " << patch_mark << ", locale_offset = " << locale_offset;
|
|
|
|
|
|
- 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;
|
|
|
+ if (patch_mark == 0 && locale_offset == 0) {
|
|
|
+ LOG(INFO) << "CHCKLOCALECORRECT: No file patch info found, check successfull!";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- BinaryData locale_data = dicts_data + BinaryData("\0", 1);
|
|
|
- std::string locale((char *) (locale_data.data()));
|
|
|
+ if (patch_mark == 0 && locale_offset != 0) {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Locale dict exists, but patch mark is incorrect!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- LOCALE dat_locale = (locale == "PATC" ? PATCHED : ORIGINAL);
|
|
|
+ if (patch_mark != 0 && locale_offset == 0) {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Locale offset is null, but patch mark exists!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (patch_mark == 1) {
|
|
|
+ LOG(INFO) << "CHCKLOCALECORRECT: Header is fine, patch mark is original, so skipping dat locale dict correctness check";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- if ((locale_status == 0 && dat_locale == PATCHED) || (locale_status != 0 && dat_locale == ORIGINAL)) {
|
|
|
- LOG(ERROR) << "CHCKLOCALECORRECT: Locale status and current_locale doesn't match!";
|
|
|
+ if (patch_mark != 2) {
|
|
|
+ LOG(INFO) << "CHCKLOCALECORRECT: Patch mark is invalid! Found " << patch_mark << ", expected: 0, 1 or 2!";
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if (locale_status != 0 && locale_status != dat->GetIO().GetHeaderHash()){
|
|
|
- LOG(ERROR) << "CHCKLOCALECORRECT: Locale hash doesn't match!";
|
|
|
+ // for this moment patch_mark is 2, file should be patched and current locale should be PATCHED
|
|
|
+
|
|
|
+ BinaryData locale_dict_header(16 + 15 + 4);
|
|
|
+ auto operation = dat->GetIO().ReadData(locale_dict_header, 16 + 15 + 4, locale_offset);
|
|
|
+
|
|
|
+ if (!operation.result) {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: incorrect locale offset (cannot read data at offset" << locale_offset << ")";
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ long long dict_version = locale_dict_header.ToNumber<4>(4);
|
|
|
+ long long dat_header_hashsum = locale_dict_header.ToNumber<4>(12);
|
|
|
+ BinaryData hi_data = locale_dict_header.CutData(16, 16 + 15) + BinaryData("\0", 1);
|
|
|
+ std::string hi_string = std::string((char *) (hi_data.data()));
|
|
|
+
|
|
|
+ BinaryData current_locale_data = locale_dict_header.CutData(16 + 15, 16 + 15 + 4) + BinaryData("\0", 1);
|
|
|
+ std::string locale_string = std::string((char *) (current_locale_data.data()));
|
|
|
+
|
|
|
+ if (dict_version != DAT_LOCALE_DICT_VERSION) {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Locale dict version is incorrect, through patch mark shows, that file was patched. Found version:" << dict_version << " expected: " << DAT_LOCALE_DICT_VERSION;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (locale_string != "PATC") {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Data in locales' dictionary is incorrect (dictionary locale mark is invalid). Found: " << locale_string << " expected: PATC";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hi_string != "Hi from Gi1dor!") {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Data in locales' dictionary is incorrect (couldn't receive 'Hello').";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dat_header_hashsum != dat->GetIO().GetHeaderHash()) {
|
|
|
+ LOG(ERROR) << "CHCKLOCALECORRECT: Dat header checksum from header does not match dat header checksum from locale dictionary!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG(INFO) << "CHCKLOCALECORRECT: All checks passed successfully, no errors found!";
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -444,9 +467,9 @@ namespace LOTRO_DAT {
|
|
|
* 4 * inactive_categories.size() bytes for inactive_categories data
|
|
|
* ========================================
|
|
|
* Помимо этого:
|
|
|
- * 0x128-0x12C - 0, если выбрана локаль ORIGINAL и обновление клиентом игры не испортит .dat file
|
|
|
- * хэш хедера файла в противном случае.
|
|
|
- * Отличие значения в 0x128 от 0 и значения в 0x148 => файл ресурсов мог быть повреждён
|
|
|
+ * 0x128-0x12C - 0, если .dat файл не был изменен библиотекой, обновление клиентом игры не испортит .dat file
|
|
|
+ * 1, если активна локаль ORIGINAL, обновление клиентом игры не испортит .dat file
|
|
|
+ * 2, если активна локаль PATCHED, обновление клиентом игры может испортить .dat file
|
|
|
*
|
|
|
* 0x12C-0x130 - Офсет начала словаря локализации
|
|
|
*/
|
|
@@ -456,8 +479,6 @@ namespace LOTRO_DAT {
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -510,14 +531,7 @@ namespace LOTRO_DAT {
|
|
|
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) {
|
|
|
+ if (binary_data.size() > dict_size_ || dict_offset_ == 0) {
|
|
|
long long new_dict_offset = dat->GetFileSystem().patched_file_end + 16;
|
|
|
|
|
|
// Updating first 16 bytes
|
|
@@ -533,10 +547,10 @@ namespace LOTRO_DAT {
|
|
|
|
|
|
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);
|
|
|
+ if (current_locale_ == ORIGINAL) {
|
|
|
+ dat->GetIO().WriteData(BinaryData::FromNumber<4>(1), 4, 296);
|
|
|
} else {
|
|
|
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
|
|
|
+ dat->GetIO().WriteData(BinaryData::FromNumber<4>(2), 4, 296);
|
|
|
}
|
|
|
dat->GetFileSystem().patched_file_end += binary_data.size();
|
|
|
|
|
@@ -551,13 +565,13 @@ namespace LOTRO_DAT {
|
|
|
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);
|
|
|
+ if (current_locale_ == ORIGINAL) {
|
|
|
+ dat->GetIO().WriteData(BinaryData::FromNumber<4>(1), 4, 296);
|
|
|
} else {
|
|
|
- dat->GetIO().WriteData(BinaryData::FromNumber<4>(0), 4, 296);
|
|
|
+ dat->GetIO().WriteData(BinaryData::FromNumber<4>(2), 4, 296);
|
|
|
}
|
|
|
|
|
|
- auto operation = dat->GetIO().WriteData(binary_data, binary_data.size(), dict_offset);
|
|
|
+ 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);
|
|
@@ -570,10 +584,12 @@ namespace LOTRO_DAT {
|
|
|
}
|
|
|
|
|
|
void DatLocaleManager::ClearData() {
|
|
|
+ dict_size_ = 0;
|
|
|
+ dict_offset_ = 0;
|
|
|
orig_dict_.clear();
|
|
|
patch_dict_.clear();
|
|
|
inactive_categories.clear();
|
|
|
- current_locale_ = LOCALE(-1);
|
|
|
+ current_locale_ = ORIGINAL;
|
|
|
}
|
|
|
|
|
|
DatOperationResult<> DatLocaleManager::EnableCategory(long long category) {
|