DatLocaleManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. //
  2. // Created by kikab on 04.06.2018.
  3. //
  4. #include <DatSubsystems/DatLocaleManager.h>
  5. #include <EasyLogging++/easylogging++.h>
  6. #include <DatFile.h>
  7. #include <SubFile.h>
  8. namespace LOTRO_DAT {
  9. DatLocaleManager::DatLocaleManager(DatFile *datFilePtr) : dat(datFilePtr), current_locale_(ORIGINAL) {
  10. }
  11. DatOperationResult<> DatLocaleManager::Init() {
  12. if (!dat)
  13. return DatOperationResult<>(ERROR, "LOCALEINIT: no connection with Dat (dat is nullptr)");
  14. orig_dict_.clear();
  15. patch_dict_.clear();
  16. LOG(INFO) << "Initialising locales...";
  17. BinaryData locale_offset_data(4);
  18. dat->getIO().ReadData(locale_offset_data, 4, 300);
  19. long long locale_offset = locale_offset_data.ToNumber<4>(0);
  20. if (locale_offset == 0 || locale_offset + 8 >= dat->getIO().GetActualDatSize()) {
  21. LOG(INFO) << "Dictionary offset is empty or incorrect. Passing.";
  22. return DatOperationResult<>();
  23. }
  24. BinaryData locale_info(12);
  25. dat->getIO().ReadData(locale_info, 12, locale_offset);
  26. long long dict_size = locale_info.ToNumber<4>(0);
  27. long long dict_version = locale_info.ToNumber<4>(4);
  28. dat->getIO().file_size = locale_info.ToNumber<4>(8);
  29. LOG(INFO) << "Dictionary size is " << dict_size << ". Version is " << dict_version << ". Localed .dat size = " << dat->getIO().file_size;
  30. if (dict_version != 101) {
  31. LOG(WARNING) << "DICTIONARY IS OLD! Version = " << dict_version;
  32. dat->getIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
  33. return DatOperationResult<>(ERROR, "Version of locales' dictionary is old (ver = " + std::to_string(dict_version) + "), cannot work with this type of .dat file.");
  34. }
  35. BinaryData dicts_data = BinaryData((unsigned)dict_size);
  36. dat->getIO().ReadData(dicts_data, dict_size, locale_offset + 12);
  37. if (dicts_data.size() < 15) {
  38. dat->getIO().WriteData(BinaryData::FromNumber<4>(0), 4, 300);
  39. return DatOperationResult<>(ERROR, "INITLOCALE: Data in locales' dictionary is incorrect.");
  40. }
  41. BinaryData hi_data = dicts_data.CutData(0, 15) + BinaryData("\0", 1);
  42. std::string hi = std::string((char *) (hi_data.data()));
  43. if (hi != "Hi from Gi1dor!")
  44. return DatOperationResult<>(ERROR, "INITLOCALE: Data in locales' dictionary is incorrect (couldn't receive 'Hello').");
  45. int offset = 15;
  46. BinaryData current_locale_data = dicts_data.CutData(offset, offset + 4) + BinaryData("\0", 1);
  47. std::string locale((char *) (current_locale_data.data()));
  48. offset += 4;
  49. if (locale != "PATC" && locale != "ORIG")
  50. return DatOperationResult<>(ERROR, "INITLOCALE: Data in locales' dictionary is incorrect (current locale mark is invalid).");
  51. current_locale_ = (locale == "PATC" ? PATCHED : ORIGINAL);
  52. size_t orig_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
  53. offset += 4;
  54. for (size_t i = 0; i < orig_dict_size; i++) {
  55. auto file = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
  56. file.category = dicts_data.ToNumber<4>(offset);
  57. orig_dict_[file.file_id()] = file;
  58. offset += 36;
  59. }
  60. size_t patch_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
  61. offset += 4;
  62. for (size_t i = 0; i < patch_dict_size; i++) {
  63. auto file = SubFile(*dat, dicts_data.CutData(offset, offset + 32));
  64. file.category = dicts_data.ToNumber<4>(offset);
  65. orig_dict_[file.file_id()] = file;
  66. offset += 36;
  67. }
  68. LOG(INFO) << "There are " << patch_dict_.size() << " files in patch locale dictionary";
  69. LOG(INFO) << "There are " << orig_dict_.size() << " files in original locale dictionary";
  70. LOG(INFO) << "Finished initialising locales";
  71. return DatOperationResult<>(SUCCESS);
  72. }
  73. DatOperationResult<> DatLocaleManager::SetLocale(DatLocaleManager::LOCALE locale) {
  74. LOG(INFO) << "Setting locale to " << (locale == PATCHED ? " PATCHED" : " ORIGINAL");
  75. if (!dat)
  76. return DatOperationResult<>(ERROR, "SETLOCALE: no connection with Dat (dat is nullptr)");
  77. if (current_locale_ == locale) {
  78. LOG(INFO) << "Locale is already " << locale << ", nothing to do.";
  79. return DatOperationResult<>(SUCCESS);
  80. }
  81. auto dict = GetLocaleDictReference(locale);
  82. for (const auto &file : dict) {
  83. long long file_id = file.first;
  84. auto dict_file_result = dat->getFileSystem().GetFile(file_id);
  85. if (dict_file_result.result != SUCCESS) {
  86. LOG(WARNING) << "Unable to get file with id = " << file_id << "from datFileSystem!";
  87. dict.erase(file_id);
  88. continue;
  89. }
  90. std::shared_ptr<SubFile> dict_file = dict_file_result.value;
  91. if (dict_file->MakeHeaderData().CutData(8, 16) == file.second.MakeHeaderData().CutData(8, 16))
  92. continue;
  93. dat->getFileSystem().UpdateFileInfo(file.second);
  94. }
  95. current_locale_ = locale;
  96. return DatOperationResult<>(SUCCESS);
  97. }
  98. DatLocaleManager::LOCALE DatLocaleManager::GetCurrentLocale() {
  99. return current_locale_;
  100. }
  101. DatOperationResult<> DatLocaleManager::DeInit() {
  102. LOG(INFO) << "Committing locales...";
  103. if (!dat)
  104. return DatOperationResult<>(ERROR, "LOCALEDEINIT: no connection with Dat (dat is nullptr)");
  105. BinaryData binary_data = BinaryData(4 + 4 + 4 + 14 + 15 + 4
  106. + 4 + (32 + 4) * orig_dict_.size()
  107. + 4 + (32 + 4) * patch_dict_.size()
  108. + 4 + 4 * inactive_categories.size());
  109. size_t current_size = 0;
  110. binary_data.Append(BinaryData::FromNumber<4>(std::max(binary_data.size() + 4, 20u * 1024u * 1024u)));
  111. binary_data.Append(BinaryData::FromNumber<4>(101));
  112. binary_data.Append(BinaryData::FromNumber<4>(dat->getIO().file_size + binary_data.size() + 12 + 20 * 1024 * 1024));
  113. current_size = 12;
  114. binary_data.Append(BinaryData("Hi from Gi1dor!", 15), current_size);
  115. current_size += 15;
  116. binary_data.Append(BinaryData((current_locale_ == ORIGINAL ? "ORIG" : "PATC"), 4), current_size);
  117. current_size += 4;
  118. binary_data.Append(BinaryData::FromNumber<4>(orig_dict_.size()), current_size);
  119. current_size += 4;
  120. for (const auto &file : orig_dict_) {
  121. binary_data.Append(file.second.MakeHeaderData(), current_size);
  122. current_size += 32;
  123. binary_data.Append(BinaryData::FromNumber<4>(file.second.category), current_size);
  124. current_size += 4;
  125. }
  126. binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
  127. current_size += 4;
  128. for (const auto &file : patch_dict_) {
  129. binary_data.Append(file.second.MakeHeaderData(), current_size);
  130. current_size += 32;
  131. binary_data.Append(BinaryData::FromNumber<4>(file.second.category), current_size);
  132. current_size += 4;
  133. }
  134. binary_data.Append(BinaryData::FromNumber<4>(inactive_categories.size()), current_size);
  135. current_size += 4;
  136. for (auto patch_id : inactive_categories) {
  137. binary_data.Append(BinaryData::FromNumber<4>(patch_id), current_size);
  138. current_size += 4;
  139. }
  140. BinaryData dicts_data(4);
  141. dat->getIO().ReadData(dicts_data, 4, 300);
  142. long long dict_offset = dicts_data.ToNumber<4>(0);
  143. dat->getIO().ReadData(dicts_data, 4, dict_offset);
  144. long long dict_size = dicts_data.ToNumber<4>(0);
  145. if (binary_data.size() > dict_size || dict_offset == 0) {
  146. auto operation = dat->getIO().WriteData(binary_data, binary_data.size(), dat->getIO().file_size + 12);
  147. if (operation.result != SUCCESS)
  148. return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales. ERRMSG: " + operation.msg);
  149. dat->getIO().WriteData(BinaryData::FromNumber<4>(dat->getIO().file_size), 4, 300);
  150. dat->getIO().file_size += binary_data.size();
  151. // Adding space for 20 megabytes locales file in total.
  152. BinaryData nulls(unsigned(20 * 1024 * 1024));
  153. dat->getIO().WriteData(nulls, nulls.size(), dat->getIO().file_size);
  154. dat->getIO().file_size += nulls.size();
  155. } else {
  156. auto operation = dat->getIO().WriteData(binary_data, binary_data.size(), dict_offset);
  157. if (operation.result != SUCCESS)
  158. return DatOperationResult<>(ERROR, "LOCALEDEINIT: Cannot write locales. ERRMSG: " + operation.msg);
  159. }
  160. LOG(INFO) << "Locales commited successfully";
  161. return DatOperationResult<>(SUCCESS);
  162. }
  163. void DatLocaleManager::UpdateLocaleFile(DatLocaleManager::LOCALE locale, const SubFile &file) {
  164. auto dict = GetLocaleDictReference(locale);
  165. dict[file.file_id()] = file;
  166. }
  167. DatOperationResult<SubFile> DatLocaleManager::GetLocaleFile(long long file_id, DatLocaleManager::LOCALE locale) {
  168. auto dict = GetLocaleDictReference(locale);
  169. if (dict.count(file_id) != 0)
  170. return DatOperationResult<SubFile>(SubFile(), ERROR, "GETLOCFILE: cannot get file with id = " + std::to_string(file_id) + " from dict " + std::to_string(locale));
  171. return DatOperationResult<SubFile>(dict[file_id], SUCCESS);
  172. }
  173. std::map<long long, SubFile> &DatLocaleManager::GetLocaleDictReference(DatLocaleManager::LOCALE locale) {
  174. return locale == PATCHED ? patch_dict_ : orig_dict_;
  175. }
  176. void DatLocaleManager::PrintInformaion(FILE *file) {
  177. fprintf(file, "========= Locales info ========\n");
  178. BinaryData locale_offset_data(4);
  179. dat->getIO().ReadData(locale_offset_data, 4, 300);
  180. long long locale_offset = locale_offset_data.ToNumber<4>(0);
  181. fprintf(file, "Locales' dictionary offset = %lld\n", locale_offset);
  182. if (locale_offset != 0) {
  183. BinaryData locale_info(12);
  184. dat->getIO().ReadData(locale_info, 12, locale_offset);
  185. long long dict_size = locale_info.ToNumber<4>(0);
  186. long long dict_version = locale_info.ToNumber<4>(4);
  187. fprintf(file, "Locales' dictionary size = %lld, version = %lld\n", dict_size, dict_version);
  188. dat->getIO().file_size = locale_info.ToNumber<4>(8);
  189. }
  190. fprintf(file, "Current locale id = %d\n", current_locale_);
  191. fprintf(file, "Patch dictionary size = %d\n", patch_dict_.size());
  192. fprintf(file, "Original dictionary size = %d\n", orig_dict_.size());
  193. }
  194. }