* Read a particular language. * @param lang The metadata about the language. * @return Whether the loading went okay or not. */
| 2046 | * @return Whether the loading went okay or not. |
| 2047 | */ |
| 2048 | bool ReadLanguagePack(const LanguageMetadata *lang) |
| 2049 | { |
| 2050 | /* Current language pack */ |
| 2051 | size_t total_len = 0; |
| 2052 | std::unique_ptr<LanguagePack, LanguagePackDeleter> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(FS2OTTD(lang->file.native()), total_len, 1U << 20).release())); |
| 2053 | if (!lang_pack) return false; |
| 2054 | |
| 2055 | /* End of read data (+ terminating zero added in ReadFileToMem()) */ |
| 2056 | const char *end = (char *)lang_pack.get() + total_len + 1; |
| 2057 | |
| 2058 | /* We need at least one byte of lang_pack->data */ |
| 2059 | if (end <= lang_pack->data || !lang_pack->IsValid()) { |
| 2060 | return false; |
| 2061 | } |
| 2062 | |
| 2063 | std::array<uint, TEXT_TAB_END> tab_start, tab_num; |
| 2064 | |
| 2065 | uint count = 0; |
| 2066 | for (uint i = 0; i < TEXT_TAB_END; i++) { |
| 2067 | uint16_t num = FROM_LE16(lang_pack->offsets[i]); |
| 2068 | if (num > TAB_SIZE) return false; |
| 2069 | |
| 2070 | tab_start[i] = count; |
| 2071 | tab_num[i] = num; |
| 2072 | count += num; |
| 2073 | } |
| 2074 | |
| 2075 | /* Allocate offsets */ |
| 2076 | std::vector<std::string_view> strings; |
| 2077 | |
| 2078 | /* Fill offsets */ |
| 2079 | char *s = lang_pack->data; |
| 2080 | for (uint i = 0; i < count; i++) { |
| 2081 | size_t len = static_cast<uint8_t>(*s++); |
| 2082 | if (s + len >= end) return false; |
| 2083 | |
| 2084 | if (len >= 0xC0) { |
| 2085 | len = ((len & 0x3F) << 8) + static_cast<uint8_t>(*s++); |
| 2086 | if (s + len >= end) return false; |
| 2087 | } |
| 2088 | strings.emplace_back(s, len); |
| 2089 | s += len; |
| 2090 | } |
| 2091 | assert(strings.size() == count); |
| 2092 | |
| 2093 | _langpack.langpack = std::move(lang_pack); |
| 2094 | _langpack.strings = std::move(strings); |
| 2095 | _langpack.langtab_num = tab_num; |
| 2096 | _langpack.langtab_start = tab_start; |
| 2097 | |
| 2098 | _current_language = lang; |
| 2099 | _current_text_dir = (TextDirection)_current_language->text_dir; |
| 2100 | _config_language_file = FS2OTTD(_current_language->file.filename().native()); |
| 2101 | SetCurrentGrfLangID(_current_language->newgrflangid); |
| 2102 | _langpack.list_separator = GetString(STR_LIST_SEPARATOR); |
| 2103 | _langpack.ellipsis = GetString(STR_TRUNCATION_ELLIPSIS); |
| 2104 | |
| 2105 | #ifdef _WIN32 |
no test coverage detected