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