strings.cpp

Go to the documentation of this file.
00001 /* $Id: strings.cpp 26063 2013-11-23 13:24:31Z 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 
00677 struct Units {
00678   UnitConversion c; 
00679   StringID s;       
00680 };
00681 
00683 struct UnitsLong {
00684   UnitConversion c; 
00685   StringID s;       
00686   StringID l;       
00687 };
00688 
00690 static const Units _units_velocity[] = {
00691   { {   1,  0}, STR_UNITS_VELOCITY_IMPERIAL },
00692   { { 103,  6}, STR_UNITS_VELOCITY_METRIC   },
00693   { {1831, 12}, STR_UNITS_VELOCITY_SI       },
00694 };
00695 
00697 static const Units _units_power[] = {
00698   { {   1,  0}, STR_UNITS_POWER_IMPERIAL },
00699   { {4153, 12}, STR_UNITS_POWER_METRIC   },
00700   { {6109, 13}, STR_UNITS_POWER_SI       },
00701 };
00702 
00704 static const UnitsLong _units_weight[] = {
00705   { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
00706   { {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC,   STR_UNITS_WEIGHT_LONG_METRIC   },
00707   { {1000,  0}, STR_UNITS_WEIGHT_SHORT_SI,       STR_UNITS_WEIGHT_LONG_SI       },
00708 };
00709 
00711 static const UnitsLong _units_volume[] = {
00712   { {4227,  4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
00713   { {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC,   STR_UNITS_VOLUME_LONG_METRIC   },
00714   { {   1,  0}, STR_UNITS_VOLUME_SHORT_SI,       STR_UNITS_VOLUME_LONG_SI       },
00715 };
00716 
00718 static const Units _units_force[] = {
00719   { {3597,  4}, STR_UNITS_FORCE_IMPERIAL },
00720   { {3263,  5}, STR_UNITS_FORCE_METRIC   },
00721   { {   1,  0}, STR_UNITS_FORCE_SI       },
00722 };
00723 
00725 static const Units _units_height[] = {
00726   { {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL }, // "Wrong" conversion factor for more nicer GUI values
00727   { {   1,  0}, STR_UNITS_HEIGHT_METRIC   },
00728   { {   1,  0}, STR_UNITS_HEIGHT_SI       },
00729 };
00730 
00736 uint ConvertSpeedToDisplaySpeed(uint speed)
00737 {
00738   /* For historical reasons we don't want to mess with the
00739    * conversion for speed. So, don't round it and keep the
00740    * original conversion factors instead of the real ones. */
00741   return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed, false);
00742 }
00743 
00749 uint ConvertDisplaySpeedToSpeed(uint speed)
00750 {
00751   return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed);
00752 }
00753 
00759 uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
00760 {
00761   return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16;
00762 }
00763 
00769 uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
00770 {
00771   return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10);
00772 }
00782 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
00783 {
00784   uint orig_offset = args->offset;
00785 
00786   /* When there is no array with types there is no need to do a dry run. */
00787   if (args->HasTypeInformation() && !dry_run) {
00788     if (UsingNewGRFTextStack()) {
00789       /* Values from the NewGRF text stack are only copied to the normal
00790        * argv array at the time they are encountered. That means that if
00791        * another string command references a value later in the string it
00792        * would fail. We solve that by running FormatString twice. The first
00793        * pass makes sure the argv array is correctly filled and the second
00794        * pass can reference later values without problems. */
00795       struct TextRefStack *backup = CreateTextRefStackBackup();
00796       FormatString(buff, str_arg, args, last, case_index, game_script, true);
00797       RestoreTextRefStackBackup(backup);
00798     } else {
00799       FormatString(buff, str_arg, args, last, case_index, game_script, true);
00800     }
00801     /* We have to restore the original offset here to to read the correct values. */
00802     args->offset = orig_offset;
00803   }
00804   WChar b = '\0';
00805   uint next_substr_case_index = 0;
00806   char *buf_start = buff;
00807   std::stack<const char *> str_stack;
00808   str_stack.push(str_arg);
00809 
00810   for (;;) {
00811     while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
00812       str_stack.pop();
00813     }
00814     if (str_stack.empty()) break;
00815     const char *&str = str_stack.top();
00816 
00817     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
00818       /* We need to pass some stuff as it might be modified; oh boy. */
00819       //todo: should argve be passed here too?
00820       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), dry_run);
00821       if (b == 0) continue;
00822     }
00823 
00824     switch (b) {
00825       case SCC_ENCODED: {
00826         uint64 sub_args_data[20];
00827         WChar sub_args_type[20];
00828         bool sub_args_need_free[20];
00829         StringParameters sub_args(sub_args_data, 20, sub_args_type);
00830 
00831         sub_args.ClearTypeInformation();
00832         memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
00833 
00834         uint16 stringid;
00835         const char *s = str;
00836         char *p;
00837         stringid = strtol(str, &p, 16);
00838         if (*p != ':' && *p != '\0') {
00839           while (*p != '\0') p++;
00840           str = p;
00841           buff = strecat(buff, "(invalid SCC_ENCODED)", last);
00842           break;
00843         }
00844         if (stringid >= TAB_SIZE) {
00845           while (*p != '\0') p++;
00846           str = p;
00847           buff = strecat(buff, "(invalid StringID)", last);
00848           break;
00849         }
00850 
00851         int i = 0;
00852         while (*p != '\0' && i < 20) {
00853           uint64 param;
00854           s = ++p;
00855 
00856           /* Find the next value */
00857           bool instring = false;
00858           bool escape = false;
00859           for (;; p++) {
00860             if (*p == '\\') {
00861               escape = true;
00862               continue;
00863             }
00864             if (*p == '"' && escape) {
00865               escape = false;
00866               continue;
00867             }
00868             escape = false;
00869 
00870             if (*p == '"') {
00871               instring = !instring;
00872               continue;
00873             }
00874             if (instring) {
00875               continue;
00876             }
00877 
00878             if (*p == ':') break;
00879             if (*p == '\0') break;
00880           }
00881 
00882           if (*s != '"') {
00883             /* Check if we want to look up another string */
00884             WChar l;
00885             size_t len = Utf8Decode(&l, s);
00886             bool lookup = (l == SCC_ENCODED);
00887             if (lookup) s += len;
00888 
00889             param = (int32)strtoul(s, &p, 16);
00890 
00891             if (lookup) {
00892               if (param >= TAB_SIZE) {
00893                 while (*p != '\0') p++;
00894                 str = p;
00895                 buff = strecat(buff, "(invalid sub-StringID)", last);
00896                 break;
00897               }
00898               param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param;
00899             }
00900 
00901             sub_args.SetParam(i++, param);
00902           } else {
00903             char *g = strdup(s);
00904             g[p - s] = '\0';
00905 
00906             sub_args_need_free[i] = true;
00907             sub_args.SetParam(i++, (uint64)(size_t)g);
00908           }
00909         }
00910         /* If we didn't error out, we can actually print the string. */
00911         if (*str != '\0') {
00912           str = p;
00913           buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
00914         }
00915 
00916         for (int i = 0; i < 20; i++) {
00917           if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
00918         }
00919         break;
00920       }
00921 
00922       case SCC_NEWGRF_STRINL: {
00923         StringID substr = Utf8Consume(&str);
00924         str_stack.push(GetStringPtr(substr));
00925         break;
00926       }
00927 
00928       case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
00929         StringID substr = args->GetInt32(SCC_NEWGRF_PRINT_WORD_STRING_ID);
00930         str_stack.push(GetStringPtr(substr));
00931         case_index = next_substr_case_index;
00932         next_substr_case_index = 0;
00933         break;
00934       }
00935 
00936 
00937       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
00938         /* First read the meta data from the language file. */
00939         uint offset = orig_offset + (byte)*str++;
00940         int gender = 0;
00941         if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
00942           /* Now we need to figure out what text to resolve, i.e.
00943            * what do we need to draw? So get the actual raw string
00944            * first using the control code to get said string. */
00945           char input[4 + 1];
00946           char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
00947           *p = '\0';
00948 
00949           /* Now do the string formatting. */
00950           char buf[256];
00951           bool old_sgd = _scan_for_gender_data;
00952           _scan_for_gender_data = true;
00953           StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
00954           p = FormatString(buf, input, &tmp_params, lastof(buf));
00955           _scan_for_gender_data = old_sgd;
00956           *p = '\0';
00957 
00958           /* And determine the string. */
00959           const char *s = buf;
00960           WChar c = Utf8Consume(&s);
00961           /* Does this string have a gender, if so, set it */
00962           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
00963         }
00964         str = ParseStringChoice(str, gender, &buff, last);
00965         break;
00966       }
00967 
00968       /* This sets up the gender for the string.
00969        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
00970       case SCC_GENDER_INDEX: // {GENDER 0}
00971         if (_scan_for_gender_data) {
00972           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
00973           *buff++ = *str++;
00974         } else {
00975           str++;
00976         }
00977         break;
00978 
00979       case SCC_PLURAL_LIST: { // {P}
00980         int plural_form = *str++;          // contains the plural form for this string
00981         uint offset = orig_offset + (byte)*str++;
00982         int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
00983         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
00984         break;
00985       }
00986 
00987       case SCC_ARG_INDEX: { // Move argument pointer
00988         args->offset = orig_offset + (byte)*str++;
00989         break;
00990       }
00991 
00992       case SCC_SET_CASE: { // {SET_CASE}
00993         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
00994          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
00995         next_substr_case_index = (byte)*str++;
00996         break;
00997       }
00998 
00999       case SCC_SWITCH_CASE: { // {Used to implement case switching}
01000         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
01001          * Each LEN is printed using 2 bytes in big endian order. */
01002         uint num = (byte)*str++;
01003         while (num) {
01004           if ((byte)str[0] == case_index) {
01005             /* Found the case, adjust str pointer and continue */
01006             str += 3;
01007             break;
01008           }
01009           /* Otherwise skip to the next case */
01010           str += 3 + (str[1] << 8) + str[2];
01011           num--;
01012         }
01013         break;
01014       }
01015 
01016       case SCC_REVISION: // {REV}
01017         buff = strecpy(buff, _openttd_revision, last);
01018         break;
01019 
01020       case SCC_STRING_ID: // {STRINL}
01021         if (game_script) break;
01022         buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
01023         break;
01024 
01025       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
01026         if (game_script) break;
01027         const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
01028         buff = FormatString(buff, str, args, last);
01029         break;
01030       }
01031 
01032       case SCC_STRING: {// {STRING}
01033         StringID str = args->GetInt32(SCC_STRING);
01034         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
01035         /* WARNING. It's prohibited for the included string to consume any arguments.
01036          * For included strings that consume argument, you should use STRING1, STRING2 etc.
01037          * To debug stuff you can set argv to NULL and it will tell you */
01038         StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
01039         buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
01040         next_substr_case_index = 0;
01041         break;
01042       }
01043 
01044       case SCC_STRING1:
01045       case SCC_STRING2:
01046       case SCC_STRING3:
01047       case SCC_STRING4:
01048       case SCC_STRING5:
01049       case SCC_STRING6:
01050       case SCC_STRING7: { // {STRING1..7}
01051         /* Strings that consume arguments */
01052         StringID str = args->GetInt32(b);
01053         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
01054         uint size = b - SCC_STRING1 + 1;
01055         if (game_script && size > args->num_param - args->offset) {
01056           buff = strecat(buff, "(too many parameters)", last);
01057         } else {
01058           StringParameters sub_args(*args, size);
01059           buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
01060         }
01061         next_substr_case_index = 0;
01062         break;
01063       }
01064 
01065       case SCC_COMMA: // {COMMA}
01066         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
01067         break;
01068 
01069       case SCC_DECIMAL: {// {DECIMAL}
01070         int64 number = args->GetInt64(SCC_DECIMAL);
01071         int digits = args->GetInt32(SCC_DECIMAL);
01072         buff = FormatCommaNumber(buff, number, last, digits);
01073         break;
01074       }
01075 
01076       case SCC_NUM: // {NUM}
01077         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
01078         break;
01079 
01080       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
01081         int64 num = args->GetInt64();
01082         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
01083         break;
01084       }
01085 
01086       case SCC_HEX: // {HEX}
01087         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
01088         break;
01089 
01090       case SCC_BYTES: // {BYTES}
01091         buff = FormatBytes(buff, args->GetInt64(), last);
01092         break;
01093 
01094       case SCC_CARGO_TINY: { // {CARGO_TINY}
01095         /* Tiny description of cargotypes. Layout:
01096          * param 1: cargo type
01097          * param 2: cargo count */
01098         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
01099         if (cargo >= CargoSpec::GetArraySize()) break;
01100 
01101         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01102         int64 amount = 0;
01103         switch (cargo_str) {
01104           case STR_TONS:
01105             amount = _units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64());
01106             break;
01107 
01108           case STR_LITERS:
01109             amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64());
01110             break;
01111 
01112           default: {
01113             amount = args->GetInt64();
01114             break;
01115           }
01116         }
01117 
01118         buff = FormatCommaNumber(buff, amount, last);
01119         break;
01120       }
01121 
01122       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
01123         /* Short description of cargotypes. Layout:
01124          * param 1: cargo type
01125          * param 2: cargo count */
01126         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
01127         if (cargo >= CargoSpec::GetArraySize()) break;
01128 
01129         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01130         switch (cargo_str) {
01131           case STR_TONS: {
01132             assert(_settings_game.locale.units_weight < lengthof(_units_weight));
01133             int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
01134             StringParameters tmp_params(args_array);
01135             buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
01136             break;
01137           }
01138 
01139           case STR_LITERS: {
01140             assert(_settings_game.locale.units_volume < lengthof(_units_volume));
01141             int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
01142             StringParameters tmp_params(args_array);
01143             buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
01144             break;
01145           }
01146 
01147           default: {
01148             StringParameters tmp_params(*args, 1);
01149             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
01150             break;
01151           }
01152         }
01153         break;
01154       }
01155 
01156       case SCC_CARGO_LONG: { // {CARGO_LONG}
01157         /* First parameter is cargo type, second parameter is cargo count */
01158         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
01159         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
01160 
01161         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
01162         StringParameters tmp_args(*args, 1);
01163         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
01164         break;
01165       }
01166 
01167       case SCC_CARGO_LIST: { // {CARGO_LIST}
01168         uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
01169         bool first = true;
01170 
01171         const CargoSpec *cs;
01172         FOR_ALL_SORTED_CARGOSPECS(cs) {
01173           if (!HasBit(cmask, cs->Index())) continue;
01174 
01175           if (buff >= last - 2) break; // ',' and ' '
01176 
01177           if (first) {
01178             first = false;
01179           } else {
01180             /* Add a comma if this is not the first item */
01181             *buff++ = ',';
01182             *buff++ = ' ';
01183           }
01184 
01185           buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
01186         }
01187 
01188         /* If first is still true then no cargo is accepted */
01189         if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
01190 
01191         *buff = '\0';
01192         next_substr_case_index = 0;
01193 
01194         /* Make sure we detect any buffer overflow */
01195         assert(buff < last);
01196         break;
01197       }
01198 
01199       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
01200         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
01201         break;
01202 
01203       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
01204         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
01205         break;
01206 
01207       case SCC_DATE_TINY: // {DATE_TINY}
01208         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
01209         break;
01210 
01211       case SCC_DATE_SHORT: // {DATE_SHORT}
01212         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
01213         next_substr_case_index = 0;
01214         break;
01215 
01216       case SCC_DATE_LONG: // {DATE_LONG}
01217         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
01218         next_substr_case_index = 0;
01219         break;
01220 
01221       case SCC_DATE_ISO: // {DATE_ISO}
01222         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
01223         break;
01224 
01225       case SCC_FORCE: { // {FORCE}
01226         assert(_settings_game.locale.units_force < lengthof(_units_force));
01227         int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())};
01228         StringParameters tmp_params(args_array);
01229         buff = FormatString(buff, GetStringPtr(_units_force[_settings_game.locale.units_force].s), &tmp_params, last);
01230         break;
01231       }
01232 
01233       case SCC_HEIGHT: { // {HEIGHT}
01234         assert(_settings_game.locale.units_height < lengthof(_units_height));
01235         int64 args_array[] = {_units_height[_settings_game.locale.units_height].c.ToDisplay(args->GetInt64())};
01236         StringParameters tmp_params(args_array);
01237         buff = FormatString(buff, GetStringPtr(_units_height[_settings_game.locale.units_height].s), &tmp_params, last);
01238         break;
01239       }
01240 
01241       case SCC_POWER: { // {POWER}
01242         assert(_settings_game.locale.units_power < lengthof(_units_power));
01243         int64 args_array[1] = {_units_power[_settings_game.locale.units_power].c.ToDisplay(args->GetInt64())};
01244         StringParameters tmp_params(args_array);
01245         buff = FormatString(buff, GetStringPtr(_units_power[_settings_game.locale.units_power].s), &tmp_params, last);
01246         break;
01247       }
01248 
01249       case SCC_VELOCITY: { // {VELOCITY}
01250         assert(_settings_game.locale.units_velocity < lengthof(_units_velocity));
01251         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
01252         StringParameters tmp_params(args_array);
01253         buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last);
01254         break;
01255       }
01256 
01257       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
01258         assert(_settings_game.locale.units_volume < lengthof(_units_volume));
01259         int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
01260         StringParameters tmp_params(args_array);
01261         buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].s), &tmp_params, last);
01262         break;
01263       }
01264 
01265       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
01266         assert(_settings_game.locale.units_volume < lengthof(_units_volume));
01267         int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
01268         StringParameters tmp_params(args_array);
01269         buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
01270         break;
01271       }
01272 
01273       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
01274         assert(_settings_game.locale.units_weight < lengthof(_units_weight));
01275         int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
01276         StringParameters tmp_params(args_array);
01277         buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].s), &tmp_params, last);
01278         break;
01279       }
01280 
01281       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
01282         assert(_settings_game.locale.units_weight < lengthof(_units_weight));
01283         int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
01284         StringParameters tmp_params(args_array);
01285         buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
01286         break;
01287       }
01288 
01289       case SCC_COMPANY_NAME: { // {COMPANY}
01290         const Company *c = Company::GetIfValid(args->GetInt32());
01291         if (c == NULL) break;
01292 
01293         if (c->name != NULL) {
01294           int64 args_array[] = {(uint64)(size_t)c->name};
01295           StringParameters tmp_params(args_array);
01296           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01297         } else {
01298           int64 args_array[] = {c->name_2};
01299           StringParameters tmp_params(args_array);
01300           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
01301         }
01302         break;
01303       }
01304 
01305       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
01306         CompanyID company = (CompanyID)args->GetInt32();
01307 
01308         /* Nothing is added for AI or inactive companies */
01309         if (Company::IsValidHumanID(company)) {
01310           int64 args_array[] = {company + 1};
01311           StringParameters tmp_params(args_array);
01312           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
01313         }
01314         break;
01315       }
01316 
01317       case SCC_DEPOT_NAME: { // {DEPOT}
01318         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
01319         if (vt == VEH_AIRCRAFT) {
01320           uint64 args_array[] = {args->GetInt32()};
01321           WChar types_array[] = {SCC_STATION_NAME};
01322           StringParameters tmp_params(args_array, 1, types_array);
01323           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
01324           break;
01325         }
01326 
01327         const Depot *d = Depot::Get(args->GetInt32());
01328         if (d->name != NULL) {
01329           int64 args_array[] = {(uint64)(size_t)d->name};
01330           StringParameters tmp_params(args_array);
01331           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01332         } else {
01333           int64 args_array[] = {d->town->index, d->town_cn + 1};
01334           StringParameters tmp_params(args_array);
01335           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
01336         }
01337         break;
01338       }
01339 
01340       case SCC_ENGINE_NAME: { // {ENGINE}
01341         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
01342         if (e == NULL) break;
01343 
01344         if (e->name != NULL && e->IsEnabled()) {
01345           int64 args_array[] = {(uint64)(size_t)e->name};
01346           StringParameters tmp_params(args_array);
01347           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01348         } else {
01349           StringParameters tmp_params(NULL, 0, NULL);
01350           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
01351         }
01352         break;
01353       }
01354 
01355       case SCC_GROUP_NAME: { // {GROUP}
01356         const Group *g = Group::GetIfValid(args->GetInt32());
01357         if (g == NULL) break;
01358 
01359         if (g->name != NULL) {
01360           int64 args_array[] = {(uint64)(size_t)g->name};
01361           StringParameters tmp_params(args_array);
01362           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01363         } else {
01364           int64 args_array[] = {g->index};
01365           StringParameters tmp_params(args_array);
01366 
01367           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
01368         }
01369         break;
01370       }
01371 
01372       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
01373         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
01374         if (i == NULL) break;
01375 
01376         if (_scan_for_gender_data) {
01377           /* Gender is defined by the industry type.
01378            * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
01379           StringParameters tmp_params(NULL, 0, NULL);
01380           buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
01381         } else {
01382           /* First print the town name and the industry type name. */
01383           int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
01384           StringParameters tmp_params(args_array);
01385 
01386           buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
01387         }
01388         next_substr_case_index = 0;
01389         break;
01390       }
01391 
01392       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
01393         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
01394         if (c == NULL) break;
01395 
01396         if (c->president_name != NULL) {
01397           int64 args_array[] = {(uint64)(size_t)c->president_name};
01398           StringParameters tmp_params(args_array);
01399           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01400         } else {
01401           int64 args_array[] = {c->president_name_2};
01402           StringParameters tmp_params(args_array);
01403           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
01404         }
01405         break;
01406       }
01407 
01408       case SCC_STATION_NAME: { // {STATION}
01409         StationID sid = args->GetInt32(SCC_STATION_NAME);
01410         const Station *st = Station::GetIfValid(sid);
01411 
01412         if (st == NULL) {
01413           /* The station doesn't exist anymore. The only place where we might
01414            * be "drawing" an invalid station is in the case of cargo that is
01415            * in transit. */
01416           StringParameters tmp_params(NULL, 0, NULL);
01417           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
01418           break;
01419         }
01420 
01421         if (st->name != NULL) {
01422           int64 args_array[] = {(uint64)(size_t)st->name};
01423           StringParameters tmp_params(args_array);
01424           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01425         } else {
01426           StringID str = st->string_id;
01427           if (st->indtype != IT_INVALID) {
01428             /* Special case where the industry provides the name for the station */
01429             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
01430 
01431             /* Industry GRFs can change which might remove the station name and
01432              * thus cause very strange things. Here we check for that before we
01433              * actually set the station name. */
01434             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
01435               str = indsp->station_name;
01436             }
01437           }
01438 
01439           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
01440           StringParameters tmp_params(args_array);
01441           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01442         }
01443         break;
01444       }
01445 
01446       case SCC_TOWN_NAME: { // {TOWN}
01447         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
01448         if (t == NULL) break;
01449 
01450         if (t->name != NULL) {
01451           int64 args_array[] = {(uint64)(size_t)t->name};
01452           StringParameters tmp_params(args_array);
01453           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01454         } else {
01455           buff = GetTownName(buff, t, last);
01456         }
01457         break;
01458       }
01459 
01460       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
01461         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
01462         if (wp == NULL) break;
01463 
01464         if (wp->name != NULL) {
01465           int64 args_array[] = {(uint64)(size_t)wp->name};
01466           StringParameters tmp_params(args_array);
01467           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01468         } else {
01469           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
01470           StringParameters tmp_params(args_array);
01471           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
01472           if (wp->town_cn != 0) str++;
01473           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01474         }
01475         break;
01476       }
01477 
01478       case SCC_VEHICLE_NAME: { // {VEHICLE}
01479         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
01480         if (v == NULL) break;
01481 
01482         if (v->name != NULL) {
01483           int64 args_array[] = {(uint64)(size_t)v->name};
01484           StringParameters tmp_params(args_array);
01485           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01486         } else {
01487           int64 args_array[] = {v->unitnumber};
01488           StringParameters tmp_params(args_array);
01489 
01490           StringID str;
01491           switch (v->type) {
01492             default:           str = STR_INVALID_VEHICLE; break;
01493             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
01494             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
01495             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
01496             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
01497           }
01498 
01499           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01500         }
01501         break;
01502       }
01503 
01504       case SCC_SIGN_NAME: { // {SIGN}
01505         const Sign *si = Sign::GetIfValid(args->GetInt32());
01506         if (si == NULL) break;
01507 
01508         if (si->name != NULL) {
01509           int64 args_array[] = {(uint64)(size_t)si->name};
01510           StringParameters tmp_params(args_array);
01511           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01512         } else {
01513           StringParameters tmp_params(NULL, 0, NULL);
01514           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
01515         }
01516         break;
01517       }
01518 
01519       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
01520         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
01521         break;
01522       }
01523 
01524       default:
01525         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01526         break;
01527     }
01528   }
01529   *buff = '\0';
01530   return buff;
01531 }
01532 
01533 
01534 static char *StationGetSpecialString(char *buff, int x, const char *last)
01535 {
01536   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01537   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01538   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
01539   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
01540   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01541   *buff = '\0';
01542   return buff;
01543 }
01544 
01545 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01546 {
01547   return GenerateTownNameString(buff, last, ind, seed);
01548 }
01549 
01550 static const char * const _silly_company_names[] = {
01551   "Bloggs Brothers",
01552   "Tiny Transport Ltd.",
01553   "Express Travel",
01554   "Comfy-Coach & Co.",
01555   "Crush & Bump Ltd.",
01556   "Broken & Late Ltd.",
01557   "Sam Speedy & Son",
01558   "Supersonic Travel",
01559   "Mike's Motors",
01560   "Lightning International",
01561   "Pannik & Loozit Ltd.",
01562   "Inter-City Transport",
01563   "Getout & Pushit Ltd."
01564 };
01565 
01566 static const char * const _surname_list[] = {
01567   "Adams",
01568   "Allan",
01569   "Baker",
01570   "Bigwig",
01571   "Black",
01572   "Bloggs",
01573   "Brown",
01574   "Campbell",
01575   "Gordon",
01576   "Hamilton",
01577   "Hawthorn",
01578   "Higgins",
01579   "Green",
01580   "Gribble",
01581   "Jones",
01582   "McAlpine",
01583   "MacDonald",
01584   "McIntosh",
01585   "Muir",
01586   "Murphy",
01587   "Nelson",
01588   "O'Donnell",
01589   "Parker",
01590   "Phillips",
01591   "Pilkington",
01592   "Quigley",
01593   "Sharkey",
01594   "Thomson",
01595   "Watkins"
01596 };
01597 
01598 static const char * const _silly_surname_list[] = {
01599   "Grumpy",
01600   "Dozy",
01601   "Speedy",
01602   "Nosey",
01603   "Dribble",
01604   "Mushroom",
01605   "Cabbage",
01606   "Sniffle",
01607   "Fishy",
01608   "Swindle",
01609   "Sneaky",
01610   "Nutkins"
01611 };
01612 
01613 static const char _initial_name_letters[] = {
01614   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
01615   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
01616 };
01617 
01618 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
01619 {
01620   const char * const *base;
01621   uint num;
01622 
01623   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01624     base = _silly_surname_list;
01625     num  = lengthof(_silly_surname_list);
01626   } else {
01627     base = _surname_list;
01628     num  = lengthof(_surname_list);
01629   }
01630 
01631   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
01632   buff = strecpy(buff, " & Co.", last);
01633 
01634   return buff;
01635 }
01636 
01637 static char *GenPresidentName(char *buff, uint32 x, const char *last)
01638 {
01639   char initial[] = "?. ";
01640   const char * const *base;
01641   uint num;
01642   uint i;
01643 
01644   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
01645   buff = strecpy(buff, initial, last);
01646 
01647   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
01648   if (i < sizeof(_initial_name_letters)) {
01649     initial[0] = _initial_name_letters[i];
01650     buff = strecpy(buff, initial, last);
01651   }
01652 
01653   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01654     base = _silly_surname_list;
01655     num  = lengthof(_silly_surname_list);
01656   } else {
01657     base = _surname_list;
01658     num  = lengthof(_surname_list);
01659   }
01660 
01661   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
01662 
01663   return buff;
01664 }
01665 
01666 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
01667 {
01668   switch (ind) {
01669     case 1: // not used
01670       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
01671 
01672     case 2: // used for Foobar & Co company names
01673       return GenAndCoName(buff, args->GetInt32(), last);
01674 
01675     case 3: // President name
01676       return GenPresidentName(buff, args->GetInt32(), last);
01677   }
01678 
01679   /* town name? */
01680   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
01681     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
01682     return strecpy(buff, " Transport", last);
01683   }
01684 
01685   /* language name? */
01686   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
01687     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
01688     return strecpy(buff,
01689       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
01690   }
01691 
01692   /* resolution size? */
01693   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
01694     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
01695     buff += seprintf(
01696       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
01697     );
01698     return buff;
01699   }
01700 
01701   /* screenshot format name? */
01702   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
01703     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
01704     return strecpy(buff, GetScreenshotFormatDesc(i), last);
01705   }
01706 
01707   NOT_REACHED();
01708 }
01709 
01710 #ifdef ENABLE_NETWORK
01711 extern void SortNetworkLanguages();
01712 #else /* ENABLE_NETWORK */
01713 static inline void SortNetworkLanguages() {}
01714 #endif /* ENABLE_NETWORK */
01715 
01720 bool LanguagePackHeader::IsValid() const
01721 {
01722   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
01723          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
01724          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
01725          this->text_dir     <= 1 &&
01726          this->newgrflangid < MAX_LANG &&
01727          this->num_genders  < MAX_NUM_GENDERS &&
01728          this->num_cases    < MAX_NUM_CASES &&
01729          StrValid(this->name,                           lastof(this->name)) &&
01730          StrValid(this->own_name,                       lastof(this->own_name)) &&
01731          StrValid(this->isocode,                        lastof(this->isocode)) &&
01732          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
01733          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
01734          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
01735 }
01736 
01742 bool ReadLanguagePack(const LanguageMetadata *lang)
01743 {
01744   /* Current language pack */
01745   size_t len;
01746   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
01747   if (lang_pack == NULL) return false;
01748 
01749   /* End of read data (+ terminating zero added in ReadFileToMem()) */
01750   const char *end = (char *)lang_pack + len + 1;
01751 
01752   /* We need at least one byte of lang_pack->data */
01753   if (end <= lang_pack->data || !lang_pack->IsValid()) {
01754     free(lang_pack);
01755     return false;
01756   }
01757 
01758 #if TTD_ENDIAN == TTD_BIG_ENDIAN
01759   for (uint i = 0; i < TAB_COUNT; i++) {
01760     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
01761   }
01762 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
01763 
01764   uint count = 0;
01765   for (uint i = 0; i < TAB_COUNT; i++) {
01766     uint16 num = lang_pack->offsets[i];
01767     if (num > TAB_SIZE) {
01768       free(lang_pack);
01769       return false;
01770     }
01771 
01772     _langtab_start[i] = count;
01773     _langtab_num[i] = num;
01774     count += num;
01775   }
01776 
01777   /* Allocate offsets */
01778   char **langpack_offs = MallocT<char *>(count);
01779 
01780   /* Fill offsets */
01781   char *s = lang_pack->data;
01782   len = (byte)*s++;
01783   for (uint i = 0; i < count; i++) {
01784     if (s + len >= end) {
01785       free(lang_pack);
01786       free(langpack_offs);
01787       return false;
01788     }
01789     if (len >= 0xC0) {
01790       len = ((len & 0x3F) << 8) + (byte)*s++;
01791       if (s + len >= end) {
01792         free(lang_pack);
01793         free(langpack_offs);
01794         return false;
01795       }
01796     }
01797     langpack_offs[i] = s;
01798     s += len;
01799     len = (byte)*s;
01800     *s++ = '\0'; // zero terminate the string
01801   }
01802 
01803   free(_langpack);
01804   _langpack = lang_pack;
01805 
01806   free(_langpack_offs);
01807   _langpack_offs = langpack_offs;
01808 
01809   _current_language = lang;
01810   _current_text_dir = (TextDirection)_current_language->text_dir;
01811   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
01812   strecpy(_config_language_file, c_file, lastof(_config_language_file));
01813   SetCurrentGrfLangID(_current_language->newgrflangid);
01814 
01815 #ifdef WITH_ICU
01816   /* Delete previous collator. */
01817   if (_current_collator != NULL) {
01818     delete _current_collator;
01819     _current_collator = NULL;
01820   }
01821 
01822   /* Create a collator instance for our current locale. */
01823   UErrorCode status = U_ZERO_ERROR;
01824   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
01825   /* Sort number substrings by their numerical value. */
01826   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
01827   /* Avoid using the collator if it is not correctly set. */
01828   if (U_FAILURE(status)) {
01829     delete _current_collator;
01830     _current_collator = NULL;
01831   }
01832 #endif /* WITH_ICU */
01833 
01834   /* Some lists need to be sorted again after a language change. */
01835   ReconsiderGameScriptLanguage();
01836   InitializeSortedCargoSpecs();
01837   SortIndustryTypes();
01838   BuildIndustriesLegend();
01839   SortNetworkLanguages();
01840   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
01841   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
01842   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
01843   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
01844   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
01845   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
01846   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
01847 
01848   return true;
01849 }
01850 
01851 /* Win32 implementation in win32.cpp.
01852  * OS X implementation in os/macosx/macos.mm. */
01853 #if !(defined(WIN32) || defined(__APPLE__))
01854 
01862 const char *GetCurrentLocale(const char *param)
01863 {
01864   const char *env;
01865 
01866   env = getenv("LANGUAGE");
01867   if (env != NULL) return env;
01868 
01869   env = getenv("LC_ALL");
01870   if (env != NULL) return env;
01871 
01872   if (param != NULL) {
01873     env = getenv(param);
01874     if (env != NULL) return env;
01875   }
01876 
01877   return getenv("LANG");
01878 }
01879 #else
01880 const char *GetCurrentLocale(const char *param);
01881 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
01882 
01883 int CDECL StringIDSorter(const StringID *a, const StringID *b)
01884 {
01885   char stra[512];
01886   char strb[512];
01887   GetString(stra, *a, lastof(stra));
01888   GetString(strb, *b, lastof(strb));
01889 
01890   return strcmp(stra, strb);
01891 }
01892 
01898 const LanguageMetadata *GetLanguage(byte newgrflangid)
01899 {
01900   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
01901     if (newgrflangid == lang->newgrflangid) return lang;
01902   }
01903 
01904   return NULL;
01905 }
01906 
01913 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
01914 {
01915   FILE *f = fopen(file, "rb");
01916   if (f == NULL) return false;
01917 
01918   size_t read = fread(hdr, sizeof(*hdr), 1, f);
01919   fclose(f);
01920 
01921   bool ret = read == 1 && hdr->IsValid();
01922 
01923   /* Convert endianness for the windows language ID */
01924   if (ret) {
01925     hdr->missing = FROM_LE16(hdr->missing);
01926     hdr->winlangid = FROM_LE16(hdr->winlangid);
01927   }
01928   return ret;
01929 }
01930 
01935 static void GetLanguageList(const char *path)
01936 {
01937   DIR *dir = ttd_opendir(path);
01938   if (dir != NULL) {
01939     struct dirent *dirent;
01940     while ((dirent = readdir(dir)) != NULL) {
01941       const char *d_name    = FS2OTTD(dirent->d_name);
01942       const char *extension = strrchr(d_name, '.');
01943 
01944       /* Not a language file */
01945       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
01946 
01947       LanguageMetadata lmd;
01948       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
01949 
01950       /* Check whether the file is of the correct version */
01951       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
01952         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
01953       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
01954         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
01955       } else {
01956         *_languages.Append() = lmd;
01957       }
01958     }
01959     closedir(dir);
01960   }
01961 }
01962 
01967 void InitializeLanguagePacks()
01968 {
01969   Searchpath sp;
01970 
01971   FOR_ALL_SEARCHPATHS(sp) {
01972     char path[MAX_PATH];
01973     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
01974     GetLanguageList(path);
01975   }
01976   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
01977 
01978   /* Acquire the locale of the current system */
01979   const char *lang = GetCurrentLocale("LC_MESSAGES");
01980   if (lang == NULL) lang = "en_GB";
01981 
01982   const LanguageMetadata *chosen_language   = NULL; 
01983   const LanguageMetadata *language_fallback = NULL; 
01984   const LanguageMetadata *en_GB_fallback    = _languages.Begin(); 
01985 
01986   /* Find a proper language. */
01987   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
01988     /* We are trying to find a default language. The priority is by
01989      * configuration file, local environment and last, if nothing found,
01990      * English. */
01991     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
01992     if (strcmp(lang_file, _config_language_file) == 0) {
01993       chosen_language = lng;
01994       break;
01995     }
01996 
01997     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
01998     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
01999     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
02000   }
02001 
02002   /* We haven't found the language in the config nor the one in the locale.
02003    * Now we set it to one of the fallback languages */
02004   if (chosen_language == NULL) {
02005     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
02006   }
02007 
02008   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
02009 }
02010 
02015 const char *GetCurrentLanguageIsoCode()
02016 {
02017   return _langpack->isocode;
02018 }
02019 
02026 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
02027 {
02028   InitFreeType(this->Monospace());
02029   const Sprite *question_mark[FS_END];
02030 
02031   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
02032     question_mark[size] = GetGlyph(size, '?');
02033   }
02034 
02035   this->Reset();
02036   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
02037     FontSize size = this->DefaultSize();
02038     if (str != NULL) *str = text;
02039     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
02040       if (c == SCC_TINYFONT) {
02041         size = FS_SMALL;
02042       } else if (c == SCC_BIGFONT) {
02043         size = FS_LARGE;
02044       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
02045         /* The character is printable, but not in the normal font. This is the case we were testing for. */
02046         return true;
02047       }
02048     }
02049   }
02050   return false;
02051 }
02052 
02054 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
02055   uint i; 
02056   uint j; 
02057 
02058   /* virtual */ void Reset()
02059   {
02060     this->i = 0;
02061     this->j = 0;
02062   }
02063 
02064   /* virtual */ FontSize DefaultSize()
02065   {
02066     return FS_NORMAL;
02067   }
02068 
02069   /* virtual */ const char *NextString()
02070   {
02071     if (this->i >= TAB_COUNT) return NULL;
02072 
02073     const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
02074 
02075     this->j++;
02076     while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) {
02077       this->i++;
02078       this->j = 0;
02079     }
02080 
02081     return ret;
02082   }
02083 
02084   /* virtual */ bool Monospace()
02085   {
02086     return false;
02087   }
02088 
02089   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
02090   {
02091 #ifdef WITH_FREETYPE
02092     strecpy(settings->small.font,  font_name, lastof(settings->small.font));
02093     strecpy(settings->medium.font, font_name, lastof(settings->medium.font));
02094     strecpy(settings->large.font,  font_name, lastof(settings->large.font));
02095 #endif /* WITH_FREETYPE */
02096   }
02097 };
02098 
02112 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
02113 {
02114   static LanguagePackGlyphSearcher pack_searcher;
02115   if (searcher == NULL) searcher = &pack_searcher;
02116   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
02117 #ifdef WITH_FREETYPE
02118   if (bad_font) {
02119     /* We found an unprintable character... lets try whether we can find
02120      * a fallback font that can print the characters in the current language. */
02121     FreeTypeSettings backup;
02122     memcpy(&backup, &_freetype, sizeof(backup));
02123 
02124     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
02125 
02126     memcpy(&_freetype, &backup, sizeof(backup));
02127 
02128     if (bad_font && base_font) {
02129       /* Our fallback font does miss characters too, so keep the
02130        * user chosen font as that is more likely to be any good than
02131        * the wild guess we made */
02132       InitFreeType(searcher->Monospace());
02133     }
02134   }
02135 #endif
02136 
02137   if (bad_font) {
02138     /* All attempts have failed. Display an error. As we do not want the string to be translated by
02139      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
02140      * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
02141      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
02142      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
02143     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.");
02144     Utf8Encode(err_str, SCC_YELLOW);
02145     SetDParamStr(0, err_str);
02146     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
02147 
02148     /* Reset the font width */
02149     LoadStringWidthTable(searcher->Monospace());
02150     return;
02151   }
02152 
02153   /* Update the font with cache */
02154   LoadStringWidthTable(searcher->Monospace());
02155 
02156 #if !defined(WITH_ICU)
02157   /*
02158    * For right-to-left languages we need the ICU library. If
02159    * we do not have support for that library we warn the user
02160    * about it with a message. As we do not want the string to
02161    * be translated by the translators, we 'force' it into the
02162    * binary and 'load' it via a BindCString. To do this
02163    * properly we have to set the colour of the string,
02164    * otherwise we end up with a lot of artifacts. The colour
02165    * 'character' might change in the future, so for safety
02166    * we just Utf8 Encode it into the string, which takes
02167    * exactly three characters, so it replaces the "XXX" with
02168    * the colour marker.
02169    */
02170   if (_current_text_dir != TD_LTR) {
02171     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
02172     Utf8Encode(err_str, SCC_YELLOW);
02173     SetDParamStr(0, err_str);
02174     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02175   }
02176 #endif
02177 }