# strings.cpp

Go to the documentation of this file.

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