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 }