strings.cpp

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