strings.cpp

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