Changeset - r24527:d7a4b00784e2
[Not reviewed]
master
0 6 0
Michael Lutz - 3 years ago 2020-12-06 20:11:48
michi@icosahedron.de
Codechange: Use automatic memory management for language pack reading.
6 files changed with 66 insertions and 77 deletions:
0 comments (0 inline, 0 general)
src/fileio.cpp
Show inline comments
 
@@ -1236,28 +1236,27 @@ void SanitizeFilename(char *filename)
 
 * @return Pointer to new memory containing the loaded data, or \c nullptr if loading failed.
 
 * @note If \a maxsize less than the length of the file, loading fails.
 
 */
 
void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
 
std::unique_ptr<char> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize)
 
{
 
	FILE *in = fopen(filename, "rb");
 
	FILE *in = fopen(filename.c_str(), "rb");
 
	if (in == nullptr) return nullptr;
 

	
 
	FileCloser fc(in);
 

	
 
	fseek(in, 0, SEEK_END);
 
	size_t len = ftell(in);
 
	fseek(in, 0, SEEK_SET);
 
	if (len > maxsize) {
 
		fclose(in);
 
		return nullptr;
 
	}
 
	byte *mem = MallocT<byte>(len + 1);
 
	mem[len] = 0;
 
	if (fread(mem, len, 1, in) != 1) {
 
		fclose(in);
 
		free(mem);
 
		return nullptr;
 
	}
 
	fclose(in);
 
	if (len > maxsize) return nullptr;
 

	
 
	*lenp = len;
 
	/* std::unique_ptr assumes new/delete unless a custom deleter is supplied.
 
	 * As we don't want to have to carry that deleter all over the place, use
 
	 * new directly to allocate the memory instead of malloc. */
 
	std::unique_ptr<char> mem(static_cast<char *>(::operator new(len + 1)));
 

	
 
	mem.get()[len] = 0;
 
	if (fread(mem.get(), len, 1, in) != 1) return nullptr;
 

	
 
	lenp = len;
 
	return mem;
 
}
 

	
src/fileio_func.h
Show inline comments
 
@@ -49,7 +49,7 @@ const char *FiosGetScreenshotDir();
 
void SanitizeFilename(char *filename);
 
void AppendPathSeparator(std::string &buf);
 
void DeterminePaths(const char *exe);
 
void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
 
std::unique_ptr<char> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize);
 
bool FileExists(const std::string &filename);
 
bool ExtractTar(const std::string &tar_filename, Subdirectory subdir);
 

	
src/language.h
Show inline comments
 
@@ -103,7 +103,7 @@ extern LanguageList _languages;
 
extern const LanguageMetadata *_current_language;
 

	
 
#ifdef WITH_ICU_I18N
 
extern icu::Collator *_current_collator;
 
extern std::unique_ptr<icu::Collator> _current_collator;
 
#endif /* WITH_ICU_I18N */
 

	
 
bool ReadLanguagePack(const LanguageMetadata *lang);
src/string.cpp
Show inline comments
 
@@ -630,7 +630,7 @@ int strnatcmp(const char *s1, const char
 
	}
 

	
 
#ifdef WITH_ICU_I18N
 
	if (_current_collator != nullptr) {
 
	if (_current_collator) {
 
		UErrorCode status = U_ZERO_ERROR;
 
		int result = _current_collator->compareUTF8(s1, s2, status);
 
		if (U_SUCCESS(status)) return result;
src/strings.cpp
Show inline comments
 
@@ -41,14 +41,14 @@
 

	
 
#include "safeguards.h"
 

	
 
char _config_language_file[MAX_PATH];             ///< The file (name) stored in the configuration.
 
std::string _config_language_file;                ///< The file (name) stored in the configuration.
 
LanguageList _languages;                          ///< The actual list of language meta data.
 
const LanguageMetadata *_current_language = nullptr; ///< The currently loaded language.
 

	
 
TextDirection _current_text_dir; ///< Text direction of the currently selected language.
 

	
 
#ifdef WITH_ICU_I18N
 
icu::Collator *_current_collator = nullptr;          ///< Collator for the language currently in use.
 
std::unique_ptr<icu::Collator> _current_collator;    ///< Collator for the language currently in use.
 
#endif /* WITH_ICU_I18N */
 

	
 
static uint64 _global_string_params_data[20];     ///< Global array of string parameters. To access, use #SetDParam.
 
@@ -185,10 +185,17 @@ struct LanguagePack : public LanguagePac
 
	char data[]; // list of strings
 
};
 

	
 
static char **_langpack_offs;
 
static LanguagePack *_langpack;
 
static uint _langtab_num[TEXT_TAB_END];   ///< Offset into langpack offs
 
static uint _langtab_start[TEXT_TAB_END]; ///< Offset into langpack offs
 
struct LoadedLanguagePack {
 
	std::unique_ptr<LanguagePack> langpack;
 

	
 
	std::vector<char *> offsets;
 

	
 
	std::array<uint, TEXT_TAB_END> langtab_num;   ///< Offset into langpack offs
 
	std::array<uint, TEXT_TAB_END> langtab_start; ///< Offset into langpack offs
 
};
 

	
 
static LoadedLanguagePack _langpack;
 

	
 
static bool _scan_for_gender_data = false;  ///< Are we scanning for the gender of the current string? (instead of formatting it)
 

	
 

	
 
@@ -199,7 +206,7 @@ const char *GetStringPtr(StringID string
 
		/* 0xD0xx and 0xD4xx IDs have been converted earlier. */
 
		case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
 
		case TEXT_TAB_NEWGRF_START: return GetGRFStringPtr(GetStringIndex(string));
 
		default: return _langpack_offs[_langtab_start[GetStringTab(string)] + GetStringIndex(string)];
 
		default: return _langpack.offsets[_langpack.langtab_start[GetStringTab(string)] + GetStringIndex(string)];
 
	}
 
}
 

	
 
@@ -253,7 +260,7 @@ char *GetStringWithArgs(char *buffr, Str
 
			break;
 
	}
 

	
 
	if (index >= _langtab_num[tab]) {
 
	if (index >= _langpack.langtab_num[tab]) {
 
		if (game_script) {
 
			return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
 
		}
 
@@ -318,7 +325,7 @@ static char *FormatNumber(char *buff, in
 
	for (int i = 0; i < max_digits; i++) {
 
		if (i == max_digits - fractional_digits) {
 
			const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
 
			if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator;
 
			if (decimal_separator == nullptr) decimal_separator = _langpack.langpack->digit_decimal_separator;
 
			buff += seprintf(buff, last, "%s", decimal_separator);
 
		}
 

	
 
@@ -343,7 +350,7 @@ static char *FormatNumber(char *buff, in
 
static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
 
{
 
	const char *separator = _settings_game.locale.digit_group_separator;
 
	if (separator == nullptr) separator = _langpack->digit_group_separator;
 
	if (separator == nullptr) separator = _langpack.langpack->digit_group_separator;
 
	return FormatNumber(buff, number, last, separator, 1, fractional_digits);
 
}
 

	
 
@@ -382,7 +389,7 @@ static char *FormatBytes(char *buff, int
 
	}
 

	
 
	const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
 
	if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator;
 
	if (decimal_separator == nullptr) decimal_separator = _langpack.langpack->digit_decimal_separator;
 

	
 
	if (number < 1024) {
 
		id = 0;
 
@@ -477,7 +484,7 @@ static char *FormatGenericCurrency(char 
 

	
 
	const char *separator = _settings_game.locale.digit_group_separator_currency;
 
	if (separator == nullptr && !StrEmpty(_currency->separator)) separator = _currency->separator;
 
	if (separator == nullptr) separator = _langpack->digit_group_separator_currency;
 
	if (separator == nullptr) separator = _langpack.langpack->digit_group_separator_currency;
 
	buff = FormatNumber(buff, number, last, separator);
 
	buff = strecpy(buff, multiplier, last);
 

	
 
@@ -1721,16 +1728,15 @@ bool LanguagePackHeader::IsValid() const
 
bool ReadLanguagePack(const LanguageMetadata *lang)
 
{
 
	/* Current language pack */
 
	size_t len;
 
	LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
 
	if (lang_pack == nullptr) return false;
 
	size_t len = 0;
 
	std::unique_ptr<LanguagePack> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(lang->file, len, 1U << 20).release()));
 
	if (!lang_pack) return false;
 

	
 
	/* End of read data (+ terminating zero added in ReadFileToMem()) */
 
	const char *end = (char *)lang_pack + len + 1;
 
	const char *end = (char *)lang_pack.get() + len + 1;
 

	
 
	/* We need at least one byte of lang_pack->data */
 
	if (end <= lang_pack->data || !lang_pack->IsValid()) {
 
		free(lang_pack);
 
		return false;
 
	}
 

	
 
@@ -1740,55 +1746,46 @@ bool ReadLanguagePack(const LanguageMeta
 
	}
 
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
 

	
 
	std::array<uint, TEXT_TAB_END> tab_start, tab_num;
 

	
 
	uint count = 0;
 
	for (uint i = 0; i < TEXT_TAB_END; i++) {
 
		uint16 num = lang_pack->offsets[i];
 
		if (num > TAB_SIZE) {
 
			free(lang_pack);
 
			return false;
 
		}
 
		if (num > TAB_SIZE) return false;
 

	
 
		_langtab_start[i] = count;
 
		_langtab_num[i] = num;
 
		tab_start[i] = count;
 
		tab_num[i] = num;
 
		count += num;
 
	}
 

	
 
	/* Allocate offsets */
 
	char **langpack_offs = MallocT<char *>(count);
 
	std::vector<char *> offs(count);
 

	
 
	/* Fill offsets */
 
	char *s = lang_pack->data;
 
	len = (byte)*s++;
 
	for (uint i = 0; i < count; i++) {
 
		if (s + len >= end) {
 
			free(lang_pack);
 
			free(langpack_offs);
 
			return false;
 
		}
 
		if (s + len >= end) return false;
 

	
 
		if (len >= 0xC0) {
 
			len = ((len & 0x3F) << 8) + (byte)*s++;
 
			if (s + len >= end) {
 
				free(lang_pack);
 
				free(langpack_offs);
 
				return false;
 
			}
 
			if (s + len >= end) return false;
 
		}
 
		langpack_offs[i] = s;
 
		offs[i] = s;
 
		s += len;
 
		len = (byte)*s;
 
		*s++ = '\0'; // zero terminate the string
 
	}
 

	
 
	free(_langpack);
 
	_langpack = lang_pack;
 

	
 
	free(_langpack_offs);
 
	_langpack_offs = langpack_offs;
 
	_langpack.langpack = std::move(lang_pack);
 
	_langpack.offsets = std::move(offs);
 
	_langpack.langtab_num = tab_num;
 
	_langpack.langtab_start = tab_start;
 

	
 
	_current_language = lang;
 
	_current_text_dir = (TextDirection)_current_language->text_dir;
 
	const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
 
	strecpy(_config_language_file, c_file, lastof(_config_language_file));
 
	_config_language_file = c_file;
 
	SetCurrentGrfLangID(_current_language->newgrflangid);
 

	
 
#ifdef _WIN32
 
@@ -1802,21 +1799,14 @@ bool ReadLanguagePack(const LanguageMeta
 
#endif
 

	
 
#ifdef WITH_ICU_I18N
 
	/* Delete previous collator. */
 
	if (_current_collator != nullptr) {
 
		delete _current_collator;
 
		_current_collator = nullptr;
 
	}
 

	
 
	/* Create a collator instance for our current locale. */
 
	UErrorCode status = U_ZERO_ERROR;
 
	_current_collator = icu::Collator::createInstance(icu::Locale(_current_language->isocode), status);
 
	_current_collator.reset(icu::Collator::createInstance(icu::Locale(_current_language->isocode), status));
 
	/* Sort number substrings by their numerical value. */
 
	if (_current_collator != nullptr) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
 
	if (_current_collator) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
 
	/* Avoid using the collator if it is not correctly set. */
 
	if (U_FAILURE(status)) {
 
		delete _current_collator;
 
		_current_collator = nullptr;
 
		_current_collator.reset();
 
	}
 
#endif /* WITH_ICU_I18N */
 

	
 
@@ -1978,7 +1968,7 @@ void InitializeLanguagePacks()
 
		 * configuration file, local environment and last, if nothing found,
 
		 * English. */
 
		const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1;
 
		if (strcmp(lang_file, _config_language_file) == 0) {
 
		if (_config_language_file == lang_file) {
 
			chosen_language = &lng;
 
			break;
 
		}
 
@@ -2003,7 +1993,7 @@ void InitializeLanguagePacks()
 
 */
 
const char *GetCurrentLanguageIsoCode()
 
{
 
	return _langpack->isocode;
 
	return _langpack.langpack->isocode;
 
}
 

	
 
/**
 
@@ -2057,10 +2047,10 @@ class LanguagePackGlyphSearcher : public
 
	{
 
		if (this->i >= TEXT_TAB_END) return nullptr;
 

	
 
		const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
 
		const char *ret = _langpack.offsets[_langpack.langtab_start[this->i] + this->j];
 

	
 
		this->j++;
 
		while (this->i < TEXT_TAB_END && this->j >= _langtab_num[this->i]) {
 
		while (this->i < TEXT_TAB_END && this->j >= _langpack.langtab_num[this->i]) {
 
			this->i++;
 
			this->j = 0;
 
		}
 
@@ -2116,7 +2106,7 @@ void CheckForMissingGlyphs(bool base_fon
 
		_freetype.mono.os_handle = nullptr;
 
		_freetype.medium.os_handle = nullptr;
 

	
 
		bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
 
		bad_font = !SetFallbackFont(&_freetype, _langpack.langpack->isocode, _langpack.langpack->winlangid, searcher);
 

	
 
		free(_freetype.mono.os_handle);
 
		free(_freetype.medium.os_handle);
src/table/misc_settings.ini
Show inline comments
 
@@ -5,7 +5,7 @@
 
;
 

	
 
[pre-amble]
 
extern char _config_language_file[MAX_PATH];
 
extern std::string _config_language_file;
 

	
 
static const char *_support8bppmodes = "no|system|hardware";
 

	
 
@@ -107,9 +107,9 @@ type     = SLE_STRQ
 
var      = _ini_blitter
 
def      = nullptr
 

	
 
[SDTG_STR]
 
[SDTG_SSTR]
 
name     = ""language""
 
type     = SLE_STRB
 
type     = SLE_STR
 
var      = _config_language_file
 
def      = nullptr
 
cat      = SC_BASIC
0 comments (0 inline, 0 general)