# 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
    00612   int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
    00613   {
    00614     return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
    00615   }
    00616 };
    00617
    00618 struct Units {
    00619   UnitConversion c_velocity;
    00620   StringID velocity;
    00621   UnitConversion c_power;
    00622   StringID power;
    00623   UnitConversion c_weight;
    00624   StringID s_weight;
    00625   StringID l_weight;
    00626   UnitConversion c_volume;
    00627   StringID s_volume;
    00628   StringID l_volume;
    00629   UnitConversion c_force;
    00630   StringID force;
    00631   UnitConversion c_height;
    00632   StringID height;
    00633 };
    00634
    00635 /* Unit conversions */
    00636 static const Units _units[] = {
    00637   { // Imperial (Original, mph, hp, metric ton, litre, kN, ft)
    00638     {   1,  0}, STR_UNITS_VELOCITY_IMPERIAL,
    00639     {   1,  0}, STR_UNITS_POWER_IMPERIAL,
    00640     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00641     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00642     {   1,  0}, STR_UNITS_FORCE_SI,
    00643     {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL, // "Wrong" conversion factor for more nicer GUI values
    00644   },
    00645   { // Metric (km/h, hp, metric ton, litre, kN, metre)
    00646     { 103,  6}, STR_UNITS_VELOCITY_METRIC,
    00647     {4153, 12}, STR_UNITS_POWER_METRIC,
    00648     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00649     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00650     {   1,  0}, STR_UNITS_FORCE_SI,
    00651     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00652   },
    00653   { // SI (m/s, kilowatt, kilogram, cubic metre, kilonewton, metre)
    00654     {1831, 12}, STR_UNITS_VELOCITY_SI,
    00655     {6109, 13}, STR_UNITS_POWER_SI,
    00656     {1000,  0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
    00657     {   1,  0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
    00658     {   1,  0}, STR_UNITS_FORCE_SI,
    00659     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00660   },
    00661 };
    00662
    00668 uint ConvertSpeedToDisplaySpeed(uint speed)
    00669 {
    00670   /* For historical reasons we don't want to mess with the
    00671    * conversion for speed. So, don't round it and keep the
    00672    * original conversion factors instead of the real ones. */
    00673   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed, false);
    00674 }
    00675
    00681 uint ConvertDisplaySpeedToSpeed(uint speed)
    00682 {
    00683   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed);
    00684 }
    00685
    00691 uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
    00692 {
    00693   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed * 10, false) / 16;
    00694 }
    00695
    00701 uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
    00702 {
    00703   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed * 16, true, 10);
    00704 }
    00714 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
    00715 {
    00716   uint orig_offset = args->offset;
    00717
    00718   /* When there is no array with types there is no need to do a dry run. */
    00719   if (args->HasTypeInformation() && !dry_run) {
    00720     if (UsingNewGRFTextStack()) {
    00721       /* Values from the NewGRF text stack are only copied to the normal
    00722        * argv array at the time they are encountered. That means that if
    00723        * another string command references a value later in the string it
    00724        * would fail. We solve that by running FormatString twice. The first
    00725        * pass makes sure the argv array is correctly filled and the second
    00726        * pass can reference later values without problems. */
    00727       struct TextRefStack *backup = CreateTextRefStackBackup();
    00728       FormatString(buff, str_arg, args, last, case_index, game_script, true);
    00729       RestoreTextRefStackBackup(backup);
    00730     } else {
    00731       FormatString(buff, str_arg, args, last, case_index, game_script, true);
    00732     }
    00733     /* We have to restore the original offset here to to read the correct values. */
    00734     args->offset = orig_offset;
    00735   }
    00736   WChar b;
    00737   uint next_substr_case_index = 0;
    00738   char *buf_start = buff;
    00739   std::stack<const char *> str_stack;
    00740   str_stack.push(str_arg);
    00741
    00742   for (;;) {
    00743     while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
    00744       str_stack.pop();
    00745     }
    00746     if (str_stack.empty()) break;
    00747     const char *&str = str_stack.top();
    00748
    00749     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
    00750       /* We need to pass some stuff as it might be modified; oh boy. */
    00751       //todo: should argve be passed here too?
    00752       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), dry_run);
    00753       if (b == 0) continue;
    00754     }
    00755
    00756     switch (b) {
    00757       case SCC_ENCODED: {
    00758         uint64 sub_args_data[20];
    00759         WChar sub_args_type[20];
    00760         bool sub_args_need_free[20];
    00761         StringParameters sub_args(sub_args_data, 20, sub_args_type);
    00762
    00763         sub_args.ClearTypeInformation();
    00764         memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
    00765
    00766         uint16 stringid;
    00767         const char *s = str;
    00768         char *p;
    00769         stringid = strtol(str, &p, 16);
    00770         if (*p != ':' && *p != '\0') {
    00771           while (*p != '\0') p++;
    00772           str = p;
    00773           buff = strecat(buff, "(invalid SCC_ENCODED)", last);
    00774           break;
    00775         }
    00776         if (stringid >= TAB_SIZE) {
    00777           while (*p != '\0') p++;
    00778           str = p;
    00779           buff = strecat(buff, "(invalid StringID)", last);
    00780           break;
    00781         }
    00782
    00783         int i = 0;
    00784         while (*p != '\0') {
    00785           uint64 param;
    00786           s = ++p;
    00787
    00788           /* Find the next value */
    00789           bool instring = false;
    00790           bool escape = false;
    00791           for (;; p++) {
    00792             if (*p == '\\') {
    00793               escape = true;
    00794               continue;
    00795             }
    00796             if (*p == '"' && escape) {
    00797               escape = false;
    00798               continue;
    00799             }
    00800             escape = false;
    00801
    00802             if (*p == '"') {
    00803               instring = !instring;
    00804               continue;
    00805             }
    00806             if (instring) {
    00807               continue;
    00808             }
    00809
    00810             if (*p == ':') break;
    00811             if (*p == '\0') break;
    00812           }
    00813
    00814           if (*s != '"') {
    00815             /* Check if we want to look up another string */
    00816             WChar l;
    00817             size_t len = Utf8Decode(&l, s);
    00818             bool lookup = (l == SCC_ENCODED);
    00819             if (lookup) s += len;
    00820
    00821             param = strtol(s, &p, 16);
    00822
    00823             if (lookup) {
    00824               if (param >= TAB_SIZE) {
    00825                 while (*p != '\0') p++;
    00826                 str = p;
    00827                 buff = strecat(buff, "(invalid sub-StringID)", last);
    00828                 break;
    00829               }
    00830               param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param;
    00831             }
    00832
    00833             sub_args.SetParam(i++, param);
    00834           } else {
    00835             char *g = strdup(s);
    00836             g[p - s] = '\0';
    00837
    00838             sub_args_need_free[i] = true;
    00839             sub_args.SetParam(i++, (uint64)(size_t)g);
    00840           }
    00841         }
    00842         /* We error'd out in the while, to error out in themain too */
    00843         if (*str == '\0') break;
    00844
    00845         str = p;
    00846         buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
    00847
    00848         for (int i = 0; i < 20; i++) {
    00849           if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
    00850         }
    00851         break;
    00852       }
    00853
    00854       case SCC_NEWGRF_STRINL: {
    00855         StringID substr = Utf8Consume(&str);
    00856         str_stack.push(GetStringPtr(substr));
    00857         break;
    00858       }
    00859
    00860       case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
    00861         StringID substr = args->GetInt32(SCC_NEWGRF_PRINT_WORD_STRING_ID);
    00862         str_stack.push(GetStringPtr(substr));
    00863         case_index = next_substr_case_index;
    00864         next_substr_case_index = 0;
    00865         break;
    00866       }
    00867
    00868
    00869       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
    00870         /* First read the meta data from the language file. */
    00871         uint offset = orig_offset + (byte)*str++;
    00872         int gender = 0;
    00873         if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
    00874           /* Now we need to figure out what text to resolve, i.e.
    00875            * what do we need to draw? So get the actual raw string
    00876            * first using the control code to get said string. */
    00877           char input[4 + 1];
    00878           char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
    00879           *p = '\0';
    00880
    00881           /* Now do the string formatting. */
    00882           char buf[256];
    00883           bool old_kgd = _keep_gender_data;
    00884           _keep_gender_data = true;
    00885           StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
    00886           p = FormatString(buf, input, &tmp_params, lastof(buf));
    00887           _keep_gender_data = old_kgd;
    00888           *p = '\0';
    00889
    00890           /* And determine the string. */
    00891           const char *s = buf;
    00892           WChar c = Utf8Consume(&s);
    00893           /* Does this string have a gender, if so, set it */
    00894           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00895         }
    00896         str = ParseStringChoice(str, gender, &buff, last);
    00897         break;
    00898       }
    00899
    00900       /* This sets up the gender for the string.
    00901        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00902       case SCC_GENDER_INDEX: // {GENDER 0}
    00903         if (_keep_gender_data) {
    00904           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
    00905           *buff++ = *str++;
    00906         } else {
    00907           str++;
    00908         }
    00909         break;
    00910
    00911       case SCC_PLURAL_LIST: { // {P}
    00912         int plural_form = *str++;          // contains the plural form for this string
    00913         uint offset = orig_offset + (byte)*str++;
    00914         int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
    00915         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
    00916         break;
    00917       }
    00918
    00919       case SCC_ARG_INDEX: { // Move argument pointer
    00920         args->offset = orig_offset + (byte)*str++;
    00921         break;
    00922       }
    00923
    00924       case SCC_SET_CASE: { // {SET_CASE}
    00925         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    00926          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    00927         next_substr_case_index = (byte)*str++;
    00928         break;
    00929       }
    00930
    00931       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    00932         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    00933          * Each LEN is printed using 2 bytes in big endian order. */
    00934         uint num = (byte)*str++;
    00935         while (num) {
    00936           if ((byte)str[0] == case_index) {
    00937             /* Found the case, adjust str pointer and continue */
    00938             str += 3;
    00939             break;
    00940           }
    00941           /* Otherwise skip to the next case */
    00942           str += 3 + (str[1] << 8) + str[2];
    00943           num--;
    00944         }
    00945         break;
    00946       }
    00947
    00948       case SCC_SETX: // {SETX}
    00949         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
    00950           buff += Utf8Encode(buff, SCC_SETX);
    00951           *buff++ = *str++;
    00952         }
    00953         break;
    00954
    00955       case SCC_SETXY: // {SETXY}
    00956         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
    00957           buff += Utf8Encode(buff, SCC_SETXY);
    00958           *buff++ = *str++;
    00959           *buff++ = *str++;
    00960         }
    00961         break;
    00962
    00963       case SCC_REVISION: // {REV}
    00964         buff = strecpy(buff, _openttd_revision, last);
    00965         break;
    00966
    00967       case SCC_STRING_ID: // {STRINL}
    00968         if (game_script) break;
    00969         buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
    00970         break;
    00971
    00972       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
    00973         if (game_script) break;
    00974         const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
    00975         buff = FormatString(buff, str, args, last);
    00976         break;
    00977       }
    00978
    00979       case SCC_STRING: {// {STRING}
    00980         StringID str = args->GetInt32(SCC_STRING);
    00981         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
    00982         /* WARNING. It's prohibited for the included string to consume any arguments.
    00983          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    00984          * To debug stuff you can set argv to NULL and it will tell you */
    00985         StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
    00986         buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
    00987         next_substr_case_index = 0;
    00988         break;
    00989       }
    00990
    00991       case SCC_STRING1:
    00992       case SCC_STRING2:
    00993       case SCC_STRING3:
    00994       case SCC_STRING4:
    00995       case SCC_STRING5:
    00996       case SCC_STRING6:
    00997       case SCC_STRING7: { // {STRING1..7}
    00998         /* Strings that consume arguments */
    00999         StringID str = args->GetInt32(b);
    01000         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
    01001         StringParameters sub_args(*args, b - SCC_STRING1 + 1);
    01002         buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
    01003         next_substr_case_index = 0;
    01004         break;
    01005       }
    01006
    01007       case SCC_COMMA: // {COMMA}
    01008         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
    01009         break;
    01010
    01011       case SCC_DECIMAL: {// {DECIMAL}
    01012         int64 number = args->GetInt64(SCC_DECIMAL);
    01013         int digits = args->GetInt32(SCC_DECIMAL);
    01014         buff = FormatCommaNumber(buff, number, last, digits);
    01015         break;
    01016       }
    01017
    01018       case SCC_NUM: // {NUM}
    01019         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
    01020         break;
    01021
    01022       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    01023         int64 num = args->GetInt64();
    01024         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
    01025         break;
    01026       }
    01027
    01028       case SCC_HEX: // {HEX}
    01029         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
    01030         break;
    01031
    01032       case SCC_BYTES: // {BYTES}
    01033         buff = FormatBytes(buff, args->GetInt64(), last);
    01034         break;
    01035
    01036       case SCC_CARGO_TINY: { // {CARGO_TINY}
    01037         /* Tiny description of cargotypes. Layout:
    01038          * param 1: cargo type
    01039          * param 2: cargo count */
    01040         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
    01041         if (cargo >= CargoSpec::GetArraySize()) break;
    01042
    01043         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01044         int64 amount = 0;
    01045         switch (cargo_str) {
    01046           case STR_TONS:
    01047             amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
    01048             break;
    01049
    01050           case STR_LITERS:
    01051             amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
    01052             break;
    01053
    01054           default: {
    01055             amount = args->GetInt64();
    01056             break;
    01057           }
    01058         }
    01059
    01060         buff = FormatCommaNumber(buff, amount, last);
    01061         break;
    01062       }
    01063
    01064       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
    01065         /* Short description of cargotypes. Layout:
    01066          * param 1: cargo type
    01067          * param 2: cargo count */
    01068         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
    01069         if (cargo >= CargoSpec::GetArraySize()) break;
    01070
    01071         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01072         switch (cargo_str) {
    01073           case STR_TONS: {
    01074             assert(_settings_game.locale.units < lengthof(_units));
    01075             int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01076             StringParameters tmp_params(args_array);
    01077             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01078             break;
    01079           }
    01080
    01081           case STR_LITERS: {
    01082             assert(_settings_game.locale.units < lengthof(_units));
    01083             int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01084             StringParameters tmp_params(args_array);
    01085             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01086             break;
    01087           }
    01088
    01089           default: {
    01090             StringParameters tmp_params(*args, 1);
    01091             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
    01092             break;
    01093           }
    01094         }
    01095         break;
    01096       }
    01097
    01098       case SCC_CARGO_LONG: { // {CARGO_LONG}
    01099         /* First parameter is cargo type, second parameter is cargo count */
    01100         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
    01101         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
    01102
    01103         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    01104         StringParameters tmp_args(*args, 1);
    01105         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
    01106         break;
    01107       }
    01108
    01109       case SCC_CARGO_LIST: { // {CARGO_LIST}
    01110         uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
    01111         bool first = true;
    01112
    01113         const CargoSpec *cs;
    01114         FOR_ALL_SORTED_CARGOSPECS(cs) {
    01115           if (!HasBit(cmask, cs->Index())) continue;
    01116
    01117           if (buff >= last - 2) break; // ',' and ' '
    01118
    01119           if (first) {
    01120             first = false;
    01121           } else {
    01122             /* Add a comma if this is not the first item */
    01123             *buff++ = ',';
    01124             *buff++ = ' ';
    01125           }
    01126
    01127           buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
    01128         }
    01129
    01130         /* If first is still true then no cargo is accepted */
    01131         if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
    01132
    01133         *buff = '\0';
    01134         next_substr_case_index = 0;
    01135
    01136         /* Make sure we detect any buffer overflow */
    01137         assert(buff < last);
    01138         break;
    01139       }
    01140
    01141       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
    01142         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
    01143         break;
    01144
    01145       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
    01146         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
    01147         break;
    01148
    01149       case SCC_DATE_TINY: // {DATE_TINY}
    01150         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
    01151         break;
    01152
    01153       case SCC_DATE_SHORT: // {DATE_SHORT}
    01154         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
    01155         next_substr_case_index = 0;
    01156         break;
    01157
    01158       case SCC_DATE_LONG: // {DATE_LONG}
    01159         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
    01160         next_substr_case_index = 0;
    01161         break;
    01162
    01163       case SCC_DATE_ISO: // {DATE_ISO}
    01164         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
    01165         break;
    01166
    01167       case SCC_FORCE: { // {FORCE}
    01168         assert(_settings_game.locale.units < lengthof(_units));
    01169         int64 args_array[1] = {_units[_settings_game.locale.units].c_force.ToDisplay(args->GetInt64())};
    01170         StringParameters tmp_params(args_array);
    01171         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), &tmp_params, last);
    01172         break;
    01173       }
    01174
    01175       case SCC_HEIGHT: { // {HEIGHT}
    01176         int64 args_array[] = {_units[_settings_game.locale.units].c_height.ToDisplay(args->GetInt64())};
    01177         StringParameters tmp_params(args_array);
    01178         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), &tmp_params, last);
    01179         break;
    01180       }
    01181
    01182       case SCC_POWER: { // {POWER}
    01183         assert(_settings_game.locale.units < lengthof(_units));
    01184         int64 args_array[1] = {_units[_settings_game.locale.units].c_power.ToDisplay(args->GetInt64())};
    01185         StringParameters tmp_params(args_array);
    01186         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), &tmp_params, last);
    01187         break;
    01188       }
    01189
    01190       case SCC_VELOCITY: { // {VELOCITY}
    01191         assert(_settings_game.locale.units < lengthof(_units));
    01192         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
    01193         StringParameters tmp_params(args_array);
    01194         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), &tmp_params, last);
    01195         break;
    01196       }
    01197
    01198       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
    01199         assert(_settings_game.locale.units < lengthof(_units));
    01200         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01201         StringParameters tmp_params(args_array);
    01202         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), &tmp_params, last);
    01203         break;
    01204       }
    01205
    01206       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
    01207         assert(_settings_game.locale.units < lengthof(_units));
    01208         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
    01209         StringParameters tmp_params(args_array);
    01210         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01211         break;
    01212       }
    01213
    01214       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
    01215         assert(_settings_game.locale.units < lengthof(_units));
    01216         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01217         StringParameters tmp_params(args_array);
    01218         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), &tmp_params, last);
    01219         break;
    01220       }
    01221
    01222       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
    01223         assert(_settings_game.locale.units < lengthof(_units));
    01224         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
    01225         StringParameters tmp_params(args_array);
    01226         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01227         break;
    01228       }
    01229
    01230       case SCC_COMPANY_NAME: { // {COMPANY}
    01231         const Company *c = Company::GetIfValid(args->GetInt32());
    01232         if (c == NULL) break;
    01233
    01234         if (c->name != NULL) {
    01235           int64 args_array[] = {(uint64)(size_t)c->name};
    01236           StringParameters tmp_params(args_array);
    01237           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01238         } else {
    01239           int64 args_array[] = {c->name_2};
    01240           StringParameters tmp_params(args_array);
    01241           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
    01242         }
    01243         break;
    01244       }
    01245
    01246       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
    01247         CompanyID company = (CompanyID)args->GetInt32();
    01248
    01249         /* Nothing is added for AI or inactive companies */
    01250         if (Company::IsValidHumanID(company)) {
    01251           int64 args_array[] = {company + 1};
    01252           StringParameters tmp_params(args_array);
    01253           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
    01254         }
    01255         break;
    01256       }
    01257
    01258       case SCC_DEPOT_NAME: { // {DEPOT}
    01259         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
    01260         if (vt == VEH_AIRCRAFT) {
    01261           uint64 args_array[] = {args->GetInt32()};
    01262           WChar types_array[] = {SCC_STATION_NAME};
    01263           StringParameters tmp_params(args_array, 1, types_array);
    01264           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
    01265           break;
    01266         }
    01267
    01268         const Depot *d = Depot::Get(args->GetInt32());
    01269         if (d->name != NULL) {
    01270           int64 args_array[] = {(uint64)(size_t)d->name};
    01271           StringParameters tmp_params(args_array);
    01272           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01273         } else {
    01274           int64 args_array[] = {d->town->index, d->town_cn + 1};
    01275           StringParameters tmp_params(args_array);
    01276           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
    01277         }
    01278         break;
    01279       }
    01280
    01281       case SCC_ENGINE_NAME: { // {ENGINE}
    01282         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
    01283         if (e == NULL) break;
    01284
    01285         if (e->name != NULL && e->IsEnabled()) {
    01286           int64 args_array[] = {(uint64)(size_t)e->name};
    01287           StringParameters tmp_params(args_array);
    01288           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01289         } else {
    01290           StringParameters tmp_params(NULL, 0, NULL);
    01291           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
    01292         }
    01293         break;
    01294       }
    01295
    01296       case SCC_GROUP_NAME: { // {GROUP}
    01297         const Group *g = Group::GetIfValid(args->GetInt32());
    01298         if (g == NULL) break;
    01299
    01300         if (g->name != NULL) {
    01301           int64 args_array[] = {(uint64)(size_t)g->name};
    01302           StringParameters tmp_params(args_array);
    01303           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01304         } else {
    01305           int64 args_array[] = {g->index};
    01306           StringParameters tmp_params(args_array);
    01307
    01308           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
    01309         }
    01310         break;
    01311       }
    01312
    01313       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    01314         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
    01315         if (i == NULL) break;
    01316
    01317         /* First print the town name and the industry type name. */
    01318         int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
    01319         StringParameters tmp_params(args_array);
    01320
    01321         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
    01322         next_substr_case_index = 0;
    01323         break;
    01324       }
    01325
    01326       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
    01327         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
    01328         if (c == NULL) break;
    01329
    01330         if (c->president_name != NULL) {
    01331           int64 args_array[] = {(uint64)(size_t)c->president_name};
    01332           StringParameters tmp_params(args_array);
    01333           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01334         } else {
    01335           int64 args_array[] = {c->president_name_2};
    01336           StringParameters tmp_params(args_array);
    01337           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
    01338         }
    01339         break;
    01340       }
    01341
    01342       case SCC_STATION_NAME: { // {STATION}
    01343         StationID sid = args->GetInt32(SCC_STATION_NAME);
    01344         const Station *st = Station::GetIfValid(sid);
    01345
    01346         if (st == NULL) {
    01347           /* The station doesn't exist anymore. The only place where we might
    01348            * be "drawing" an invalid station is in the case of cargo that is
    01349            * in transit. */
    01350           StringParameters tmp_params(NULL, 0, NULL);
    01351           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
    01352           break;
    01353         }
    01354
    01355         if (st->name != NULL) {
    01356           int64 args_array[] = {(uint64)(size_t)st->name};
    01357           StringParameters tmp_params(args_array);
    01358           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01359         } else {
    01360           StringID str = st->string_id;
    01361           if (st->indtype != IT_INVALID) {
    01362             /* Special case where the industry provides the name for the station */
    01363             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    01364
    01365             /* Industry GRFs can change which might remove the station name and
    01366              * thus cause very strange things. Here we check for that before we
    01367              * actually set the station name. */
    01368             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    01369               str = indsp->station_name;
    01370             }
    01371           }
    01372
    01373           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
    01374           StringParameters tmp_params(args_array);
    01375           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01376         }
    01377         break;
    01378       }
    01379
    01380       case SCC_TOWN_NAME: { // {TOWN}
    01381         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
    01382         if (t == NULL) break;
    01383
    01384         if (t->name != NULL) {
    01385           int64 args_array[] = {(uint64)(size_t)t->name};
    01386           StringParameters tmp_params(args_array);
    01387           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01388         } else {
    01389           buff = GetTownName(buff, t, last);
    01390         }
    01391         break;
    01392       }
    01393
    01394       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    01395         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
    01396         if (wp == NULL) break;
    01397
    01398         if (wp->name != NULL) {
    01399           int64 args_array[] = {(uint64)(size_t)wp->name};
    01400           StringParameters tmp_params(args_array);
    01401           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01402         } else {
    01403           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
    01404           StringParameters tmp_params(args_array);
    01405           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    01406           if (wp->town_cn != 0) str++;
    01407           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01408         }
    01409         break;
    01410       }
    01411
    01412       case SCC_VEHICLE_NAME: { // {VEHICLE}
    01413         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
    01414         if (v == NULL) break;
    01415
    01416         if (v->name != NULL) {
    01417           int64 args_array[] = {(uint64)(size_t)v->name};
    01418           StringParameters tmp_params(args_array);
    01419           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01420         } else {
    01421           int64 args_array[] = {v->unitnumber};
    01422           StringParameters tmp_params(args_array);
    01423
    01424           StringID str;
    01425           switch (v->type) {
    01426             default: NOT_REACHED();
    01427             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    01428             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    01429             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    01430             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    01431           }
    01432
    01433           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01434         }
    01435         break;
    01436       }
    01437
    01438       case SCC_SIGN_NAME: { // {SIGN}
    01439         const Sign *si = Sign::GetIfValid(args->GetInt32());
    01440         if (si == NULL) break;
    01441
    01442         if (si->name != NULL) {
    01443           int64 args_array[] = {(uint64)(size_t)si->name};
    01444           StringParameters tmp_params(args_array);
    01445           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01446         } else {
    01447           StringParameters tmp_params(NULL, 0, NULL);
    01448           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
    01449         }
    01450         break;
    01451       }
    01452
    01453       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    01454         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
    01455         break;
    01456       }
    01457
    01458       default:
    01459         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01460         break;
    01461     }
    01462   }
    01463   *buff = '\0';
    01464   return buff;
    01465 }
    01466
    01467
    01468 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01469 {
    01470   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01471   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01472   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01473   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01474   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01475   *buff = '\0';
    01476   return buff;
    01477 }
    01478
    01479 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01480 {
    01481   return GenerateTownNameString(buff, last, ind, seed);
    01482 }
    01483
    01484 static const char * const _silly_company_names[] = {
    01485   "Bloggs Brothers",
    01486   "Tiny Transport Ltd.",
    01487   "Express Travel",
    01488   "Comfy-Coach & Co.",
    01489   "Crush & Bump Ltd.",
    01490   "Broken & Late Ltd.",
    01491   "Sam Speedy & Son",
    01492   "Supersonic Travel",
    01493   "Mike's Motors",
    01494   "Lightning International",
    01495   "Pannik & Loozit Ltd.",
    01496   "Inter-City Transport",
    01497   "Getout & Pushit Ltd."
    01498 };
    01499
    01500 static const char * const _surname_list[] = {
    01501   "Adams",
    01502   "Allan",
    01503   "Baker",
    01504   "Bigwig",
    01505   "Black",
    01506   "Bloggs",
    01507   "Brown",
    01508   "Campbell",
    01509   "Gordon",
    01510   "Hamilton",
    01511   "Hawthorn",
    01512   "Higgins",
    01513   "Green",
    01514   "Gribble",
    01515   "Jones",
    01516   "McAlpine",
    01517   "MacDonald",
    01518   "McIntosh",
    01519   "Muir",
    01520   "Murphy",
    01521   "Nelson",
    01522   "O'Donnell",
    01523   "Parker",
    01524   "Phillips",
    01525   "Pilkington",
    01526   "Quigley",
    01527   "Sharkey",
    01528   "Thomson",
    01529   "Watkins"
    01530 };
    01531
    01532 static const char * const _silly_surname_list[] = {
    01533   "Grumpy",
    01534   "Dozy",
    01535   "Speedy",
    01536   "Nosey",
    01537   "Dribble",
    01538   "Mushroom",
    01539   "Cabbage",
    01540   "Sniffle",
    01541   "Fishy",
    01542   "Swindle",
    01543   "Sneaky",
    01544   "Nutkins"
    01545 };
    01546
    01547 static const char _initial_name_letters[] = {
    01548   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01549   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01550 };
    01551
    01552 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01553 {
    01554   const char * const *base;
    01555   uint num;
    01556
    01557   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01558     base = _silly_surname_list;
    01559     num  = lengthof(_silly_surname_list);
    01560   } else {
    01561     base = _surname_list;
    01562     num  = lengthof(_surname_list);
    01563   }
    01564
    01565   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01566   buff = strecpy(buff, " & Co.", last);
    01567
    01568   return buff;
    01569 }
    01570
    01571 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01572 {
    01573   char initial[] = "?. ";
    01574   const char * const *base;
    01575   uint num;
    01576   uint i;
    01577
    01578   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01579   buff = strecpy(buff, initial, last);
    01580
    01581   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01582   if (i < sizeof(_initial_name_letters)) {
    01583     initial[0] = _initial_name_letters[i];
    01584     buff = strecpy(buff, initial, last);
    01585   }
    01586
    01587   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01588     base = _silly_surname_list;
    01589     num  = lengthof(_silly_surname_list);
    01590   } else {
    01591     base = _surname_list;
    01592     num  = lengthof(_surname_list);
    01593   }
    01594
    01595   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01596
    01597   return buff;
    01598 }
    01599
    01600 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
    01601 {
    01602   switch (ind) {
    01603     case 1: // not used
    01604       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
    01605
    01606     case 2: // used for Foobar & Co company names
    01607       return GenAndCoName(buff, args->GetInt32(), last);
    01608
    01609     case 3: // President name
    01610       return GenPresidentName(buff, args->GetInt32(), last);
    01611   }
    01612
    01613   /* town name? */
    01614   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01615     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
    01616     return strecpy(buff, " Transport", last);
    01617   }
    01618
    01619   /* language name? */
    01620   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01621     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01622     return strecpy(buff,
    01623       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
    01624   }
    01625
    01626   /* resolution size? */
    01627   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01628     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01629     buff += seprintf(
    01630       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01631     );
    01632     return buff;
    01633   }
    01634
    01635   /* screenshot format name? */
    01636   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01637     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01638     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01639   }
    01640
    01641   NOT_REACHED();
    01642 }
    01643
    01644 #ifdef ENABLE_NETWORK
    01645 extern void SortNetworkLanguages();
    01646 #else /* ENABLE_NETWORK */
    01647 static inline void SortNetworkLanguages() {}
    01648 #endif /* ENABLE_NETWORK */
    01649
    01654 bool LanguagePackHeader::IsValid() const
    01655 {
    01656   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
    01657          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
    01658          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
    01659          this->text_dir     <= 1 &&
    01660          this->newgrflangid < MAX_LANG &&
    01661          this->num_genders  < MAX_NUM_GENDERS &&
    01662          this->num_cases    < MAX_NUM_CASES &&
    01663          StrValid(this->name,                           lastof(this->name)) &&
    01664          StrValid(this->own_name,                       lastof(this->own_name)) &&
    01665          StrValid(this->isocode,                        lastof(this->isocode)) &&
    01666          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
    01667          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
    01668          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
    01669 }
    01670
    01676 bool ReadLanguagePack(const LanguageMetadata *lang)
    01677 {
    01678   /* Current language pack */
    01679   size_t len;
    01680   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
    01681   if (lang_pack == NULL) return false;
    01682
    01683   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01684   const char *end = (char *)lang_pack + len + 1;
    01685
    01686   /* We need at least one byte of lang_pack->data */
    01687   if (end <= lang_pack->data || !lang_pack->IsValid()) {
    01688     free(lang_pack);
    01689     return false;
    01690   }
    01691
    01692 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01693   for (uint i = 0; i < TAB_COUNT; i++) {
    01694     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01695   }
    01696 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01697
    01698   uint count = 0;
    01699   for (uint i = 0; i < TAB_COUNT; i++) {
    01700     uint num = lang_pack->offsets[i];
    01701     _langtab_start[i] = count;
    01702     _langtab_num[i] = num;
    01703     count += num;
    01704   }
    01705
    01706   /* Allocate offsets */
    01707   char **langpack_offs = MallocT<char *>(count);
    01708
    01709   /* Fill offsets */
    01710   char *s = lang_pack->data;
    01711   len = (byte)*s++;
    01712   for (uint i = 0; i < count; i++) {
    01713     if (s + len >= end) {
    01714       free(lang_pack);
    01715       free(langpack_offs);
    01716       return false;
    01717     }
    01718     if (len >= 0xC0) {
    01719       len = ((len & 0x3F) << 8) + (byte)*s++;
    01720       if (s + len >= end) {
    01721         free(lang_pack);
    01722         free(langpack_offs);
    01723         return false;
    01724       }
    01725     }
    01726     langpack_offs[i] = s;
    01727     s += len;
    01728     len = (byte)*s;
    01729     *s++ = '\0'; // zero terminate the string
    01730   }
    01731
    01732   free(_langpack);
    01733   _langpack = lang_pack;
    01734
    01735   free(_langpack_offs);
    01736   _langpack_offs = langpack_offs;
    01737
    01738   _current_language = lang;
    01739   _current_text_dir = (TextDirection)_current_language->text_dir;
    01740   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
    01741   strecpy(_config_language_file, c_file, lastof(_config_language_file));
    01742   SetCurrentGrfLangID(_current_language->newgrflangid);
    01743
    01744 #ifdef WITH_ICU
    01745   /* Delete previous collator. */
    01746   if (_current_collator != NULL) {
    01747     delete _current_collator;
    01748     _current_collator = NULL;
    01749   }
    01750
    01751   /* Create a collator instance for our current locale. */
    01752   UErrorCode status = U_ZERO_ERROR;
    01753   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
    01754   /* Sort number substrings by their numerical value. */
    01755   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
    01756   /* Avoid using the collator if it is not correctly set. */
    01757   if (U_FAILURE(status)) {
    01758     delete _current_collator;
    01759     _current_collator = NULL;
    01760   }
    01761 #endif /* WITH_ICU */
    01762
    01763   /* Some lists need to be sorted again after a language change. */
    01764   ReconsiderGameScriptLanguage();
    01765   InitializeSortedCargoSpecs();
    01766   SortIndustryTypes();
    01767   BuildIndustriesLegend();
    01768   SortNetworkLanguages();
    01769   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
    01770   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
    01771   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
    01772   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
    01773   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
    01774   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
    01775   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
    01776
    01777   return true;
    01778 }
    01779
    01780 /* Win32 implementation in win32.cpp.
    01781  * OS X implementation in os/macosx/macos.mm. */
    01782 #if !(defined(WIN32) || defined(__APPLE__))
    01783
    01791 const char *GetCurrentLocale(const char *param)
    01792 {
    01793   const char *env;
    01794
    01795   env = getenv("LANGUAGE");
    01796   if (env != NULL) return env;
    01797
    01798   env = getenv("LC_ALL");
    01799   if (env != NULL) return env;
    01800
    01801   if (param != NULL) {
    01802     env = getenv(param);
    01803     if (env != NULL) return env;
    01804   }
    01805
    01806   return getenv("LANG");
    01807 }
    01808 #else
    01809 const char *GetCurrentLocale(const char *param);
    01810 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01811
    01812 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01813 {
    01814   char stra[512];
    01815   char strb[512];
    01816   GetString(stra, *a, lastof(stra));
    01817   GetString(strb, *b, lastof(strb));
    01818
    01819   return strcmp(stra, strb);
    01820 }
    01821
    01827 const LanguageMetadata *GetLanguage(byte newgrflangid)
    01828 {
    01829   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
    01830     if (newgrflangid == lang->newgrflangid) return lang;
    01831   }
    01832
    01833   return NULL;
    01834 }
    01835
    01842 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
    01843 {
    01844   FILE *f = fopen(file, "rb");
    01845   if (f == NULL) return false;
    01846
    01847   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01848   fclose(f);
    01849
    01850   bool ret = read == 1 && hdr->IsValid();
    01851
    01852   /* Convert endianness for the windows language ID */
    01853   if (ret) {
    01854     hdr->missing = FROM_LE16(hdr->missing);
    01855     hdr->winlangid = FROM_LE16(hdr->winlangid);
    01856   }
    01857   return ret;
    01858 }
    01859
    01864 static void GetLanguageList(const char *path)
    01865 {
    01866   DIR *dir = ttd_opendir(path);
    01867   if (dir != NULL) {
    01868     struct dirent *dirent;
    01869     while ((dirent = readdir(dir)) != NULL) {
    01870       const char *d_name    = FS2OTTD(dirent->d_name);
    01871       const char *extension = strrchr(d_name, '.');
    01872
    01873       /* Not a language file */
    01874       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01875
    01876       LanguageMetadata lmd;
    01877       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
    01878
    01879       /* Check whether the file is of the correct version */
    01880       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
    01881         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
    01882       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
    01883         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
    01884       } else {
    01885         *_languages.Append() = lmd;
    01886       }
    01887     }
    01888     closedir(dir);
    01889   }
    01890 }
    01891
    01896 void InitializeLanguagePacks()
    01897 {
    01898   Searchpath sp;
    01899
    01900   FOR_ALL_SEARCHPATHS(sp) {
    01901     char path[MAX_PATH];
    01902     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01903     GetLanguageList(path);
    01904   }
    01905   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
    01906
    01907   /* Acquire the locale of the current system */
    01908   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01909   if (lang == NULL) lang = "en_GB";
    01910
    01911   const LanguageMetadata *chosen_language   = NULL;
    01912   const LanguageMetadata *language_fallback = NULL;
    01913   const LanguageMetadata *en_GB_fallback    = _languages.Begin();
    01914
    01915   /* Find a proper language. */
    01916   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
    01917     /* We are trying to find a default language. The priority is by
    01918      * configuration file, local environment and last, if nothing found,
    01919      * English. */
    01920     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
    01921     if (strcmp(lang_file, _config_language_file) == 0) {
    01922       chosen_language = lng;
    01923       break;
    01924     }
    01925
    01926     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
    01927     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
    01928     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
    01929   }
    01930
    01931   /* We haven't found the language in the config nor the one in the locale.
    01932    * Now we set it to one of the fallback languages */
    01933   if (chosen_language == NULL) {
    01934     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
    01935   }
    01936
    01937   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
    01938 }
    01939
    01944 const char *GetCurrentLanguageIsoCode()
    01945 {
    01946   return _langpack->isocode;
    01947 }
    01948
    01955 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
    01956 {
    01957   InitFreeType(this->Monospace());
    01958   const Sprite *question_mark[FS_END];
    01959
    01960   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
    01961     question_mark[size] = GetGlyph(size, '?');
    01962   }
    01963
    01964   this->Reset();
    01965   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
    01966     FontSize size = this->DefaultSize();
    01967     if (str != NULL) *str = text;
    01968     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
    01969       if (c == SCC_SETX) {
    01970         /* SetX is, together with SetXY as special character that
    01971           * uses the next (two) characters as data points. We have
    01972           * to skip those, otherwise the UTF8 reading will go haywire. */
    01973         text++;
    01974       } else if (c == SCC_SETXY) {
    01975         text += 2;
    01976       } else if (c == SCC_TINYFONT) {
    01977         size = FS_SMALL;
    01978       } else if (c == SCC_BIGFONT) {
    01979         size = FS_LARGE;
    01980       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
    01981         /* The character is printable, but not in the normal font. This is the case we were testing for. */
    01982         return true;
    01983       }
    01984     }
    01985   }
    01986   return false;
    01987 }
    01988
    01990 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
    01991   uint i;
    01992   uint j;
    01993
    01994   /* virtual */ void Reset()
    01995   {
    01996     this->i = 0;
    01997     this->j = 0;
    01998   }
    01999
    02000   /* virtual */ FontSize DefaultSize()
    02001   {
    02002     return FS_NORMAL;
    02003   }
    02004
    02005   /* virtual */ const char *NextString()
    02006   {
    02007     if (this->i >= TAB_COUNT) return NULL;
    02008
    02009     const char *ret = _langpack_offs[_langtab_start[i] + j];
    02010
    02011     this->j++;
    02012     while (this->j >= _langtab_num[this->i] && this->i < TAB_COUNT) {
    02013       i++;
    02014       j = 0;
    02015     }
    02016
    02017     return ret;
    02018   }
    02019
    02020   /* virtual */ bool Monospace()
    02021   {
    02022     return false;
    02023   }
    02024
    02025   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
    02026   {
    02027 #ifdef WITH_FREETYPE
    02028     strecpy(settings->small_font,  font_name, lastof(settings->small_font));
    02029     strecpy(settings->medium_font, font_name, lastof(settings->medium_font));
    02030     strecpy(settings->large_font,  font_name, lastof(settings->large_font));
    02031 #endif /* WITH_FREETYPE */
    02032   }
    02033 };
    02034
    02048 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
    02049 {
    02050   static LanguagePackGlyphSearcher pack_searcher;
    02051   if (searcher == NULL) searcher = &pack_searcher;
    02052   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
    02053 #ifdef WITH_FREETYPE
    02054   if (bad_font) {
    02055     /* We found an unprintable character... lets try whether we can find
    02056      * a fallback font that can print the characters in the current language. */
    02057     FreeTypeSettings backup;
    02058     memcpy(&backup, &_freetype, sizeof(backup));
    02059
    02060     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
    02061
    02062     memcpy(&_freetype, &backup, sizeof(backup));
    02063
    02064     if (bad_font && base_font) {
    02065       /* Our fallback font does miss characters too, so keep the
    02066        * user chosen font as that is more likely to be any good than
    02067        * the wild guess we made */
    02068       InitFreeType(searcher->Monospace());
    02069     }
    02070   }
    02071 #endif
    02072
    02073   if (bad_font) {
    02074     /* All attempts have failed. Display an error. As we do not want the string to be translated by
    02075      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
    02076      * properly we have to set the colour of the string, otherwise we end up with a lot of artefacts.
    02077      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
    02078      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
    02079     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.");
    02080     Utf8Encode(err_str, SCC_YELLOW);
    02081     SetDParamStr(0, err_str);
    02082     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
    02083
    02084     /* Reset the font width */
    02085     LoadStringWidthTable(searcher->Monospace());
    02086     return;
    02087   }
    02088
    02089   /* Update the font with cache */
    02090   LoadStringWidthTable(searcher->Monospace());
    02091
    02092 #if !defined(WITH_ICU)
    02093   /*
    02094    * For right-to-left languages we need the ICU library. If
    02095    * we do not have support for that library we warn the user
    02096    * about it with a message. As we do not want the string to
    02097    * be translated by the translators, we 'force' it into the
    02098    * binary and 'load' it via a BindCString. To do this
    02099    * properly we have to set the colour of the string,
    02100    * otherwise we end up with a lot of artefacts. The colour
    02101    * 'character' might change in the future, so for safety
    02102    * we just Utf8 Encode it into the string, which takes
    02103    * exactly three characters, so it replaces the "XXX" with
    02104    * the colour marker.
    02105    */
    02106   if (_current_text_dir != TD_LTR) {
    02107     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    02108     Utf8Encode(err_str, SCC_YELLOW);
    02109     SetDParamStr(0, err_str);
    02110     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
    02111   }
    02112 #endif
    02113 }