# strings.cpp

Go to the documentation of this file.

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