# strings.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "currency.h"
    00014 #include "station_base.h"
    00015 #include "town.h"
    00016 #include "screenshot.h"
    00017 #include "waypoint_base.h"
    00018 #include "depot_base.h"
    00019 #include "industry.h"
    00020 #include "newgrf_text.h"
    00021 #include "fileio_func.h"
    00022 #include "signs_base.h"
    00023 #include "fontcache.h"
    00024 #include "error.h"
    00025 #include "strings_func.h"
    00026 #include "rev.h"
    00027 #include "core/endian_func.hpp"
    00028 #include "date_func.h"
    00029 #include "vehicle_base.h"
    00030 #include "engine_base.h"
    00031 #include "language.h"
    00032 #include "townname_func.h"
    00033 #include "string_func.h"
    00034 #include "company_base.h"
    00035 #include "smallmap_gui.h"
    00036 #include "window_func.h"
    00037 #include "debug.h"
    00038 #include "game/game_text.hpp"
    00039 #include <stack>
    00040
    00041 #include "table/strings.h"
    00042 #include "table/control_codes.h"
    00043
    00044 char _config_language_file[MAX_PATH];
    00045 LanguageList _languages;
    00046 const LanguageMetadata *_current_language = NULL;
    00047
    00048 TextDirection _current_text_dir;
    00049
    00050 #ifdef WITH_ICU
    00051 Collator *_current_collator = NULL;
    00052 #endif /* WITH_ICU */
    00053
    00054 static uint64 _global_string_params_data[20];
    00055 static WChar _global_string_params_type[20];
    00056 StringParameters _global_string_params(_global_string_params_data, 20, _global_string_params_type);
    00057
    00059 void StringParameters::ClearTypeInformation()
    00060 {
    00061   assert(this->type != NULL);
    00062   MemSetT(this->type, 0, this->num_param);
    00063 }
    00064
    00065
    00070 int64 StringParameters::GetInt64(WChar type)
    00071 {
    00072   if (this->offset >= this->num_param) {
    00073     DEBUG(misc, 0, "Trying to read invalid string parameter");
    00074     return 0;
    00075   }
    00076   if (this->type != NULL) {
    00077     assert(this->type[this->offset] == 0 || this->type[this->offset] == type);
    00078     this->type[this->offset] = type;
    00079   }
    00080   return this->data[this->offset++];
    00081 }
    00082
    00087 void StringParameters::ShiftParameters(uint amount)
    00088 {
    00089   assert(amount <= this->num_param);
    00090   MemMoveT(this->data + amount, this->data, this->num_param - amount);
    00091 }
    00092
    00100 void SetDParamMaxValue(uint n, uint64 max_value, uint min_count)
    00101 {
    00102   uint num_digits = 1;
    00103   while (max_value >= 10) {
    00104     num_digits++;
    00105     max_value /= 10;
    00106   }
    00107   SetDParamMaxDigits(n, max(min_count, num_digits));
    00108 }
    00109
    00115 void SetDParamMaxDigits(uint n, uint count)
    00116 {
    00117   static const uint biggest_digit = 8;
    00118   uint64 val = biggest_digit;
    00119   for (; count > 1; count--) {
    00120     val = 10 * val + biggest_digit;
    00121   }
    00122   SetDParam(n, val);
    00123 }
    00124
    00131 void CopyInDParam(int offs, const uint64 *src, int num)
    00132 {
    00133   MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num);
    00134 }
    00135
    00142 void CopyOutDParam(uint64 *dst, int offs, int num)
    00143 {
    00144   MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num);
    00145 }
    00146
    00155 void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num)
    00156 {
    00157   char buf[DRAW_STRING_BUFFER];
    00158   GetString(buf, string, lastof(buf));
    00159
    00160   MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num);
    00161   for (int i = 0; i < num; i++) {
    00162     if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) {
    00163       strings[i] = strdup((const char *)(size_t)_global_string_params.GetParam(i));
    00164       dst[i] = (size_t)strings[i];
    00165     } else {
    00166       strings[i] = NULL;
    00167     }
    00168   }
    00169 }
    00170
    00171 static char *StationGetSpecialString(char *buff, int x, const char *last);
    00172 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
    00173 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
    00174
    00175 static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false);
    00176
    00177 struct LanguagePack : public LanguagePackHeader {
    00178   char data[]; // list of strings
    00179 };
    00180
    00181 static char **_langpack_offs;
    00182 static LanguagePack *_langpack;
    00183 static uint _langtab_num[TAB_COUNT];
    00184 static uint _langtab_start[TAB_COUNT];
    00185 static bool _scan_for_gender_data = false;
    00186
    00187
    00188 const char *GetStringPtr(StringID string)
    00189 {
    00190   switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
    00191     case GAME_TEXT_TAB: return GetGameStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
    00192     /* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
    00193     case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, TAB_SIZE_OFFSET, 10)));
    00194     case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
    00195     case 29: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x0800);
    00196     case 30: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x1000);
    00197     default: return _langpack_offs[_langtab_start[GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)] + GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)];
    00198   }
    00199 }
    00200
    00211 char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
    00212 {
    00213   if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
    00214
    00215   uint index = GB(string, TAB_SIZE_OFFSET,  TAB_SIZE_BITS);
    00216   uint tab   = GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS);
    00217
    00218   switch (tab) {
    00219     case 4:
    00220       if (index >= 0xC0 && !game_script) {
    00221         return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
    00222       }
    00223       break;
    00224
    00225     case 14:
    00226       if (index >= 0xE4 && !game_script) {
    00227         return GetSpecialNameString(buffr, index - 0xE4, args, last);
    00228       }
    00229       break;
    00230
    00231     case 15:
    00232       /* Old table for custom names. This is no longer used */
    00233       error("Incorrect conversion of custom name string.");
    00234
    00235     case GAME_TEXT_TAB:
    00236       return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
    00237
    00238     case 26:
    00239       /* Include string within newgrf text (format code 81) */
    00240       if (HasBit(index, 10)) {
    00241         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
    00242         return GetStringWithArgs(buffr, string, args, last, case_index);
    00243       }
    00244       break;
    00245
    00246     case 28:
    00247       return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
    00248
    00249     case 29:
    00250       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), args, last, case_index);
    00251
    00252     case 30:
    00253       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), args, last, case_index);
    00254
    00255     case 31:
    00256       NOT_REACHED();
    00257   }
    00258
    00259   if (index >= _langtab_num[tab]) {
    00260     if (game_script) {
    00261       return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
    00262     }
    00263     error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
    00264   }
    00265
    00266   return FormatString(buffr, GetStringPtr(string), args, last, case_index);
    00267 }
    00268
    00269 char *GetString(char *buffr, StringID string, const char *last)
    00270 {
    00271   _global_string_params.ClearTypeInformation();
    00272   _global_string_params.offset = 0;
    00273   return GetStringWithArgs(buffr, string, &_global_string_params, last);
    00274 }
    00275
    00276
    00277 char *InlineString(char *buf, StringID string)
    00278 {
    00279   buf += Utf8Encode(buf, SCC_STRING_ID);
    00280   buf += Utf8Encode(buf, string);
    00281   return buf;
    00282 }
    00283
    00284
    00290 void SetDParamStr(uint n, const char *str)
    00291 {
    00292   SetDParam(n, (uint64)(size_t)str);
    00293 }
    00294
    00299 void InjectDParam(uint amount)
    00300 {
    00301   _global_string_params.ShiftParameters(amount);
    00302 }
    00303
    00315 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0)
    00316 {
    00317   static const int max_digits = 20;
    00318   uint64 divisor = 10000000000000000000ULL;
    00319   zerofill += fractional_digits;
    00320   int thousands_offset = (max_digits - fractional_digits - 1) % 3;
    00321
    00322   if (number < 0) {
    00323     buff += seprintf(buff, last, "-");
    00324     number = -number;
    00325   }
    00326
    00327   uint64 num = number;
    00328   uint64 tot = 0;
    00329   for (int i = 0; i < max_digits; i++) {
    00330     if (i == max_digits - fractional_digits) {
    00331       const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00332       if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00333       buff += seprintf(buff, last, "%s", decimal_separator);
    00334     }
    00335
    00336     uint64 quot = 0;
    00337     if (num >= divisor) {
    00338       quot = num / divisor;
    00339       num = num % divisor;
    00340     }
    00341     if ((tot |= quot) || i >= max_digits - zerofill) {
    00342       buff += seprintf(buff, last, "%i", (int)quot);
    00343       if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last);
    00344     }
    00345
    00346     divisor /= 10;
    00347   }
    00348
    00349   *buff = '\0';
    00350
    00351   return buff;
    00352 }
    00353
    00354 static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
    00355 {
    00356   const char *separator = _settings_game.locale.digit_group_separator;
    00357   if (separator == NULL) separator = _langpack->digit_group_separator;
    00358   return FormatNumber(buff, number, last, separator, 1, fractional_digits);
    00359 }
    00360
    00361 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
    00362 {
    00363   return FormatNumber(buff, number, last, "");
    00364 }
    00365
    00366 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
    00367 {
    00368   return FormatNumber(buff, number, last, "", count);
    00369 }
    00370
    00371 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
    00372 {
    00373   return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
    00374 }
    00375
    00383 static char *FormatBytes(char *buff, int64 number, const char *last)
    00384 {
    00385   assert(number >= 0);
    00386
    00387   /*                                   1   2^10  2^20  2^30  2^40  2^50  2^60 */
    00388   const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
    00389   uint id = 1;
    00390   while (number >= 1024 * 1024) {
    00391     number /= 1024;
    00392     id++;
    00393   }
    00394
    00395   const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00396   if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00397
    00398   if (number < 1024) {
    00399     id = 0;
    00400     buff += seprintf(buff, last, "%i", (int)number);
    00401   } else if (number < 1024 * 10) {
    00402     buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
    00403   } else if (number < 1024 * 100) {
    00404     buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
    00405   } else {
    00406     assert(number < 1024 * 1024);
    00407     buff += seprintf(buff, last, "%i", (int)number / 1024);
    00408   }
    00409
    00410   assert(id < lengthof(iec_prefixes));
    00411   buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
    00412
    00413   return buff;
    00414 }
    00415
    00416 static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index)
    00417 {
    00418   YearMonthDay ymd;
    00419   ConvertDateToYMD(date, &ymd);
    00420
    00421   int64 args[] = {ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
    00422   StringParameters tmp_params(args);
    00423   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
    00424 }
    00425
    00426 static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index)
    00427 {
    00428   YearMonthDay ymd;
    00429   ConvertDateToYMD(date, &ymd);
    00430
    00431   int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
    00432   StringParameters tmp_params(args);
    00433   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
    00434 }
    00435
    00436 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
    00437 {
    00438   YearMonthDay ymd;
    00439   ConvertDateToYMD(date, &ymd);
    00440
    00441   char day[3];
    00442   char month[3];
    00443   /* We want to zero-pad the days and months */
    00444   snprintf(day,   lengthof(day),   "%02i", ymd.day);
    00445   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
    00446
    00447   int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year};
    00448   StringParameters tmp_params(args);
    00449   return FormatString(buff, GetStringPtr(str), &tmp_params, last);
    00450 }
    00451
    00452 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
    00453 {
    00454   /* We are going to make number absolute for printing, so
    00455    * keep this piece of data as we need it later on */
    00456   bool negative = number < 0;
    00457   const char *multiplier = "";
    00458
    00459   number *= spec->rate;
    00460
    00461   /* convert from negative */
    00462   if (number < 0) {
    00463     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
    00464     buff += Utf8Encode(buff, SCC_RED);
    00465     buff = strecpy(buff, "-", last);
    00466     number = -number;
    00467   }
    00468
    00469   /* Add prefix part, following symbol_pos specification.
    00470    * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
    00471    * The only remaining value is 1 (suffix), so everything that is not 1 */
    00472   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
    00473
    00474   /* for huge numbers, compact the number into k or M */
    00475   if (compact) {
    00476     /* Take care of the 'k' rounding. Having 1 000 000 k
    00477      * and 1 000 M is inconsistent, so always use 1 000 M. */
    00478     if (number >= 1000000000 - 500) {
    00479       number = (number + 500000) / 1000000;
    00480       multiplier = "M";
    00481     } else if (number >= 1000000) {
    00482       number = (number + 500) / 1000;
    00483       multiplier = "k";
    00484     }
    00485   }
    00486
    00487   const char *separator = _settings_game.locale.digit_group_separator_currency;
    00488   if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
    00489   if (separator == NULL) separator = _langpack->digit_group_separator_currency;
    00490   buff = FormatNumber(buff, number, last, separator);
    00491   buff = strecpy(buff, multiplier, last);
    00492
    00493   /* Add suffix part, following symbol_pos specification.
    00494    * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
    00495    * The only remaining value is 1 (prefix), so everything that is not 0 */
    00496   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
    00497
    00498   if (negative) {
    00499     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
    00500     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
    00501     *buff = '\0';
    00502   }
    00503
    00504   return buff;
    00505 }
    00506
    00513 static int DeterminePluralForm(int64 count, int plural_form)
    00514 {
    00515   /* The absolute value determines plurality */
    00516   uint64 n = abs(count);
    00517
    00518   switch (plural_form) {
    00519     default:
    00520       NOT_REACHED();
    00521
    00522     /* Two forms: singular used for one only.
    00523      * Used in:
    00524      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
    00525      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
    00526     case 0:
    00527       return n != 1 ? 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         /* We error'd out in the while, to error out in themain too */
    00893         if (*str == '\0') break;
    00894
    00895         str = p;
    00896         buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
    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         StringParameters sub_args(*args, b - SCC_STRING1 + 1);
    01052         buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
    01053         next_substr_case_index = 0;
    01054         break;
    01055       }
    01056
    01057       case SCC_COMMA: // {COMMA}
    01058         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
    01059         break;
    01060
    01061       case SCC_DECIMAL: {// {DECIMAL}
    01062         int64 number = args->GetInt64(SCC_DECIMAL);
    01063         int digits = args->GetInt32(SCC_DECIMAL);
    01064         buff = FormatCommaNumber(buff, number, last, digits);
    01065         break;
    01066       }
    01067
    01068       case SCC_NUM: // {NUM}
    01069         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
    01070         break;
    01071
    01072       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    01073         int64 num = args->GetInt64();
    01074         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
    01075         break;
    01076       }
    01077
    01078       case SCC_HEX: // {HEX}
    01079         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
    01080         break;
    01081
    01082       case SCC_BYTES: // {BYTES}
    01083         buff = FormatBytes(buff, args->GetInt64(), last);
    01084         break;
    01085
    01086       case SCC_CARGO_TINY: { // {CARGO_TINY}
    01087         /* Tiny description of cargotypes. Layout:
    01088          * param 1: cargo type
    01089          * param 2: cargo count */
    01090         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
    01091         if (cargo >= CargoSpec::GetArraySize()) break;
    01092
    01093         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01094         int64 amount = 0;
    01095         switch (cargo_str) {
    01096           case STR_TONS:
    01097             amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
    01098             break;
    01099
    01100           case STR_LITERS:
    01101             amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
    01102             break;
    01103
    01104           default: {
    01105             amount = args->GetInt64();
    01106             break;
    01107           }
    01108         }
    01109
    01110         buff = FormatCommaNumber(buff, amount, last);
    01111         break;
    01112       }
    01113
    01114       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
    01115         /* Short description of cargotypes. Layout:
    01116          * param 1: cargo type
    01117          * param 2: cargo count */
    01118         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
    01119         if (cargo >= CargoSpec::GetArraySize()) break;
    01120
    01121         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
    01122         switch (cargo_str) {
    01123           case STR_TONS: {
    01124             assert(_settings_game.locale.units < lengthof(_units));
    01125             int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01126             StringParameters tmp_params(args_array);
    01127             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01128             break;
    01129           }
    01130
    01131           case STR_LITERS: {
    01132             assert(_settings_game.locale.units < lengthof(_units));
    01133             int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01134             StringParameters tmp_params(args_array);
    01135             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01136             break;
    01137           }
    01138
    01139           default: {
    01140             StringParameters tmp_params(*args, 1);
    01141             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
    01142             break;
    01143           }
    01144         }
    01145         break;
    01146       }
    01147
    01148       case SCC_CARGO_LONG: { // {CARGO_LONG}
    01149         /* First parameter is cargo type, second parameter is cargo count */
    01150         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
    01151         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
    01152
    01153         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    01154         StringParameters tmp_args(*args, 1);
    01155         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
    01156         break;
    01157       }
    01158
    01159       case SCC_CARGO_LIST: { // {CARGO_LIST}
    01160         uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
    01161         bool first = true;
    01162
    01163         const CargoSpec *cs;
    01164         FOR_ALL_SORTED_CARGOSPECS(cs) {
    01165           if (!HasBit(cmask, cs->Index())) continue;
    01166
    01167           if (buff >= last - 2) break; // ',' and ' '
    01168
    01169           if (first) {
    01170             first = false;
    01171           } else {
    01172             /* Add a comma if this is not the first item */
    01173             *buff++ = ',';
    01174             *buff++ = ' ';
    01175           }
    01176
    01177           buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
    01178         }
    01179
    01180         /* If first is still true then no cargo is accepted */
    01181         if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
    01182
    01183         *buff = '\0';
    01184         next_substr_case_index = 0;
    01185
    01186         /* Make sure we detect any buffer overflow */
    01187         assert(buff < last);
    01188         break;
    01189       }
    01190
    01191       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
    01192         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
    01193         break;
    01194
    01195       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
    01196         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
    01197         break;
    01198
    01199       case SCC_DATE_TINY: // {DATE_TINY}
    01200         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
    01201         break;
    01202
    01203       case SCC_DATE_SHORT: // {DATE_SHORT}
    01204         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
    01205         next_substr_case_index = 0;
    01206         break;
    01207
    01208       case SCC_DATE_LONG: // {DATE_LONG}
    01209         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
    01210         next_substr_case_index = 0;
    01211         break;
    01212
    01213       case SCC_DATE_ISO: // {DATE_ISO}
    01214         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
    01215         break;
    01216
    01217       case SCC_FORCE: { // {FORCE}
    01218         assert(_settings_game.locale.units < lengthof(_units));
    01219         int64 args_array[1] = {_units[_settings_game.locale.units].c_force.ToDisplay(args->GetInt64())};
    01220         StringParameters tmp_params(args_array);
    01221         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), &tmp_params, last);
    01222         break;
    01223       }
    01224
    01225       case SCC_HEIGHT: { // {HEIGHT}
    01226         int64 args_array[] = {_units[_settings_game.locale.units].c_height.ToDisplay(args->GetInt64())};
    01227         StringParameters tmp_params(args_array);
    01228         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), &tmp_params, last);
    01229         break;
    01230       }
    01231
    01232       case SCC_POWER: { // {POWER}
    01233         assert(_settings_game.locale.units < lengthof(_units));
    01234         int64 args_array[1] = {_units[_settings_game.locale.units].c_power.ToDisplay(args->GetInt64())};
    01235         StringParameters tmp_params(args_array);
    01236         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), &tmp_params, last);
    01237         break;
    01238       }
    01239
    01240       case SCC_VELOCITY: { // {VELOCITY}
    01241         assert(_settings_game.locale.units < lengthof(_units));
    01242         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
    01243         StringParameters tmp_params(args_array);
    01244         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), &tmp_params, last);
    01245         break;
    01246       }
    01247
    01248       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
    01249         assert(_settings_game.locale.units < lengthof(_units));
    01250         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
    01251         StringParameters tmp_params(args_array);
    01252         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), &tmp_params, last);
    01253         break;
    01254       }
    01255
    01256       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
    01257         assert(_settings_game.locale.units < lengthof(_units));
    01258         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
    01259         StringParameters tmp_params(args_array);
    01260         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
    01261         break;
    01262       }
    01263
    01264       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
    01265         assert(_settings_game.locale.units < lengthof(_units));
    01266         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
    01267         StringParameters tmp_params(args_array);
    01268         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), &tmp_params, last);
    01269         break;
    01270       }
    01271
    01272       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
    01273         assert(_settings_game.locale.units < lengthof(_units));
    01274         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
    01275         StringParameters tmp_params(args_array);
    01276         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
    01277         break;
    01278       }
    01279
    01280       case SCC_COMPANY_NAME: { // {COMPANY}
    01281         const Company *c = Company::GetIfValid(args->GetInt32());
    01282         if (c == NULL) break;
    01283
    01284         if (c->name != NULL) {
    01285           int64 args_array[] = {(uint64)(size_t)c->name};
    01286           StringParameters tmp_params(args_array);
    01287           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01288         } else {
    01289           int64 args_array[] = {c->name_2};
    01290           StringParameters tmp_params(args_array);
    01291           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
    01292         }
    01293         break;
    01294       }
    01295
    01296       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
    01297         CompanyID company = (CompanyID)args->GetInt32();
    01298
    01299         /* Nothing is added for AI or inactive companies */
    01300         if (Company::IsValidHumanID(company)) {
    01301           int64 args_array[] = {company + 1};
    01302           StringParameters tmp_params(args_array);
    01303           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
    01304         }
    01305         break;
    01306       }
    01307
    01308       case SCC_DEPOT_NAME: { // {DEPOT}
    01309         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
    01310         if (vt == VEH_AIRCRAFT) {
    01311           uint64 args_array[] = {args->GetInt32()};
    01312           WChar types_array[] = {SCC_STATION_NAME};
    01313           StringParameters tmp_params(args_array, 1, types_array);
    01314           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
    01315           break;
    01316         }
    01317
    01318         const Depot *d = Depot::Get(args->GetInt32());
    01319         if (d->name != NULL) {
    01320           int64 args_array[] = {(uint64)(size_t)d->name};
    01321           StringParameters tmp_params(args_array);
    01322           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01323         } else {
    01324           int64 args_array[] = {d->town->index, d->town_cn + 1};
    01325           StringParameters tmp_params(args_array);
    01326           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
    01327         }
    01328         break;
    01329       }
    01330
    01331       case SCC_ENGINE_NAME: { // {ENGINE}
    01332         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
    01333         if (e == NULL) break;
    01334
    01335         if (e->name != NULL && e->IsEnabled()) {
    01336           int64 args_array[] = {(uint64)(size_t)e->name};
    01337           StringParameters tmp_params(args_array);
    01338           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01339         } else {
    01340           StringParameters tmp_params(NULL, 0, NULL);
    01341           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
    01342         }
    01343         break;
    01344       }
    01345
    01346       case SCC_GROUP_NAME: { // {GROUP}
    01347         const Group *g = Group::GetIfValid(args->GetInt32());
    01348         if (g == NULL) break;
    01349
    01350         if (g->name != NULL) {
    01351           int64 args_array[] = {(uint64)(size_t)g->name};
    01352           StringParameters tmp_params(args_array);
    01353           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01354         } else {
    01355           int64 args_array[] = {g->index};
    01356           StringParameters tmp_params(args_array);
    01357
    01358           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
    01359         }
    01360         break;
    01361       }
    01362
    01363       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    01364         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
    01365         if (i == NULL) break;
    01366
    01367         if (_scan_for_gender_data) {
    01368           /* Gender is defined by the industry type.
    01369            * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
    01370           StringParameters tmp_params(NULL, 0, NULL);
    01371           buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
    01372         } else {
    01373           /* First print the town name and the industry type name. */
    01374           int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
    01375           StringParameters tmp_params(args_array);
    01376
    01377           buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
    01378         }
    01379         next_substr_case_index = 0;
    01380         break;
    01381       }
    01382
    01383       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
    01384         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
    01385         if (c == NULL) break;
    01386
    01387         if (c->president_name != NULL) {
    01388           int64 args_array[] = {(uint64)(size_t)c->president_name};
    01389           StringParameters tmp_params(args_array);
    01390           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01391         } else {
    01392           int64 args_array[] = {c->president_name_2};
    01393           StringParameters tmp_params(args_array);
    01394           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
    01395         }
    01396         break;
    01397       }
    01398
    01399       case SCC_STATION_NAME: { // {STATION}
    01400         StationID sid = args->GetInt32(SCC_STATION_NAME);
    01401         const Station *st = Station::GetIfValid(sid);
    01402
    01403         if (st == NULL) {
    01404           /* The station doesn't exist anymore. The only place where we might
    01405            * be "drawing" an invalid station is in the case of cargo that is
    01406            * in transit. */
    01407           StringParameters tmp_params(NULL, 0, NULL);
    01408           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
    01409           break;
    01410         }
    01411
    01412         if (st->name != NULL) {
    01413           int64 args_array[] = {(uint64)(size_t)st->name};
    01414           StringParameters tmp_params(args_array);
    01415           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01416         } else {
    01417           StringID str = st->string_id;
    01418           if (st->indtype != IT_INVALID) {
    01419             /* Special case where the industry provides the name for the station */
    01420             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    01421
    01422             /* Industry GRFs can change which might remove the station name and
    01423              * thus cause very strange things. Here we check for that before we
    01424              * actually set the station name. */
    01425             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    01426               str = indsp->station_name;
    01427             }
    01428           }
    01429
    01430           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
    01431           StringParameters tmp_params(args_array);
    01432           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01433         }
    01434         break;
    01435       }
    01436
    01437       case SCC_TOWN_NAME: { // {TOWN}
    01438         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
    01439         if (t == NULL) break;
    01440
    01441         if (t->name != NULL) {
    01442           int64 args_array[] = {(uint64)(size_t)t->name};
    01443           StringParameters tmp_params(args_array);
    01444           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01445         } else {
    01446           buff = GetTownName(buff, t, last);
    01447         }
    01448         break;
    01449       }
    01450
    01451       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    01452         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
    01453         if (wp == NULL) break;
    01454
    01455         if (wp->name != NULL) {
    01456           int64 args_array[] = {(uint64)(size_t)wp->name};
    01457           StringParameters tmp_params(args_array);
    01458           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01459         } else {
    01460           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
    01461           StringParameters tmp_params(args_array);
    01462           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    01463           if (wp->town_cn != 0) str++;
    01464           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01465         }
    01466         break;
    01467       }
    01468
    01469       case SCC_VEHICLE_NAME: { // {VEHICLE}
    01470         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
    01471         if (v == NULL) break;
    01472
    01473         if (v->name != NULL) {
    01474           int64 args_array[] = {(uint64)(size_t)v->name};
    01475           StringParameters tmp_params(args_array);
    01476           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01477         } else {
    01478           int64 args_array[] = {v->unitnumber};
    01479           StringParameters tmp_params(args_array);
    01480
    01481           StringID str;
    01482           switch (v->type) {
    01483             default: NOT_REACHED();
    01484             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    01485             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    01486             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    01487             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    01488           }
    01489
    01490           buff = GetStringWithArgs(buff, str, &tmp_params, last);
    01491         }
    01492         break;
    01493       }
    01494
    01495       case SCC_SIGN_NAME: { // {SIGN}
    01496         const Sign *si = Sign::GetIfValid(args->GetInt32());
    01497         if (si == NULL) break;
    01498
    01499         if (si->name != NULL) {
    01500           int64 args_array[] = {(uint64)(size_t)si->name};
    01501           StringParameters tmp_params(args_array);
    01502           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
    01503         } else {
    01504           StringParameters tmp_params(NULL, 0, NULL);
    01505           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
    01506         }
    01507         break;
    01508       }
    01509
    01510       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    01511         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
    01512         break;
    01513       }
    01514
    01515       default:
    01516         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01517         break;
    01518     }
    01519   }
    01520   *buff = '\0';
    01521   return buff;
    01522 }
    01523
    01524
    01525 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01526 {
    01527   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01528   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01529   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01530   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01531   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01532   *buff = '\0';
    01533   return buff;
    01534 }
    01535
    01536 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01537 {
    01538   return GenerateTownNameString(buff, last, ind, seed);
    01539 }
    01540
    01541 static const char * const _silly_company_names[] = {
    01542   "Bloggs Brothers",
    01543   "Tiny Transport Ltd.",
    01544   "Express Travel",
    01545   "Comfy-Coach & Co.",
    01546   "Crush & Bump Ltd.",
    01547   "Broken & Late Ltd.",
    01548   "Sam Speedy & Son",
    01549   "Supersonic Travel",
    01550   "Mike's Motors",
    01551   "Lightning International",
    01552   "Pannik & Loozit Ltd.",
    01553   "Inter-City Transport",
    01554   "Getout & Pushit Ltd."
    01555 };
    01556
    01557 static const char * const _surname_list[] = {
    01558   "Adams",
    01559   "Allan",
    01560   "Baker",
    01561   "Bigwig",
    01562   "Black",
    01563   "Bloggs",
    01564   "Brown",
    01565   "Campbell",
    01566   "Gordon",
    01567   "Hamilton",
    01568   "Hawthorn",
    01569   "Higgins",
    01570   "Green",
    01571   "Gribble",
    01572   "Jones",
    01573   "McAlpine",
    01574   "MacDonald",
    01575   "McIntosh",
    01576   "Muir",
    01577   "Murphy",
    01578   "Nelson",
    01579   "O'Donnell",
    01580   "Parker",
    01581   "Phillips",
    01582   "Pilkington",
    01583   "Quigley",
    01584   "Sharkey",
    01585   "Thomson",
    01586   "Watkins"
    01587 };
    01588
    01589 static const char * const _silly_surname_list[] = {
    01590   "Grumpy",
    01591   "Dozy",
    01592   "Speedy",
    01593   "Nosey",
    01594   "Dribble",
    01595   "Mushroom",
    01596   "Cabbage",
    01597   "Sniffle",
    01598   "Fishy",
    01599   "Swindle",
    01600   "Sneaky",
    01601   "Nutkins"
    01602 };
    01603
    01604 static const char _initial_name_letters[] = {
    01605   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01606   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01607 };
    01608
    01609 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01610 {
    01611   const char * const *base;
    01612   uint num;
    01613
    01614   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01615     base = _silly_surname_list;
    01616     num  = lengthof(_silly_surname_list);
    01617   } else {
    01618     base = _surname_list;
    01619     num  = lengthof(_surname_list);
    01620   }
    01621
    01622   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01623   buff = strecpy(buff, " & Co.", last);
    01624
    01625   return buff;
    01626 }
    01627
    01628 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01629 {
    01630   char initial[] = "?. ";
    01631   const char * const *base;
    01632   uint num;
    01633   uint i;
    01634
    01635   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01636   buff = strecpy(buff, initial, last);
    01637
    01638   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01639   if (i < sizeof(_initial_name_letters)) {
    01640     initial[0] = _initial_name_letters[i];
    01641     buff = strecpy(buff, initial, last);
    01642   }
    01643
    01644   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01645     base = _silly_surname_list;
    01646     num  = lengthof(_silly_surname_list);
    01647   } else {
    01648     base = _surname_list;
    01649     num  = lengthof(_surname_list);
    01650   }
    01651
    01652   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01653
    01654   return buff;
    01655 }
    01656
    01657 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
    01658 {
    01659   switch (ind) {
    01660     case 1: // not used
    01661       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
    01662
    01663     case 2: // used for Foobar & Co company names
    01664       return GenAndCoName(buff, args->GetInt32(), last);
    01665
    01666     case 3: // President name
    01667       return GenPresidentName(buff, args->GetInt32(), last);
    01668   }
    01669
    01670   /* town name? */
    01671   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01672     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
    01673     return strecpy(buff, " Transport", last);
    01674   }
    01675
    01676   /* language name? */
    01677   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01678     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01679     return strecpy(buff,
    01680       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
    01681   }
    01682
    01683   /* resolution size? */
    01684   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01685     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01686     buff += seprintf(
    01687       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01688     );
    01689     return buff;
    01690   }
    01691
    01692   /* screenshot format name? */
    01693   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01694     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01695     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01696   }
    01697
    01698   NOT_REACHED();
    01699 }
    01700
    01701 #ifdef ENABLE_NETWORK
    01702 extern void SortNetworkLanguages();
    01703 #else /* ENABLE_NETWORK */
    01704 static inline void SortNetworkLanguages() {}
    01705 #endif /* ENABLE_NETWORK */
    01706
    01711 bool LanguagePackHeader::IsValid() const
    01712 {
    01713   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
    01714          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
    01715          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
    01716          this->text_dir     <= 1 &&
    01717          this->newgrflangid < MAX_LANG &&
    01718          this->num_genders  < MAX_NUM_GENDERS &&
    01719          this->num_cases    < MAX_NUM_CASES &&
    01720          StrValid(this->name,                           lastof(this->name)) &&
    01721          StrValid(this->own_name,                       lastof(this->own_name)) &&
    01722          StrValid(this->isocode,                        lastof(this->isocode)) &&
    01723          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
    01724          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
    01725          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
    01726 }
    01727
    01733 bool ReadLanguagePack(const LanguageMetadata *lang)
    01734 {
    01735   /* Current language pack */
    01736   size_t len;
    01737   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
    01738   if (lang_pack == NULL) return false;
    01739
    01740   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01741   const char *end = (char *)lang_pack + len + 1;
    01742
    01743   /* We need at least one byte of lang_pack->data */
    01744   if (end <= lang_pack->data || !lang_pack->IsValid()) {
    01745     free(lang_pack);
    01746     return false;
    01747   }
    01748
    01749 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01750   for (uint i = 0; i < TAB_COUNT; i++) {
    01751     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01752   }
    01753 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01754
    01755   uint count = 0;
    01756   for (uint i = 0; i < TAB_COUNT; i++) {
    01757     uint num = lang_pack->offsets[i];
    01758     _langtab_start[i] = count;
    01759     _langtab_num[i] = num;
    01760     count += num;
    01761   }
    01762
    01763   /* Allocate offsets */
    01764   char **langpack_offs = MallocT<char *>(count);
    01765
    01766   /* Fill offsets */
    01767   char *s = lang_pack->data;
    01768   len = (byte)*s++;
    01769   for (uint i = 0; i < count; i++) {
    01770     if (s + len >= end) {
    01771       free(lang_pack);
    01772       free(langpack_offs);
    01773       return false;
    01774     }
    01775     if (len >= 0xC0) {
    01776       len = ((len & 0x3F) << 8) + (byte)*s++;
    01777       if (s + len >= end) {
    01778         free(lang_pack);
    01779         free(langpack_offs);
    01780         return false;
    01781       }
    01782     }
    01783     langpack_offs[i] = s;
    01784     s += len;
    01785     len = (byte)*s;
    01786     *s++ = '\0'; // zero terminate the string
    01787   }
    01788
    01789   free(_langpack);
    01790   _langpack = lang_pack;
    01791
    01792   free(_langpack_offs);
    01793   _langpack_offs = langpack_offs;
    01794
    01795   _current_language = lang;
    01796   _current_text_dir = (TextDirection)_current_language->text_dir;
    01797   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
    01798   strecpy(_config_language_file, c_file, lastof(_config_language_file));
    01799   SetCurrentGrfLangID(_current_language->newgrflangid);
    01800
    01801 #ifdef WITH_ICU
    01802   /* Delete previous collator. */
    01803   if (_current_collator != NULL) {
    01804     delete _current_collator;
    01805     _current_collator = NULL;
    01806   }
    01807
    01808   /* Create a collator instance for our current locale. */
    01809   UErrorCode status = U_ZERO_ERROR;
    01810   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
    01811   /* Sort number substrings by their numerical value. */
    01812   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
    01813   /* Avoid using the collator if it is not correctly set. */
    01814   if (U_FAILURE(status)) {
    01815     delete _current_collator;
    01816     _current_collator = NULL;
    01817   }
    01818 #endif /* WITH_ICU */
    01819
    01820   /* Some lists need to be sorted again after a language change. */
    01821   ReconsiderGameScriptLanguage();
    01822   InitializeSortedCargoSpecs();
    01823   SortIndustryTypes();
    01824   BuildIndustriesLegend();
    01825   SortNetworkLanguages();
    01826   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
    01827   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
    01828   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
    01829   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
    01830   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
    01831   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
    01832   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
    01833
    01834   return true;
    01835 }
    01836
    01837 /* Win32 implementation in win32.cpp.
    01838  * OS X implementation in os/macosx/macos.mm. */
    01839 #if !(defined(WIN32) || defined(__APPLE__))
    01840
    01848 const char *GetCurrentLocale(const char *param)
    01849 {
    01850   const char *env;
    01851
    01852   env = getenv("LANGUAGE");
    01853   if (env != NULL) return env;
    01854
    01855   env = getenv("LC_ALL");
    01856   if (env != NULL) return env;
    01857
    01858   if (param != NULL) {
    01859     env = getenv(param);
    01860     if (env != NULL) return env;
    01861   }
    01862
    01863   return getenv("LANG");
    01864 }
    01865 #else
    01866 const char *GetCurrentLocale(const char *param);
    01867 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01868
    01869 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01870 {
    01871   char stra[512];
    01872   char strb[512];
    01873   GetString(stra, *a, lastof(stra));
    01874   GetString(strb, *b, lastof(strb));
    01875
    01876   return strcmp(stra, strb);
    01877 }
    01878
    01884 const LanguageMetadata *GetLanguage(byte newgrflangid)
    01885 {
    01886   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
    01887     if (newgrflangid == lang->newgrflangid) return lang;
    01888   }
    01889
    01890   return NULL;
    01891 }
    01892
    01899 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
    01900 {
    01901   FILE *f = fopen(file, "rb");
    01902   if (f == NULL) return false;
    01903
    01904   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01905   fclose(f);
    01906
    01907   bool ret = read == 1 && hdr->IsValid();
    01908
    01909   /* Convert endianness for the windows language ID */
    01910   if (ret) {
    01911     hdr->missing = FROM_LE16(hdr->missing);
    01912     hdr->winlangid = FROM_LE16(hdr->winlangid);
    01913   }
    01914   return ret;
    01915 }
    01916
    01921 static void GetLanguageList(const char *path)
    01922 {
    01923   DIR *dir = ttd_opendir(path);
    01924   if (dir != NULL) {
    01925     struct dirent *dirent;
    01926     while ((dirent = readdir(dir)) != NULL) {
    01927       const char *d_name    = FS2OTTD(dirent->d_name);
    01928       const char *extension = strrchr(d_name, '.');
    01929
    01930       /* Not a language file */
    01931       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01932
    01933       LanguageMetadata lmd;
    01934       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
    01935
    01936       /* Check whether the file is of the correct version */
    01937       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
    01938         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
    01939       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
    01940         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
    01941       } else {
    01942         *_languages.Append() = lmd;
    01943       }
    01944     }
    01945     closedir(dir);
    01946   }
    01947 }
    01948
    01953 void InitializeLanguagePacks()
    01954 {
    01955   Searchpath sp;
    01956
    01957   FOR_ALL_SEARCHPATHS(sp) {
    01958     char path[MAX_PATH];
    01959     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01960     GetLanguageList(path);
    01961   }
    01962   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
    01963
    01964   /* Acquire the locale of the current system */
    01965   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01966   if (lang == NULL) lang = "en_GB";
    01967
    01968   const LanguageMetadata *chosen_language   = NULL;
    01969   const LanguageMetadata *language_fallback = NULL;
    01970   const LanguageMetadata *en_GB_fallback    = _languages.Begin();
    01971
    01972   /* Find a proper language. */
    01973   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
    01974     /* We are trying to find a default language. The priority is by
    01975      * configuration file, local environment and last, if nothing found,
    01976      * English. */
    01977     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
    01978     if (strcmp(lang_file, _config_language_file) == 0) {
    01979       chosen_language = lng;
    01980       break;
    01981     }
    01982
    01983     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
    01984     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
    01985     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
    01986   }
    01987
    01988   /* We haven't found the language in the config nor the one in the locale.
    01989    * Now we set it to one of the fallback languages */
    01990   if (chosen_language == NULL) {
    01991     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
    01992   }
    01993
    01994   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
    01995 }
    01996
    02001 const char *GetCurrentLanguageIsoCode()
    02002 {
    02003   return _langpack->isocode;
    02004 }
    02005
    02012 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
    02013 {
    02014   InitFreeType(this->Monospace());
    02015   const Sprite *question_mark[FS_END];
    02016
    02017   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
    02018     question_mark[size] = GetGlyph(size, '?');
    02019   }
    02020
    02021   this->Reset();
    02022   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
    02023     FontSize size = this->DefaultSize();
    02024     if (str != NULL) *str = text;
    02025     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
    02026       if (c == SCC_SETX) {
    02027         /* SetX is, together with SetXY as special character that
    02028           * uses the next (two) characters as data points. We have
    02029           * to skip those, otherwise the UTF8 reading will go haywire. */
    02030         text++;
    02031       } else if (c == SCC_SETXY) {
    02032         text += 2;
    02033       } else if (c == SCC_TINYFONT) {
    02034         size = FS_SMALL;
    02035       } else if (c == SCC_BIGFONT) {
    02036         size = FS_LARGE;
    02037       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
    02038         /* The character is printable, but not in the normal font. This is the case we were testing for. */
    02039         return true;
    02040       }
    02041     }
    02042   }
    02043   return false;
    02044 }
    02045
    02047 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
    02048   uint i;
    02049   uint j;
    02050
    02051   /* virtual */ void Reset()
    02052   {
    02053     this->i = 0;
    02054     this->j = 0;
    02055   }
    02056
    02057   /* virtual */ FontSize DefaultSize()
    02058   {
    02059     return FS_NORMAL;
    02060   }
    02061
    02062   /* virtual */ const char *NextString()
    02063   {
    02064     if (this->i >= TAB_COUNT) return NULL;
    02065
    02066     const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
    02067
    02068     this->j++;
    02069     while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) {
    02070       this->i++;
    02071       this->j = 0;
    02072     }
    02073
    02074     return ret;
    02075   }
    02076
    02077   /* virtual */ bool Monospace()
    02078   {
    02079     return false;
    02080   }
    02081
    02082   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
    02083   {
    02084 #ifdef WITH_FREETYPE
    02085     strecpy(settings->small_font,  font_name, lastof(settings->small_font));
    02086     strecpy(settings->medium_font, font_name, lastof(settings->medium_font));
    02087     strecpy(settings->large_font,  font_name, lastof(settings->large_font));
    02088 #endif /* WITH_FREETYPE */
    02089   }
    02090 };
    02091
    02105 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
    02106 {
    02107   static LanguagePackGlyphSearcher pack_searcher;
    02108   if (searcher == NULL) searcher = &pack_searcher;
    02109   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
    02110 #ifdef WITH_FREETYPE
    02111   if (bad_font) {
    02112     /* We found an unprintable character... lets try whether we can find
    02113      * a fallback font that can print the characters in the current language. */
    02114     FreeTypeSettings backup;
    02115     memcpy(&backup, &_freetype, sizeof(backup));
    02116
    02117     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
    02118
    02119     memcpy(&_freetype, &backup, sizeof(backup));
    02120
    02121     if (bad_font && base_font) {
    02122       /* Our fallback font does miss characters too, so keep the
    02123        * user chosen font as that is more likely to be any good than
    02124        * the wild guess we made */
    02125       InitFreeType(searcher->Monospace());
    02126     }
    02127   }
    02128 #endif
    02129
    02130   if (bad_font) {
    02131     /* All attempts have failed. Display an error. As we do not want the string to be translated by
    02132      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
    02133      * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
    02134      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
    02135      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
    02136     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.");
    02137     Utf8Encode(err_str, SCC_YELLOW);
    02138     SetDParamStr(0, err_str);
    02139     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
    02140
    02141     /* Reset the font width */
    02142     LoadStringWidthTable(searcher->Monospace());
    02143     return;
    02144   }
    02145
    02146   /* Update the font with cache */
    02147   LoadStringWidthTable(searcher->Monospace());
    02148
    02149 #if !defined(WITH_ICU)
    02150   /*
    02151    * For right-to-left languages we need the ICU library. If
    02152    * we do not have support for that library we warn the user
    02153    * about it with a message. As we do not want the string to
    02154    * be translated by the translators, we 'force' it into the
    02155    * binary and 'load' it via a BindCString. To do this
    02156    * properly we have to set the colour of the string,
    02157    * otherwise we end up with a lot of artifacts. The colour
    02158    * 'character' might change in the future, so for safety
    02159    * we just Utf8 Encode it into the string, which takes
    02160    * exactly three characters, so it replaces the "XXX" with
    02161    * the colour marker.
    02162    */
    02163   if (_current_text_dir != TD_LTR) {
    02164     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    02165     Utf8Encode(err_str, SCC_YELLOW);
    02166     SetDParamStr(0, err_str);
    02167     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
    02168   }
    02169 #endif
    02170 }