strings.cpp

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