strings.cpp

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