# strings.cpp

Go to the documentation of this file.

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