# strings.cpp

Go to the documentation of this file.

    00001 /* $Id: strings.cpp 25502 2013-06-28 19:44:28Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "currency.h"
    00014 #include "station_base.h"
    00015 #include "town.h"
    00016 #include "screenshot.h"
    00017 #include "waypoint_base.h"
    00018 #include "depot_base.h"
    00019 #include "industry.h"
    00020 #include "newgrf_text.h"
    00021 #include "fileio_func.h"
    00022 #include "signs_base.h"
    00023 #include "fontdetection.h"
    00024 #include "error.h"
    00025 #include "strings_func.h"
    00026 #include "rev.h"
    00027 #include "core/endian_func.hpp"
    00028 #include "date_func.h"
    00029 #include "vehicle_base.h"
    00030 #include "engine_base.h"
    00031 #include "language.h"
    00032 #include "townname_func.h"
    00033 #include "string_func.h"
    00034 #include "company_base.h"
    00035 #include "smallmap_gui.h"
    00036 #include "window_func.h"
    00037 #include "debug.h"
    00038 #include "game/game_text.hpp"
    00039 #include <stack>
    00040
    00041 #include "table/strings.h"
    00042 #include "table/control_codes.h"
    00043
    00044 char _config_language_file[MAX_PATH];
    00045 LanguageList _languages;
    00046 const LanguageMetadata *_current_language = NULL;
    00047
    00048 TextDirection _current_text_dir;
    00049
    00050 #ifdef WITH_ICU
    00051 Collator *_current_collator = NULL;
    00052 #endif /* WITH_ICU */
    00053
    00054 static uint64 _global_string_params_data[20];
    00055 static WChar _global_string_params_type[20];
    00056 StringParameters _global_string_params(_global_string_params_data, 20, _global_string_params_type);
    00057
    00059 void StringParameters::ClearTypeInformation()
    00060 {
    00061   assert(this->type != NULL);
    00062   MemSetT(this->type, 0, this->num_param);
    00063 }
    00064
    00065
    00070 int64 StringParameters::GetInt64(WChar type)
    00071 {
    00072   if (this->offset >= this->num_param) {
    00073     DEBUG(misc, 0, "Trying to read invalid string parameter");
    00074     return 0;
    00075   }
    00076   if (this->type != NULL) {
    00077     assert(this->type[this->offset] == 0 || this->type[this->offset] == type);
    00078     this->type[this->offset] = type;
    00079   }
    00080   return this->data[this->offset++];
    00081 }
    00082
    00087 void StringParameters::ShiftParameters(uint amount)
    00088 {
    00089   assert(amount <= this->num_param);
    00090   MemMoveT(this->data + amount, this->data, this->num_param - amount);
    00091 }
    00092
    00101 void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
    00102 {
    00103   uint num_digits = 1;
    00104   while (max_value >= 10) {
    00105     num_digits++;
    00106     max_value /= 10;
    00107   }
    00108   SetDParamMaxDigits(n, max(min_count, num_digits), size);
    00109 }
    00110
    00117 void SetDParamMaxDigits(uint n, uint count, FontSize size)
    00118 {
    00119   uint front, next;
    00120   GetBroadestDigit(&front, &next, size);
    00121   uint64 val = count > 1 ? front : next;
    00122   for (; count > 1; count--) {
    00123     val = 10 * val + next;
    00124   }
    00125   SetDParam(n, val);
    00126 }
    00127
    00134 void CopyInDParam(int offs, const uint64 *src, int num)
    00135 {
    00136   MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num);
    00137 }
    00138
    00145 void CopyOutDParam(uint64 *dst, int offs, int num)
    00146 {
    00147   MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num);
    00148 }
    00149
    00158 void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num)
    00159 {
    00160   char buf[DRAW_STRING_BUFFER];
    00161   GetString(buf, string, lastof(buf));
    00162
    00163   MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num);
    00164   for (int i = 0; i < num; i++) {
    00165     if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) {
    00166       strings[i] = strdup((const char *)(size_t)_global_string_params.GetParam(i));
    00167       dst[i] = (size_t)strings[i];
    00168     } else {
    00169       strings[i] = NULL;
    00170     }
    00171   }
    00172 }
    00173
    00174 static char *StationGetSpecialString(char *buff, int x, const char *last);
    00175 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
    00176 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
    00177
    00178 static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false);
    00179
    00180 struct LanguagePack : public LanguagePackHeader {
    00181   char data[]; // list of strings
    00182 };
    00183
    00184 static char **_langpack_offs;
    00185 static LanguagePack *_langpack;
    00186 static uint _langtab_num[TAB_COUNT];
    00187 static uint _langtab_start[TAB_COUNT];
    00188 static bool _scan_for_gender_data = false;
    00189
    00190
    00191 const char *GetStringPtr(StringID string)
    00192 {
    00193   switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
    00194     case GAME_TEXT_TAB: return GetGameStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
    00195     /* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
    00196     case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, TAB_SIZE_OFFSET, 10)));
    00197     case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
    00198     case 29: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x0800);
    00199     case 30: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x1000);
    00200     default: return _langpack_offs[_langtab_start[GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)] + GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)];
    00201   }
    00202 }
    00203
    00214 char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
    00215 {
    00216   if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
    00217
    00218   uint index = GB(string, TAB_SIZE_OFFSET,  TAB_SIZE_BITS);
    00219   uint tab   = GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS);
    00220
    00221   switch (tab) {
    00222     case 4:
    00223       if (index >= 0xC0 && !game_script) {
    00224         return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
    00225       }
    00226       break;
    00227
    00228     case 14:
    00229       if (index >= 0xE4 && !game_script) {
    00230         return GetSpecialNameString(buffr, index - 0xE4, args, last);
    00231       }
    00232       break;
    00233
    00234     case 15:
    00235       /* Old table for custom names. This is no longer used */
    00236       error("Incorrect conversion of custom name string.");
    00237
    00238     case GAME_TEXT_TAB:
    00239       return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
    00240
    00241     case 26:
    00242       /* Include string within newgrf text (format code 81) */
    00243       if (HasBit(index, 10)) {
    00244         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
    00245         return GetStringWithArgs(buffr, string, args, last, case_index);
    00246       }
    00247       break;
    00248
    00249     case 28:
    00250       return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
    00251
    00252     case 29:
    00253       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), args, last, case_index);
    00254
    00255     case 30:
    00256       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), args, last, case_index);
    00257
    00258     case 31:
    00259       NOT_REACHED();
    00260   }
    00261
    00262   if (index >= _langtab_num[tab]) {
    00263     if (game_script) {
    00264       return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
    00265     }
    00266     error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
    00267   }
    00268
    00269   return FormatString(buffr, GetStringPtr(string), args, last, case_index);
    00270 }
    00271
    00272 char *GetString(char *buffr, StringID string, const char *last)
    00273 {
    00274   _global_string_params.ClearTypeInformation();
    00275   _global_string_params.offset = 0;
    00276   return GetStringWithArgs(buffr, string, &_global_string_params, last);
    00277 }
    00278
    00279
    00280 char *InlineString(char *buf, StringID string)
    00281 {
    00282   buf += Utf8Encode(buf, SCC_STRING_ID);
    00283   buf += Utf8Encode(buf, string);
    00284   return buf;
    00285 }
    00286
    00287
    00293 void SetDParamStr(uint n, const char *str)
    00294 {
    00295   SetDParam(n, (uint64)(size_t)str);
    00296 }
    00297
    00302 void InjectDParam(uint amount)
    00303 {
    00304   _global_string_params.ShiftParameters(amount);
    00305 }
    00306
    00318 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0)
    00319 {
    00320   static const int max_digits = 20;
    00321   uint64 divisor = 10000000000000000000ULL;
    00322   zerofill += fractional_digits;
    00323   int thousands_offset = (max_digits - fractional_digits - 1) % 3;
    00324
    00325   if (number < 0) {
    00326     buff += seprintf(buff, last, "-");
    00327     number = -number;
    00328   }
    00329
    00330   uint64 num = number;
    00331   uint64 tot = 0;
    00332   for (int i = 0; i < max_digits; i++) {
    00333     if (i == max_digits - fractional_digits) {
    00334       const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00335       if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00336       buff += seprintf(buff, last, "%s", decimal_separator);
    00337     }
    00338
    00339     uint64 quot = 0;
    00340     if (num >= divisor) {
    00341       quot = num / divisor;
    00342       num = num % divisor;
    00343     }
    00344     if ((tot |= quot) || i >= max_digits - zerofill) {
    00345       buff += seprintf(buff, last, "%i", (int)quot);
    00346       if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last);
    00347     }
    00348
    00349     divisor /= 10;
    00350   }
    00351
    00352   *buff = '\0';
    00353
    00354   return buff;
    00355 }
    00356
    00357 static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
    00358 {
    00359   const char *separator = _settings_game.locale.digit_group_separator;
    00360   if (separator == NULL) separator = _langpack->digit_group_separator;
    00361   return FormatNumber(buff, number, last, separator, 1, fractional_digits);
    00362 }
    00363
    00364 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
    00365 {
    00366   return FormatNumber(buff, number, last, "");
    00367 }
    00368
    00369 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
    00370 {
    00371   return FormatNumber(buff, number, last, "", count);
    00372 }
    00373
    00374 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
    00375 {
    00376   return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
    00377 }
    00378
    00386 static char *FormatBytes(char *buff, int64 number, const char *last)
    00387 {
    00388   assert(number >= 0);
    00389
    00390   /*                                   1   2^10  2^20  2^30  2^40  2^50  2^60 */
    00391   const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
    00392   uint id = 1;
    00393   while (number >= 1024 * 1024) {
    00394     number /= 1024;
    00395     id++;
    00396   }
    00397
    00398   const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00399   if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00400
    00401   if (number < 1024) {
    00402     id = 0;
    00403     buff += seprintf(buff, last, "%i", (int)number);
    00404   } else if (number < 1024 * 10) {
    00405     buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
    00406   } else if (number < 1024 * 100) {
    00407     buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
    00408   } else {
    00409     assert(number < 1024 * 1024);
    00410     buff += seprintf(buff, last, "%i", (int)number / 1024);
    00411   }
    00412
    00413   assert(id < lengthof(iec_prefixes));
    00414   buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
    00415
    00416   return buff;
    00417 }
    00418
    00419 static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index)
    00420 {
    00421   YearMonthDay ymd;
    00422   ConvertDateToYMD(date, &ymd);
    00423
    00424   int64 args[] = {ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
    00425   StringParameters tmp_params(args);
    00426   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
    00427 }
    00428
    00429 static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index)
    00430 {
    00431   YearMonthDay ymd;
    00432   ConvertDateToYMD(date, &ymd);
    00433
    00434   int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
    00435   StringParameters tmp_params(args);
    00436   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
    00437 }
    00438
    00439 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
    00440 {
    00441   YearMonthDay ymd;
    00442   ConvertDateToYMD(date, &ymd);
    00443
    00444   char day[3];
    00445   char month[3];
    00446   /* We want to zero-pad the days and months */
    00447   snprintf(day,   lengthof(day),   "%02i", ymd.day);
    00448   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
    00449
    00450   int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year};
    00451   StringParameters tmp_params(args);
    00452   return FormatString(buff, GetStringPtr(str), &tmp_params, last);
    00453 }
    00454
    00455 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
    00456 {
    00457   /* We are going to make number absolute for printing, so
    00458    * keep this piece of data as we need it later on */
    00459   bool negative = number < 0;
    00460   const char *multiplier = "";
    00461
    00462   number *= spec->rate;
    00463
    00464   /* convert from negative */
    00465   if (number < 0) {
    00466     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
    00467     buff += Utf8Encode(buff, SCC_RED);
    00468     buff = strecpy(buff, "-", last);
    00469     number = -number;
    00470   }
    00471
    00472   /* Add prefix part, following symbol_pos specification.
    00473    * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
    00474    * The only remaining value is 1 (suffix), so everything that is not 1 */
    00475   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
    00476
    00477   /* for huge numbers, compact the number into k or M */
    00478   if (compact) {
    00479     /* Take care of the 'k' rounding. Having 1 000 000 k
    00480      * and 1 000 M is inconsistent, so always use 1 000 M. */
    00481     if (number >= 1000000000 - 500) {
    00482       number = (number + 500000) / 1000000;
    00483       multiplier = "M";
    00484     } else if (number >= 1000000) {
    00485       number = (number + 500) / 1000;
    00486       multiplier = "k";
    00487     }
    00488   }
    00489
    00490   const char *separator = _settings_game.locale.digit_group_separator_currency;
    00491   if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
    00492   if (separator == NULL) separator = _langpack->digit_group_separator_currency;
    00493   buff = FormatNumber(buff, number, last, separator);
    00494   buff = strecpy(buff, multiplier, last);
    00495
    00496   /* Add suffix part, following symbol_pos specification.
    00497    * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
    00498    * The only remaining value is 1 (prefix), so everything that is not 0 */
    00499   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
    00500
    00501   if (negative) {
    00502     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
    00503     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
    00504     *buff = '\0';
    00505   }
    00506
    00507   return buff;
    00508 }
    00509
    00516 static int DeterminePluralForm(int64 count, int plural_form)
    00517 {
    00518   /* The absolute value determines plurality */
    00519   uint64 n = abs(count);
    00520
    00521   switch (plural_form) {
    00522     default:
    00523       NOT_REACHED();
    00524
    00525     /* Two forms: singular used for one only.
    00526      * Used in:
    00527      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
    00528      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
    00529     case 0:
    00530       return n != 1 ? 1 : 0;
    00531
    00532     /* Only one form.
    00533      * Used in:
    00534      *   Hungarian, Japanese, Korean, Turkish */
    00535     case 1:
    00536       return 0;
    00537
    00538     /* Two forms: singular used for 0 and 1.
    00539      * Used in:
    00540      *   French, Brazilian Portuguese */
    00541     case 2:
    00542       return n > 1 ? 1 : 0;
    00543
    00544     /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
    00545      * Note: Cases are out of order for hysterical reasons. '0' is last.
    00546      * Used in:
    00547      *   Latvian */
    00548     case 3:
    00549       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
    00550
    00551     /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
    00552      * Used in:
    00553      *   Gaelige (Irish) */
    00554     case 4:
    00555       return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
    00556
    00557     /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19.
    00558      * Used in:
    00559      *   Lithuanian */
    00560     case 5:
    00561       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00562
    00563     /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14.
    00564      * Used in:
    00565      *   Croatian, Russian, Ukrainian */
    00566     case 6:
    00567       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00568
    00569     /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
    00570      * Used in:
    00571      *   Polish */
    00572     case 7:
    00573       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00574
    00575     /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
    00576      * Used in:
    00577      *   Slovenian */
    00578     case 8:
    00579       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
    00580
    00581     /* Two forms: singular used for numbers ending in 1 except when ending in 11.
    00582      * Used in:
    00583      *   Icelandic */
    00584     case 9:
    00585       return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
    00586
    00587     /* Three forms: special cases for 1, and 2 to 4
    00588      * Used in:
    00589      *   Czech, Slovak */
    00590     case 10:
    00591       return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
    00592
    00593     /* Two forms: cases for numbers ending with a consonant, and with a vowel.
    00594      * Korean doesn't have the concept of plural, but depending on how a
    00595      * number is pronounced it needs another version of a particle.
    00596      * As such the plural system is misused to give this distinction.
    00597      */
    00598     case 11:
    00599       switch (n % 10) {
    00600         case 0: // yeong
    00601         case 1: // il
    00602         case 3: // sam
    00603         case 6: // yuk
    00604         case 7: // chil
    00605         case 8: // pal
    00606           return 0;
    00607
    00608         case 2: // i
    00609         case 4: // sa
    00610         case 5: // o
    00611         case 9: // gu
    00612           return 1;
    00613
    00614         default:
    00615           NOT_REACHED();
    00616       }
    00617
    00618     /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
    00619      * Used in:
    00620      *  Maltese */
    00621     case 12:
    00622       return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
    00623     /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
    00624      * Used in:
    00625      *  Scottish Gaelic */
    00626     case 13:
    00627       return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
    00628   }
    00629 }
    00630
    00631 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
    00632 {
    00633   /* <NUM> {Length of each string} {each string} */
    00634   uint n = (byte)*b++;
    00635   uint pos, i, mypos = 0;
    00636
    00637   for (i = pos = 0; i != n; i++) {
    00638     uint len = (byte)*b++;
    00639     if (i == form) mypos = pos;
    00640     pos += len;
    00641   }
    00642
    00643   *dst += seprintf(*dst, last, "%s", b + mypos);
    00644   return b + pos;
    00645 }
    00646
    00648 struct UnitConversion {
    00649   int multiplier;
    00650   int shift;
    00651
    00658   int64 ToDisplay(int64 input, bool round = true) const
    00659   {
    00660     return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
    00661   }
    00662
    00670   int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
    00671   {
    00672     return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
    00673   }
    00674 };
    00675
    00676 struct Units {
    00677   UnitConversion c_velocity;
    00678   StringID velocity;
    00679   UnitConversion c_power;
    00680   StringID power;
    00681   UnitConversion c_weight;
    00682   StringID s_weight;
    00683   StringID l_weight;
    00684   UnitConversion c_volume;
    00685   StringID s_volume;
    00686   StringID l_volume;
    00687   UnitConversion c_force;
    00688   StringID force;
    00689   UnitConversion c_height;
    00690   StringID height;
    00691 };
    00692
    00693 /* Unit conversions */
    00694 static const Units _units[] = {
    00695   { // Imperial (Original, mph, hp, metric ton, litre, kN, ft)
    00696     {   1,  0}, STR_UNITS_VELOCITY_IMPERIAL,
    00697     {   1,  0}, STR_UNITS_POWER_IMPERIAL,
    00698     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00699     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00700     {   1,  0}, STR_UNITS_FORCE_SI,
    00701     {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL, // "Wrong" conversion factor for more nicer GUI values
    00702   },
    00703   { // Metric (km/h, hp, metric ton, litre, kN, metre)
    00704     { 103,  6}, STR_UNITS_VELOCITY_METRIC,
    00705     {4153, 12}, STR_UNITS_POWER_METRIC,
    00706     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00707     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00708     {   1,  0}, STR_UNITS_FORCE_SI,
    00709     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00710   },
    00711   { // SI (m/s, kilowatt, kilogram, cubic metre, kilonewton, metre)
    00712     {1831, 12}, STR_UNITS_VELOCITY_SI,
    00713     {6109, 13}, STR_UNITS_POWER_SI,
    00714     {1000,  0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
    00715     {   1,  0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
    00716     {   1,  0}, STR_UNITS_FORCE_SI,
    00717     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00718   },
    00719 };
    00720
    00726 uint ConvertSpeedToDisplaySpeed(uint speed)
    00727 {
    00728   /* For historical reasons we don't want to mess with the
    00729    * conversion for speed. So, don't round it and keep the
    00730    * original conversion factors instead of the real ones. */
    00731   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed, false);
    00732 }
    00733
    00739 uint ConvertDisplaySpeedToSpeed(uint speed)
    00740 {
    00741   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed);
    00742 }
    00743
    00749 uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
    00750 {
    00751   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed * 10, false) / 16;
    00752 }
    00753
    00759 uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
    00760 {
    00761   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed * 16, true, 10);
    00762 }
    00772 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
    00773 {
    00774   uint orig_offset = args->offset;
    00775
    00776   /* When there is no array with types there is no need to do a dry run. */
    00777   if (args->HasTypeInformation() && !dry_run) {
    00778     if (UsingNewGRFTextStack()) {
    00779       /* Values from the NewGRF text stack are only copied to the normal
    00780        * argv array at the time they are encountered. That means that if
    00781        * another string command references a value later in the string it
    00782        * would fail. We solve that by running FormatString twice. The first
    00783        * pass makes sure the argv array is correctly filled and the second
    00784        * pass can reference later values without problems. */
    00785       struct TextRefStack *backup = CreateTextRefStackBackup();
    00786       FormatString(buff, str_arg, args, last, case_index, game_script, true);
    00787       RestoreTextRefStackBackup(backup);
    00788     } else {
    00789       FormatString(buff, str_arg, args, last, case_index, game_script, true);
    00790     }
    00791     /* We have to restore the original offset here to to read the correct values. */
    00792     args->offset = orig_offset;
    00793   }
    00794   WChar b;
    00795   uint next_substr_case_index = 0;
    00796   char *buf_start = buff;
    00797   std::stack<const char *> str_stack;
    00798   str_stack.push(str_arg);
    00799
    00800   for (;;) {
    00801     while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
    00802       str_stack.pop();
    00803     }
    00804     if (str_stack.empty()) break;
    00805     const char *&str = str_stack.top();
    00806
    00807     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
    00808       /* We need to pass some stuff as it might be modified; oh boy. */
    00809       //todo: should argve be passed here too?
    00810       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), dry_run);
    00811       if (b == 0) continue;
    00812     }
    00813
    00814     switch (b) {
    00815       case SCC_ENCODED: {
    00816         uint64 sub_args_data[20];
    00817         WChar sub_args_type[20];
    00818         bool sub_args_need_free[20];
    00819         StringParameters sub_args(sub_args_data, 20, sub_args_type);
    00820
    00821         sub_args.ClearTypeInformation();
    00822         memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
    00823
    00824         uint16 stringid;
    00825         const char *s = str;
    00826         char *p;
    00827         stringid = strtol(str, &p, 16);
    00828         if (*p != ':' && *p != '\0') {
    00829           while (*p != '\0') p++;
    00830           str = p;
    00831           buff = strecat(buff, "(invalid SCC_ENCODED)", last);
    00832           break;
    00833         }
    00834         if (stringid >= TAB_SIZE) {
    00835           while (*p != '\0') p++;
    00836           str = p;
    00837           buff = strecat(buff, "(invalid StringID)", last);
    00838           break;
    00839         }
    00840
    00841         int i = 0;
    00842         while (*p != '\0' && i < 20) {
    00843           uint64 param;
    00844           s = ++p;
    00845
    00846           /* Find the next value */
    00847           bool instring = false;
    00848           bool escape = false;
    00849           for (;; p++) {
    00850             if (*p == '\\') {
    00851               escape = true;
    00852               continue;
    00853             }
    00854             if (*p == '"' && escape) {
    00855               escape = false;
    00856               continue;
    00857             }
    00858             escape = false;
    00859
    00860             if (*p == '"') {
    00861               instring = !instring;
    00862               continue;
    00863             }
    00864             if (instring) {
    00865               continue;
    00866             }
    00867
    00868             if (*p == ':') break;
    00869             if (*p == '\0') break;
    00870           }
    00871
    00872           if (*s != '"') {
    00873             /* Check if we want to look up another string */
    00874             WChar l;
    00875             size_t len = Utf8Decode(&l, s);
    00876             bool lookup = (l == SCC_ENCODED);
    00877             if (lookup) s += len;
    00878
    00879             param = (int32)strtoul(s, &p, 16);
    00880
    00881             if (lookup) {
    00882               if (param >= TAB_SIZE) {
    00883                 while (*p != '\0') p++;
    00884                 str = p;
    00885                 buff = strecat(buff, "(invalid sub-StringID)", last);
    00886                 break;
    00887               }
    00888               param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param;
    00889             }
    00890
    00891             sub_args.SetParam(i++, param);
    00892           } else {
    00893             char *g = strdup(s);
    00894             g[p - s] = '\0';
    00895
    00896             sub_args_need_free[i] = true;
    00897             sub_args.SetParam(i++, (uint64)(size_t)g);
    00898           }
    00899         }
    00900         /* If we didn't error out, we can actually print the string. */
    00901         if (*str != '\0') {
    00902           str = p;
    00903           buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
    00904         }
    00905
    00906         for (int i = 0; i < 20; i++) {
    00907           if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
    00908         }
    00909         break;
    00910       }
    00911
    00912       case SCC_NEWGRF_STRINL: {
    00913         StringID substr = Utf8Consume(&str);
    00914         str_stack.push(GetStringPtr(substr));
    00915         break;
    00916       }
    00917
    00918       case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
    00919         StringID substr = args->GetInt32(SCC_NEWGRF_PRINT_WORD_STRING_ID);
    00920         str_stack.push(GetStringPtr(substr));
    00921         case_index = next_substr_case_index;
    00922         next_substr_case_index = 0;
    00923         break;
    00924       }
    00925
    00926
    00927       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
    00928         /* First read the meta data from the language file. */
    00929         uint offset = orig_offset + (byte)*str++;
    00930         int gender = 0;
    00931         if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
    00932           /* Now we need to figure out what text to resolve, i.e.
    00933            * what do we need to draw? So get the actual raw string
    00934            * first using the control code to get said string. */
    00935           char input[4 + 1];
    00936           char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
    00937           *p = '\0';
    00938
    00939           /* Now do the string formatting. */
    00940           char buf[256];
    00941           bool old_sgd = _scan_for_gender_data;
    00942           _scan_for_gender_data = true;
    00943           StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
    00944           p = FormatString(buf, input, &tmp_params, lastof(buf));
    00945           _scan_for_gender_data = old_sgd;
    00946           *p = '\0';
    00947
    00948           /* And determine the string. */
    00949           const char *s = buf;
    00950           WChar c = Utf8Consume(&s);
    00951           /* Does this string have a gender, if so, set it */
    00952           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00953         }
    00954         str = ParseStringChoice(str, gender, &buff, last);
    00955         break;
    00956       }
    00957
    00958       /* This sets up the gender for the string.
    00959        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00960       case SCC_GENDER_INDEX: // {GENDER 0}
    00961         if (_scan_for_gender_data) {
    00962           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
    00963           *buff++ = *str++;
    00964         } else {
    00965           str++;
    00966         }
    00967         break;
    00968
    00969       case SCC_PLURAL_LIST: { // {P}
    00970         int plural_form = *str++;          // contains the plural form for this string
    00971         uint offset = orig_offset + (byte)*str++;
    00972         int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
    00973         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
    00974         break;
    00975       }
    00976
    00977       case SCC_ARG_INDEX: { // Move argument pointer
    00978         args->offset = orig_offset + (byte)*str++;
    00979         break;
    00980       }
    00981
    00982       case SCC_SET_CASE: { // {SET_CASE}
    00983         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    00984          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    00985         next_substr_case_index = (byte)*str++;
    00986         break;
    00987       }
    00988
    00989       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    00990         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    00991          * Each LEN is printed using 2 bytes in big endian order. */
    00992         uint num = (byte)*str++;
    00993         while (num) {
    00994           if ((byte)str[0] == case_index) {
    00995             /* Found the case, adjust str pointer and continue */
    00996             str += 3;
    00997             break;
    00998           }
    00999           /* Otherwise skip to the next case */
    01000           str += 3 + (str[1] << 8) + str[2];
    01001           num--;
    01002         }
    01003         break;
    01004       }
    01005
    01006       case SCC_REVISION: // {REV}
    01007         buff = strecpy(buff, _openttd_revision, last);
    01008         break;
    01009
    01010       case SCC_STRING_ID: // {STRINL}
    01011         if (game_script) break;
    01012         buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
    01013         break;
    01014
    01015       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
    01016         if (game_script) break;
    01017         const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
    01018         buff = FormatString(buff, str, args, last);
    01019         break;
    01020       }
    01021
    01022       case SCC_STRING: {// {STRING}
    01023         StringID str = args->GetInt32(SCC_STRING);
    01024         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
    01025         /* WARNING. It's prohibited for the included string to consume any arguments.
    01026          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    01027          * To debug stuff you can set argv to NULL and it will tell you */
    01028         StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
    01029         buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
    01030         next_substr_case_index = 0;
    01031         break;
    01032       }
    01033
    01034       case SCC_STRING1:
    01035       case SCC_STRING2:
    01036       case SCC_STRING3:
    01037       case SCC_STRING4:
    01038       case SCC_STRING5:
    01039       case SCC_STRING6:
    01040       case SCC_STRING7: { // {STRING1..7}
    01041         /* Strings that consume arguments */
    01042         StringID str = args->GetInt32(b);
    01043         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
    01044         uint size = b - SCC_STRING1 + 1;
    01045         if (game_script && size > args->num_param - args->offset) {
    01046           buff = strecat(buff, "(too many parameters)", last);
    01047         } else {
    01048           StringParameters sub_args(*args, size);
    01049           buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
    01050         }
    01051         next_substr_case_index = 0;
    01052         break;
    01053       }
    01054
    01055       case SCC_COMMA: // {COMMA}
    01056         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
    01057         break;
    01058
    01059       case SCC_DECIMAL: {// {DECIMAL}
    01060         int64 number = args->GetInt64(SCC_DECIMAL);
    01061         int digits = args->GetInt32(SCC_DECIMAL);
    01062         buff = FormatCommaNumber(buff, number, last, digits);
    01063         break;
    01064       }
    01065
    01066       case SCC_NUM: // {NUM}
    01067         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
    01068         break;
    01069
    01070       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    01071         int64 num = args->GetInt64();
    01072         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
    01073         break;
    01074       }
    01075
    01076       case SCC_HEX: // {HEX}
    01077         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
    01078         break;
    01079
    01080       case SCC_BYTES: // {BYTES}
    01081         buff = FormatBytes(buff, args->GetInt64(), last);
    01082         break;
    01083
    01084       case SCC_CARGO_TINY: { // {CARGO_TINY}
    01085         /* Tiny description of cargotypes. Layout:
    01086          * param 1: cargo type
    01087          * param 2: cargo count */
    01088         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
    01089         if (cargo >= CargoSpec::GetArraySize()) break;
    01090
    01091         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01092         int64 amount = 0;
    01093         switch (cargo_str) {
    01094           case STR_TONS:
    01095             amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
    01096             break;
    01097
    01098           case STR_LITERS:
    01099             amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
    01100             break;
    01101
    01102           default: {
    01103             amount = args->GetInt64();
    01104             break;
    01105           }
    01106         }
    01107
    01108         buff = FormatCommaNumber(buff, amount, last);
    01109         break;
    01110       }
    01111
    01112       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
    01113         /* Short description of cargotypes. Layout:
    01114          * param 1: cargo type
    01115          * param 2: cargo count */
    01116         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
    01117         if (cargo >= CargoSpec::GetArraySize()) break;
    01118
    01119         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01120         switch (cargo_str) {
    01121           case STR_TONS: {
    01122             assert(_settings_game.locale.units < lengthof(_units));
    01123             int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01124             StringParameters tmp_params(args_array);
    01125             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01126             break;
    01127           }
    01128
    01129           case STR_LITERS: {
    01130             assert(_settings_game.locale.units < lengthof(_units));
    01131             int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01132             StringParameters tmp_params(args_array);
    01133             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01134             break;
    01135           }
    01136
    01137           default: {
    01138             StringParameters tmp_params(*args, 1);
    01139             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
    01140             break;
    01141           }
    01142         }
    01143         break;
    01144       }
    01145
    01146       case SCC_CARGO_LONG: { // {CARGO_LONG}
    01147         /* First parameter is cargo type, second parameter is cargo count */
    01148         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
    01149         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
    01150
    01151         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    01152         StringParameters tmp_args(*args, 1);
    01153         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
    01154         break;
    01155       }
    01156
    01157       case SCC_CARGO_LIST: { // {CARGO_LIST}
    01158         uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
    01159         bool first = true;
    01160
    01161         const CargoSpec *cs;
    01162         FOR_ALL_SORTED_CARGOSPECS(cs) {
    01163           if (!HasBit(cmask, cs->Index())) continue;
    01164
    01165           if (buff >= last - 2) break; // ',' and ' '
    01166
    01167           if (first) {
    01168             first = false;
    01169           } else {
    01170             /* Add a comma if this is not the first item */
    01171             *buff++ = ',';
    01172             *buff++ = ' ';
    01173           }
    01174
    01175           buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
    01176         }
    01177
    01178         /* If first is still true then no cargo is accepted */
    01179         if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
    01180
    01181         *buff = '\0';
    01182         next_substr_case_index = 0;
    01183
    01184         /* Make sure we detect any buffer overflow */
    01185         assert(buff < last);
    01186         break;
    01187       }
    01188
    01189       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
    01190         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
    01191         break;
    01192
    01193       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
    01194         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
    01195         break;
    01196
    01197       case SCC_DATE_TINY: // {DATE_TINY}
    01198         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
    01199         break;
    01200
    01201       case SCC_DATE_SHORT: // {DATE_SHORT}
    01202         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
    01203         next_substr_case_index = 0;
    01204         break;
    01205
    01206       case SCC_DATE_LONG: // {DATE_LONG}
    01207         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
    01208         next_substr_case_index = 0;
    01209         break;
    01210
    01211       case SCC_DATE_ISO: // {DATE_ISO}
    01212         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
    01213         break;
    01214
    01215       case SCC_FORCE: { // {FORCE}
    01216         assert(_settings_game.locale.units < lengthof(_units));
    01217         int64 args_array[1] = {_units[_settings_game.locale.units].c_force.ToDisplay(args->GetInt64())};
    01218         StringParameters tmp_params(args_array);
    01219         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), &tmp_params, last);
    01220         break;
    01221       }
    01222
    01223       case SCC_HEIGHT: { // {HEIGHT}
    01224         int64 args_array[] = {_units[_settings_game.locale.units].c_height.ToDisplay(args->GetInt64())};
    01225         StringParameters tmp_params(args_array);
    01226         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), &tmp_params, last);
    01227         break;
    01228       }
    01229
    01230       case SCC_POWER: { // {POWER}
    01231         assert(_settings_game.locale.units < lengthof(_units));
    01232         int64 args_array[1] = {_units[_settings_game.locale.units].c_power.ToDisplay(args->GetInt64())};
    01233         StringParameters tmp_params(args_array);
    01234         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), &tmp_params, last);
    01235         break;
    01236       }
    01237
    01238       case SCC_VELOCITY: { // {VELOCITY}
    01239         assert(_settings_game.locale.units < lengthof(_units));
    01240         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
    01241         StringParameters tmp_params(args_array);
    01242         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), &tmp_params, last);
    01243         break;
    01244       }
    01245
    01246       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
    01247         assert(_settings_game.locale.units < lengthof(_units));
    01248         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01249         StringParameters tmp_params(args_array);
    01250         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), &tmp_params, last);
    01251         break;
    01252       }
    01253
    01254       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
    01255         assert(_settings_game.locale.units < lengthof(_units));
    01256         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
    01257         StringParameters tmp_params(args_array);
    01258         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01259         break;
    01260       }
    01261
    01262       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
    01263         assert(_settings_game.locale.units < lengthof(_units));
    01264         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01265         StringParameters tmp_params(args_array);
    01266         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), &tmp_params, last);
    01267         break;
    01268       }
    01269
    01270       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
    01271         assert(_settings_game.locale.units < lengthof(_units));
    01272         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
    01273         StringParameters tmp_params(args_array);
    01274         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01275         break;
    01276       }
    01277
    01278       case SCC_COMPANY_NAME: { // {COMPANY}
    01279         const Company *c = Company::GetIfValid(args->GetInt32());
    01280         if (c == NULL) break;
    01281
    01282         if (c->name != NULL) {
    01283           int64 args_array[] = {(uint64)(size_t)c->name};
    01284           StringParameters tmp_params(args_array);
    01285           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01286         } else {
    01287           int64 args_array[] = {c->name_2};
    01288           StringParameters tmp_params(args_array);
    01289           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
    01290         }
    01291         break;
    01292       }
    01293
    01294       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
    01295         CompanyID company = (CompanyID)args->GetInt32();
    01296
    01297         /* Nothing is added for AI or inactive companies */
    01298         if (Company::IsValidHumanID(company)) {
    01299           int64 args_array[] = {company + 1};
    01300           StringParameters tmp_params(args_array);
    01301           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
    01302         }
    01303         break;
    01304       }
    01305
    01306       case SCC_DEPOT_NAME: { // {DEPOT}
    01307         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
    01308         if (vt == VEH_AIRCRAFT) {
    01309           uint64 args_array[] = {args->GetInt32()};
    01310           WChar types_array[] = {SCC_STATION_NAME};
    01311           StringParameters tmp_params(args_array, 1, types_array);
    01312           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
    01313           break;
    01314         }
    01315
    01316         const Depot *d = Depot::Get(args->GetInt32());
    01317         if (d->name != NULL) {
    01318           int64 args_array[] = {(uint64)(size_t)d->name};
    01319           StringParameters tmp_params(args_array);
    01320           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01321         } else {
    01322           int64 args_array[] = {d->town->index, d->town_cn + 1};
    01323           StringParameters tmp_params(args_array);
    01324           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
    01325         }
    01326         break;
    01327       }
    01328
    01329       case SCC_ENGINE_NAME: { // {ENGINE}
    01330         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
    01331         if (e == NULL) break;
    01332
    01333         if (e->name != NULL && e->IsEnabled()) {
    01334           int64 args_array[] = {(uint64)(size_t)e->name};
    01335           StringParameters tmp_params(args_array);
    01336           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01337         } else {
    01338           StringParameters tmp_params(NULL, 0, NULL);
    01339           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
    01340         }
    01341         break;
    01342       }
    01343
    01344       case SCC_GROUP_NAME: { // {GROUP}
    01345         const Group *g = Group::GetIfValid(args->GetInt32());
    01346         if (g == NULL) break;
    01347
    01348         if (g->name != NULL) {
    01349           int64 args_array[] = {(uint64)(size_t)g->name};
    01350           StringParameters tmp_params(args_array);
    01351           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01352         } else {
    01353           int64 args_array[] = {g->index};
    01354           StringParameters tmp_params(args_array);
    01355
    01356           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
    01357         }
    01358         break;
    01359       }
    01360
    01361       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    01362         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
    01363         if (i == NULL) break;
    01364
    01365         if (_scan_for_gender_data) {
    01366           /* Gender is defined by the industry type.
    01367            * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
    01368           StringParameters tmp_params(NULL, 0, NULL);
    01369           buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
    01370         } else {
    01371           /* First print the town name and the industry type name. */
    01372           int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
    01373           StringParameters tmp_params(args_array);
    01374
    01375           buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
    01376         }
    01377         next_substr_case_index = 0;
    01378         break;
    01379       }
    01380
    01381       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
    01382         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
    01383         if (c == NULL) break;
    01384
    01385         if (c->president_name != NULL) {
    01386           int64 args_array[] = {(uint64)(size_t)c->president_name};
    01387           StringParameters tmp_params(args_array);
    01388           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01389         } else {
    01390           int64 args_array[] = {c->president_name_2};
    01391           StringParameters tmp_params(args_array);
    01392           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
    01393         }
    01394         break;
    01395       }
    01396
    01397       case SCC_STATION_NAME: { // {STATION}
    01398         StationID sid = args->GetInt32(SCC_STATION_NAME);
    01399         const Station *st = Station::GetIfValid(sid);
    01400
    01401         if (st == NULL) {
    01402           /* The station doesn't exist anymore. The only place where we might
    01403            * be "drawing" an invalid station is in the case of cargo that is
    01404            * in transit. */
    01405           StringParameters tmp_params(NULL, 0, NULL);
    01406           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
    01407           break;
    01408         }
    01409
    01410         if (st->name != NULL) {
    01411           int64 args_array[] = {(uint64)(size_t)st->name};
    01412           StringParameters tmp_params(args_array);
    01413           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01414         } else {
    01415           StringID str = st->string_id;
    01416           if (st->indtype != IT_INVALID) {
    01417             /* Special case where the industry provides the name for the station */
    01418             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    01419
    01420             /* Industry GRFs can change which might remove the station name and
    01421              * thus cause very strange things. Here we check for that before we
    01422              * actually set the station name. */
    01423             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    01424               str = indsp->station_name;
    01425             }
    01426           }
    01427
    01428           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
    01429           StringParameters tmp_params(args_array);
    01430           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01431         }
    01432         break;
    01433       }
    01434
    01435       case SCC_TOWN_NAME: { // {TOWN}
    01436         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
    01437         if (t == NULL) break;
    01438
    01439         if (t->name != NULL) {
    01440           int64 args_array[] = {(uint64)(size_t)t->name};
    01441           StringParameters tmp_params(args_array);
    01442           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01443         } else {
    01444           buff = GetTownName(buff, t, last);
    01445         }
    01446         break;
    01447       }
    01448
    01449       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    01450         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
    01451         if (wp == NULL) break;
    01452
    01453         if (wp->name != NULL) {
    01454           int64 args_array[] = {(uint64)(size_t)wp->name};
    01455           StringParameters tmp_params(args_array);
    01456           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01457         } else {
    01458           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
    01459           StringParameters tmp_params(args_array);
    01460           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    01461           if (wp->town_cn != 0) str++;
    01462           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01463         }
    01464         break;
    01465       }
    01466
    01467       case SCC_VEHICLE_NAME: { // {VEHICLE}
    01468         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
    01469         if (v == NULL) break;
    01470
    01471         if (v->name != NULL) {
    01472           int64 args_array[] = {(uint64)(size_t)v->name};
    01473           StringParameters tmp_params(args_array);
    01474           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01475         } else {
    01476           int64 args_array[] = {v->unitnumber};
    01477           StringParameters tmp_params(args_array);
    01478
    01479           StringID str;
    01480           switch (v->type) {
    01481             default: NOT_REACHED();
    01482             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    01483             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    01484             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    01485             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    01486           }
    01487
    01488           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01489         }
    01490         break;
    01491       }
    01492
    01493       case SCC_SIGN_NAME: { // {SIGN}
    01494         const Sign *si = Sign::GetIfValid(args->GetInt32());
    01495         if (si == NULL) break;
    01496
    01497         if (si->name != NULL) {
    01498           int64 args_array[] = {(uint64)(size_t)si->name};
    01499           StringParameters tmp_params(args_array);
    01500           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01501         } else {
    01502           StringParameters tmp_params(NULL, 0, NULL);
    01503           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
    01504         }
    01505         break;
    01506       }
    01507
    01508       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    01509         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
    01510         break;
    01511       }
    01512
    01513       default:
    01514         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01515         break;
    01516     }
    01517   }
    01518   *buff = '\0';
    01519   return buff;
    01520 }
    01521
    01522
    01523 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01524 {
    01525   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01526   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01527   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01528   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01529   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01530   *buff = '\0';
    01531   return buff;
    01532 }
    01533
    01534 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01535 {
    01536   return GenerateTownNameString(buff, last, ind, seed);
    01537 }
    01538
    01539 static const char * const _silly_company_names[] = {
    01540   "Bloggs Brothers",
    01541   "Tiny Transport Ltd.",
    01542   "Express Travel",
    01543   "Comfy-Coach & Co.",
    01544   "Crush & Bump Ltd.",
    01545   "Broken & Late Ltd.",
    01546   "Sam Speedy & Son",
    01547   "Supersonic Travel",
    01548   "Mike's Motors",
    01549   "Lightning International",
    01550   "Pannik & Loozit Ltd.",
    01551   "Inter-City Transport",
    01552   "Getout & Pushit Ltd."
    01553 };
    01554
    01555 static const char * const _surname_list[] = {
    01556   "Adams",
    01557   "Allan",
    01558   "Baker",
    01559   "Bigwig",
    01560   "Black",
    01561   "Bloggs",
    01562   "Brown",
    01563   "Campbell",
    01564   "Gordon",
    01565   "Hamilton",
    01566   "Hawthorn",
    01567   "Higgins",
    01568   "Green",
    01569   "Gribble",
    01570   "Jones",
    01571   "McAlpine",
    01572   "MacDonald",
    01573   "McIntosh",
    01574   "Muir",
    01575   "Murphy",
    01576   "Nelson",
    01577   "O'Donnell",
    01578   "Parker",
    01579   "Phillips",
    01580   "Pilkington",
    01581   "Quigley",
    01582   "Sharkey",
    01583   "Thomson",
    01584   "Watkins"
    01585 };
    01586
    01587 static const char * const _silly_surname_list[] = {
    01588   "Grumpy",
    01589   "Dozy",
    01590   "Speedy",
    01591   "Nosey",
    01592   "Dribble",
    01593   "Mushroom",
    01594   "Cabbage",
    01595   "Sniffle",
    01596   "Fishy",
    01597   "Swindle",
    01598   "Sneaky",
    01599   "Nutkins"
    01600 };
    01601
    01602 static const char _initial_name_letters[] = {
    01603   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01604   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01605 };
    01606
    01607 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01608 {
    01609   const char * const *base;
    01610   uint num;
    01611
    01612   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01613     base = _silly_surname_list;
    01614     num  = lengthof(_silly_surname_list);
    01615   } else {
    01616     base = _surname_list;
    01617     num  = lengthof(_surname_list);
    01618   }
    01619
    01620   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01621   buff = strecpy(buff, " & Co.", last);
    01622
    01623   return buff;
    01624 }
    01625
    01626 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01627 {
    01628   char initial[] = "?. ";
    01629   const char * const *base;
    01630   uint num;
    01631   uint i;
    01632
    01633   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01634   buff = strecpy(buff, initial, last);
    01635
    01636   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01637   if (i < sizeof(_initial_name_letters)) {
    01638     initial[0] = _initial_name_letters[i];
    01639     buff = strecpy(buff, initial, last);
    01640   }
    01641
    01642   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01643     base = _silly_surname_list;
    01644     num  = lengthof(_silly_surname_list);
    01645   } else {
    01646     base = _surname_list;
    01647     num  = lengthof(_surname_list);
    01648   }
    01649
    01650   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01651
    01652   return buff;
    01653 }
    01654
    01655 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
    01656 {
    01657   switch (ind) {
    01658     case 1: // not used
    01659       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
    01660
    01661     case 2: // used for Foobar & Co company names
    01662       return GenAndCoName(buff, args->GetInt32(), last);
    01663
    01664     case 3: // President name
    01665       return GenPresidentName(buff, args->GetInt32(), last);
    01666   }
    01667
    01668   /* town name? */
    01669   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01670     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
    01671     return strecpy(buff, " Transport", last);
    01672   }
    01673
    01674   /* language name? */
    01675   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01676     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01677     return strecpy(buff,
    01678       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
    01679   }
    01680
    01681   /* resolution size? */
    01682   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01683     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01684     buff += seprintf(
    01685       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01686     );
    01687     return buff;
    01688   }
    01689
    01690   /* screenshot format name? */
    01691   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01692     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01693     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01694   }
    01695
    01696   NOT_REACHED();
    01697 }
    01698
    01699 #ifdef ENABLE_NETWORK
    01700 extern void SortNetworkLanguages();
    01701 #else /* ENABLE_NETWORK */
    01702 static inline void SortNetworkLanguages() {}
    01703 #endif /* ENABLE_NETWORK */
    01704
    01709 bool LanguagePackHeader::IsValid() const
    01710 {
    01711   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
    01712          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
    01713          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
    01714          this->text_dir     <= 1 &&
    01715          this->newgrflangid < MAX_LANG &&
    01716          this->num_genders  < MAX_NUM_GENDERS &&
    01717          this->num_cases    < MAX_NUM_CASES &&
    01718          StrValid(this->name,                           lastof(this->name)) &&
    01719          StrValid(this->own_name,                       lastof(this->own_name)) &&
    01720          StrValid(this->isocode,                        lastof(this->isocode)) &&
    01721          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
    01722          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
    01723          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
    01724 }
    01725
    01731 bool ReadLanguagePack(const LanguageMetadata *lang)
    01732 {
    01733   /* Current language pack */
    01734   size_t len;
    01735   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
    01736   if (lang_pack == NULL) return false;
    01737
    01738   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01739   const char *end = (char *)lang_pack + len + 1;
    01740
    01741   /* We need at least one byte of lang_pack->data */
    01742   if (end <= lang_pack->data || !lang_pack->IsValid()) {
    01743     free(lang_pack);
    01744     return false;
    01745   }
    01746
    01747 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01748   for (uint i = 0; i < TAB_COUNT; i++) {
    01749     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01750   }
    01751 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01752
    01753   uint count = 0;
    01754   for (uint i = 0; i < TAB_COUNT; i++) {
    01755     uint num = lang_pack->offsets[i];
    01756     _langtab_start[i] = count;
    01757     _langtab_num[i] = num;
    01758     count += num;
    01759   }
    01760
    01761   /* Allocate offsets */
    01762   char **langpack_offs = MallocT<char *>(count);
    01763
    01764   /* Fill offsets */
    01765   char *s = lang_pack->data;
    01766   len = (byte)*s++;
    01767   for (uint i = 0; i < count; i++) {
    01768     if (s + len >= end) {
    01769       free(lang_pack);
    01770       free(langpack_offs);
    01771       return false;
    01772     }
    01773     if (len >= 0xC0) {
    01774       len = ((len & 0x3F) << 8) + (byte)*s++;
    01775       if (s + len >= end) {
    01776         free(lang_pack);
    01777         free(langpack_offs);
    01778         return false;
    01779       }
    01780     }
    01781     langpack_offs[i] = s;
    01782     s += len;
    01783     len = (byte)*s;
    01784     *s++ = '\0'; // zero terminate the string
    01785   }
    01786
    01787   free(_langpack);
    01788   _langpack = lang_pack;
    01789
    01790   free(_langpack_offs);
    01791   _langpack_offs = langpack_offs;
    01792
    01793   _current_language = lang;
    01794   _current_text_dir = (TextDirection)_current_language->text_dir;
    01795   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
    01796   strecpy(_config_language_file, c_file, lastof(_config_language_file));
    01797   SetCurrentGrfLangID(_current_language->newgrflangid);
    01798
    01799 #ifdef WITH_ICU
    01800   /* Delete previous collator. */
    01801   if (_current_collator != NULL) {
    01802     delete _current_collator;
    01803     _current_collator = NULL;
    01804   }
    01805
    01806   /* Create a collator instance for our current locale. */
    01807   UErrorCode status = U_ZERO_ERROR;
    01808   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
    01809   /* Sort number substrings by their numerical value. */
    01810   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
    01811   /* Avoid using the collator if it is not correctly set. */
    01812   if (U_FAILURE(status)) {
    01813     delete _current_collator;
    01814     _current_collator = NULL;
    01815   }
    01816 #endif /* WITH_ICU */
    01817
    01818   /* Some lists need to be sorted again after a language change. */
    01819   ReconsiderGameScriptLanguage();
    01820   InitializeSortedCargoSpecs();
    01821   SortIndustryTypes();
    01822   BuildIndustriesLegend();
    01823   SortNetworkLanguages();
    01824   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
    01825   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
    01826   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
    01827   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
    01828   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
    01829   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
    01830   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
    01831
    01832   return true;
    01833 }
    01834
    01835 /* Win32 implementation in win32.cpp.
    01836  * OS X implementation in os/macosx/macos.mm. */
    01837 #if !(defined(WIN32) || defined(__APPLE__))
    01838
    01846 const char *GetCurrentLocale(const char *param)
    01847 {
    01848   const char *env;
    01849
    01850   env = getenv("LANGUAGE");
    01851   if (env != NULL) return env;
    01852
    01853   env = getenv("LC_ALL");
    01854   if (env != NULL) return env;
    01855
    01856   if (param != NULL) {
    01857     env = getenv(param);
    01858     if (env != NULL) return env;
    01859   }
    01860
    01861   return getenv("LANG");
    01862 }
    01863 #else
    01864 const char *GetCurrentLocale(const char *param);
    01865 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01866
    01867 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01868 {
    01869   char stra[512];
    01870   char strb[512];
    01871   GetString(stra, *a, lastof(stra));
    01872   GetString(strb, *b, lastof(strb));
    01873
    01874   return strcmp(stra, strb);
    01875 }
    01876
    01882 const LanguageMetadata *GetLanguage(byte newgrflangid)
    01883 {
    01884   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
    01885     if (newgrflangid == lang->newgrflangid) return lang;
    01886   }
    01887
    01888   return NULL;
    01889 }
    01890
    01897 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
    01898 {
    01899   FILE *f = fopen(file, "rb");
    01900   if (f == NULL) return false;
    01901
    01902   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01903   fclose(f);
    01904
    01905   bool ret = read == 1 && hdr->IsValid();
    01906
    01907   /* Convert endianness for the windows language ID */
    01908   if (ret) {
    01909     hdr->missing = FROM_LE16(hdr->missing);
    01910     hdr->winlangid = FROM_LE16(hdr->winlangid);
    01911   }
    01912   return ret;
    01913 }
    01914
    01919 static void GetLanguageList(const char *path)
    01920 {
    01921   DIR *dir = ttd_opendir(path);
    01922   if (dir != NULL) {
    01923     struct dirent *dirent;
    01924     while ((dirent = readdir(dir)) != NULL) {
    01925       const char *d_name    = FS2OTTD(dirent->d_name);
    01926       const char *extension = strrchr(d_name, '.');
    01927
    01928       /* Not a language file */
    01929       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01930
    01931       LanguageMetadata lmd;
    01932       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
    01933
    01934       /* Check whether the file is of the correct version */
    01935       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
    01936         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
    01937       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
    01938         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
    01939       } else {
    01940         *_languages.Append() = lmd;
    01941       }
    01942     }
    01943     closedir(dir);
    01944   }
    01945 }
    01946
    01951 void InitializeLanguagePacks()
    01952 {
    01953   Searchpath sp;
    01954
    01955   FOR_ALL_SEARCHPATHS(sp) {
    01956     char path[MAX_PATH];
    01957     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01958     GetLanguageList(path);
    01959   }
    01960   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
    01961
    01962   /* Acquire the locale of the current system */
    01963   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01964   if (lang == NULL) lang = "en_GB";
    01965
    01966   const LanguageMetadata *chosen_language   = NULL;
    01967   const LanguageMetadata *language_fallback = NULL;
    01968   const LanguageMetadata *en_GB_fallback    = _languages.Begin();
    01969
    01970   /* Find a proper language. */
    01971   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
    01972     /* We are trying to find a default language. The priority is by
    01973      * configuration file, local environment and last, if nothing found,
    01974      * English. */
    01975     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
    01976     if (strcmp(lang_file, _config_language_file) == 0) {
    01977       chosen_language = lng;
    01978       break;
    01979     }
    01980
    01981     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
    01982     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
    01983     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
    01984   }
    01985
    01986   /* We haven't found the language in the config nor the one in the locale.
    01987    * Now we set it to one of the fallback languages */
    01988   if (chosen_language == NULL) {
    01989     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
    01990   }
    01991
    01992   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
    01993 }
    01994
    01999 const char *GetCurrentLanguageIsoCode()
    02000 {
    02001   return _langpack->isocode;
    02002 }
    02003
    02010 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
    02011 {
    02012   InitFreeType(this->Monospace());
    02013   const Sprite *question_mark[FS_END];
    02014
    02015   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
    02016     question_mark[size] = GetGlyph(size, '?');
    02017   }
    02018
    02019   this->Reset();
    02020   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
    02021     FontSize size = this->DefaultSize();
    02022     if (str != NULL) *str = text;
    02023     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
    02024       if (c == SCC_TINYFONT) {
    02025         size = FS_SMALL;
    02026       } else if (c == SCC_BIGFONT) {
    02027         size = FS_LARGE;
    02028       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
    02029         /* The character is printable, but not in the normal font. This is the case we were testing for. */
    02030         return true;
    02031       }
    02032     }
    02033   }
    02034   return false;
    02035 }
    02036
    02038 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
    02039   uint i;
    02040   uint j;
    02041
    02042   /* virtual */ void Reset()
    02043   {
    02044     this->i = 0;
    02045     this->j = 0;
    02046   }
    02047
    02048   /* virtual */ FontSize DefaultSize()
    02049   {
    02050     return FS_NORMAL;
    02051   }
    02052
    02053   /* virtual */ const char *NextString()
    02054   {
    02055     if (this->i >= TAB_COUNT) return NULL;
    02056
    02057     const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
    02058
    02059     this->j++;
    02060     while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) {
    02061       this->i++;
    02062       this->j = 0;
    02063     }
    02064
    02065     return ret;
    02066   }
    02067
    02068   /* virtual */ bool Monospace()
    02069   {
    02070     return false;
    02071   }
    02072
    02073   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
    02074   {
    02075 #ifdef WITH_FREETYPE
    02076     strecpy(settings->small.font,  font_name, lastof(settings->small.font));
    02077     strecpy(settings->medium.font, font_name, lastof(settings->medium.font));
    02078     strecpy(settings->large.font,  font_name, lastof(settings->large.font));
    02079 #endif /* WITH_FREETYPE */
    02080   }
    02081 };
    02082
    02096 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
    02097 {
    02098   static LanguagePackGlyphSearcher pack_searcher;
    02099   if (searcher == NULL) searcher = &pack_searcher;
    02100   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
    02101 #ifdef WITH_FREETYPE
    02102   if (bad_font) {
    02103     /* We found an unprintable character... lets try whether we can find
    02104      * a fallback font that can print the characters in the current language. */
    02105     FreeTypeSettings backup;
    02106     memcpy(&backup, &_freetype, sizeof(backup));
    02107
    02108     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
    02109
    02110     memcpy(&_freetype, &backup, sizeof(backup));
    02111
    02112     if (bad_font && base_font) {
    02113       /* Our fallback font does miss characters too, so keep the
    02114        * user chosen font as that is more likely to be any good than
    02115        * the wild guess we made */
    02116       InitFreeType(searcher->Monospace());
    02117     }
    02118   }
    02119 #endif
    02120
    02121   if (bad_font) {
    02122     /* All attempts have failed. Display an error. As we do not want the string to be translated by
    02123      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
    02124      * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
    02125      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
    02126      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
    02127     static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
    02128     Utf8Encode(err_str, SCC_YELLOW);
    02129     SetDParamStr(0, err_str);
    02130     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
    02131
    02132     /* Reset the font width */
    02133     LoadStringWidthTable(searcher->Monospace());
    02134     return;
    02135   }
    02136
    02137   /* Update the font with cache */
    02138   LoadStringWidthTable(searcher->Monospace());
    02139
    02140 #if !defined(WITH_ICU)
    02141   /*
    02142    * For right-to-left languages we need the ICU library. If
    02143    * we do not have support for that library we warn the user
    02144    * about it with a message. As we do not want the string to
    02145    * be translated by the translators, we 'force' it into the
    02146    * binary and 'load' it via a BindCString. To do this
    02147    * properly we have to set the colour of the string,
    02148    * otherwise we end up with a lot of artifacts. The colour
    02149    * 'character' might change in the future, so for safety
    02150    * we just Utf8 Encode it into the string, which takes
    02151    * exactly three characters, so it replaces the "XXX" with
    02152    * the colour marker.
    02153    */
    02154   if (_current_text_dir != TD_LTR) {
    02155     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    02156     Utf8Encode(err_str, SCC_YELLOW);
    02157     SetDParamStr(0, err_str);
    02158     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
    02159   }
    02160 #endif
    02161 }