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