strings.cpp

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