strings.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "currency.h"
00014 #include "station_base.h"
00015 #include "town.h"
00016 #include "screenshot.h"
00017 #include "waypoint_base.h"
00018 #include "depot_base.h"
00019 #include "industry.h"
00020 #include "newgrf_text.h"
00021 #include "fileio_func.h"
00022 #include "signs_base.h"
00023 #include "fontcache.h"
00024 #include "error.h"
00025 #include "strings_func.h"
00026 #include "rev.h"
00027 #include "core/endian_func.hpp"
00028 #include "date_func.h"
00029 #include "vehicle_base.h"
00030 #include "engine_base.h"
00031 #include "language.h"
00032 #include "townname_func.h"
00033 #include "string_func.h"
00034 #include "company_base.h"
00035 #include "smallmap_gui.h"
00036 #include "window_func.h"
00037 #include "debug.h"
00038 #include "game/game_text.hpp"
00039 #include <stack>
00040 
00041 #include "table/strings.h"
00042 #include "table/control_codes.h"
00043 
00044 char _config_language_file[MAX_PATH];             
00045 LanguageList _languages;                          
00046 const LanguageMetadata *_current_language = NULL; 
00047 
00048 TextDirection _current_text_dir; 
00049 
00050 #ifdef WITH_ICU
00051 Collator *_current_collator = NULL;               
00052 #endif /* WITH_ICU */
00053 
00054 static uint64 _global_string_params_data[20];     
00055 static WChar _global_string_params_type[20];      
00056 StringParameters _global_string_params(_global_string_params_data, 20, _global_string_params_type);
00057 
00059 void StringParameters::ClearTypeInformation()
00060 {
00061   assert(this->type != NULL);
00062   MemSetT(this->type, 0, this->num_param);
00063 }
00064 
00065 
00070 int64 StringParameters::GetInt64(WChar type)
00071 {
00072   if (this->offset >= this->num_param) {
00073     DEBUG(misc, 0, "Trying to read invalid string parameter");
00074     return 0;
00075   }
00076   if (this->type != NULL) {
00077     assert(this->type[this->offset] == 0 || this->type[this->offset] == type);
00078     this->type[this->offset] = type;
00079   }
00080   return this->data[this->offset++];
00081 }
00082 
00087 void StringParameters::ShiftParameters(uint amount)
00088 {
00089   assert(amount <= this->num_param);
00090   MemMoveT(this->data + amount, this->data, this->num_param - amount);
00091 }
00092 
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       error("Incorrect conversion of custom name string.");
00237 
00238     case GAME_TEXT_TAB:
00239       return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
00240 
00241     case 26:
00242       /* Include string within newgrf text (format code 81) */
00243       if (HasBit(index, 10)) {
00244         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
00245         return GetStringWithArgs(buffr, string, args, last, case_index);
00246       }
00247       break;
00248 
00249     case 28:
00250       return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
00251 
00252     case 29:
00253       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), args, last, case_index);
00254 
00255     case 30:
00256       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), args, last, case_index);
00257 
00258     case 31:
00259       NOT_REACHED();
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_SETX: // {SETX}
01007         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
01008           buff += Utf8Encode(buff, SCC_SETX);
01009           *buff++ = *str++;
01010         }
01011         break;
01012 
01013       case SCC_SETXY: // {SETXY}
01014         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
01015           buff += Utf8Encode(buff, SCC_SETXY);
01016           *buff++ = *str++;
01017           *buff++ = *str++;
01018         }
01019         break;
01020 
01021       case SCC_REVISION: // {REV}
01022         buff = strecpy(buff, _openttd_revision, last);
01023         break;
01024 
01025       case SCC_STRING_ID: // {STRINL}
01026         if (game_script) break;
01027         buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
01028         break;
01029 
01030       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
01031         if (game_script) break;
01032         const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
01033         buff = FormatString(buff, str, args, last);
01034         break;
01035       }
01036 
01037       case SCC_STRING: {// {STRING}
01038         StringID str = args->GetInt32(SCC_STRING);
01039         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
01040         /* WARNING. It's prohibited for the included string to consume any arguments.
01041          * For included strings that consume argument, you should use STRING1, STRING2 etc.
01042          * To debug stuff you can set argv to NULL and it will tell you */
01043         StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
01044         buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
01045         next_substr_case_index = 0;
01046         break;
01047       }
01048 
01049       case SCC_STRING1:
01050       case SCC_STRING2:
01051       case SCC_STRING3:
01052       case SCC_STRING4:
01053       case SCC_STRING5:
01054       case SCC_STRING6:
01055       case SCC_STRING7: { // {STRING1..7}
01056         /* Strings that consume arguments */
01057         StringID str = args->GetInt32(b);
01058         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
01059         uint size = b - SCC_STRING1 + 1;
01060         if (game_script && size > args->num_param - args->offset) {
01061           buff = strecat(buff, "(too many parameters)", last);
01062         } else {
01063           StringParameters sub_args(*args, size);
01064           buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
01065         }
01066         next_substr_case_index = 0;
01067         break;
01068       }
01069 
01070       case SCC_COMMA: // {COMMA}
01071         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
01072         break;
01073 
01074       case SCC_DECIMAL: {// {DECIMAL}
01075         int64 number = args->GetInt64(SCC_DECIMAL);
01076         int digits = args->GetInt32(SCC_DECIMAL);
01077         buff = FormatCommaNumber(buff, number, last, digits);
01078         break;
01079       }
01080 
01081       case SCC_NUM: // {NUM}
01082         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
01083         break;
01084 
01085       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
01086         int64 num = args->GetInt64();
01087         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
01088         break;
01089       }
01090 
01091       case SCC_HEX: // {HEX}
01092         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
01093         break;
01094 
01095       case SCC_BYTES: // {BYTES}
01096         buff = FormatBytes(buff, args->GetInt64(), last);
01097         break;
01098 
01099       case SCC_CARGO_TINY: { // {CARGO_TINY}
01100         /* Tiny description of cargotypes. Layout:
01101          * param 1: cargo type
01102          * param 2: cargo count */
01103         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
01104         if (cargo >= CargoSpec::GetArraySize()) break;
01105 
01106         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01107         int64 amount = 0;
01108         switch (cargo_str) {
01109           case STR_TONS:
01110             amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
01111             break;
01112 
01113           case STR_LITERS:
01114             amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
01115             break;
01116 
01117           default: {
01118             amount = args->GetInt64();
01119             break;
01120           }
01121         }
01122 
01123         buff = FormatCommaNumber(buff, amount, last);
01124         break;
01125       }
01126 
01127       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
01128         /* Short description of cargotypes. Layout:
01129          * param 1: cargo type
01130          * param 2: cargo count */
01131         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
01132         if (cargo >= CargoSpec::GetArraySize()) break;
01133 
01134         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01135         switch (cargo_str) {
01136           case STR_TONS: {
01137             assert(_settings_game.locale.units < lengthof(_units));
01138             int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
01139             StringParameters tmp_params(args_array);
01140             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
01141             break;
01142           }
01143 
01144           case STR_LITERS: {
01145             assert(_settings_game.locale.units < lengthof(_units));
01146             int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
01147             StringParameters tmp_params(args_array);
01148             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
01149             break;
01150           }
01151 
01152           default: {
01153             StringParameters tmp_params(*args, 1);
01154             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
01155             break;
01156           }
01157         }
01158         break;
01159       }
01160 
01161       case SCC_CARGO_LONG: { // {CARGO_LONG}
01162         /* First parameter is cargo type, second parameter is cargo count */
01163         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
01164         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
01165 
01166         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
01167         StringParameters tmp_args(*args, 1);
01168         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
01169         break;
01170       }
01171 
01172       case SCC_CARGO_LIST: { // {CARGO_LIST}
01173         uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
01174         bool first = true;
01175 
01176         const CargoSpec *cs;
01177         FOR_ALL_SORTED_CARGOSPECS(cs) {
01178           if (!HasBit(cmask, cs->Index())) continue;
01179 
01180           if (buff >= last - 2) break; // ',' and ' '
01181 
01182           if (first) {
01183             first = false;
01184           } else {
01185             /* Add a comma if this is not the first item */
01186             *buff++ = ',';
01187             *buff++ = ' ';
01188           }
01189 
01190           buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
01191         }
01192 
01193         /* If first is still true then no cargo is accepted */
01194         if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
01195 
01196         *buff = '\0';
01197         next_substr_case_index = 0;
01198 
01199         /* Make sure we detect any buffer overflow */
01200         assert(buff < last);
01201         break;
01202       }
01203 
01204       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
01205         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
01206         break;
01207 
01208       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
01209         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
01210         break;
01211 
01212       case SCC_DATE_TINY: // {DATE_TINY}
01213         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
01214         break;
01215 
01216       case SCC_DATE_SHORT: // {DATE_SHORT}
01217         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
01218         next_substr_case_index = 0;
01219         break;
01220 
01221       case SCC_DATE_LONG: // {DATE_LONG}
01222         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
01223         next_substr_case_index = 0;
01224         break;
01225 
01226       case SCC_DATE_ISO: // {DATE_ISO}
01227         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
01228         break;
01229 
01230       case SCC_FORCE: { // {FORCE}
01231         assert(_settings_game.locale.units < lengthof(_units));
01232         int64 args_array[1] = {_units[_settings_game.locale.units].c_force.ToDisplay(args->GetInt64())};
01233         StringParameters tmp_params(args_array);
01234         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), &tmp_params, last);
01235         break;
01236       }
01237 
01238       case SCC_HEIGHT: { // {HEIGHT}
01239         int64 args_array[] = {_units[_settings_game.locale.units].c_height.ToDisplay(args->GetInt64())};
01240         StringParameters tmp_params(args_array);
01241         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), &tmp_params, last);
01242         break;
01243       }
01244 
01245       case SCC_POWER: { // {POWER}
01246         assert(_settings_game.locale.units < lengthof(_units));
01247         int64 args_array[1] = {_units[_settings_game.locale.units].c_power.ToDisplay(args->GetInt64())};
01248         StringParameters tmp_params(args_array);
01249         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), &tmp_params, last);
01250         break;
01251       }
01252 
01253       case SCC_VELOCITY: { // {VELOCITY}
01254         assert(_settings_game.locale.units < lengthof(_units));
01255         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
01256         StringParameters tmp_params(args_array);
01257         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), &tmp_params, last);
01258         break;
01259       }
01260 
01261       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
01262         assert(_settings_game.locale.units < lengthof(_units));
01263         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
01264         StringParameters tmp_params(args_array);
01265         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), &tmp_params, last);
01266         break;
01267       }
01268 
01269       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
01270         assert(_settings_game.locale.units < lengthof(_units));
01271         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
01272         StringParameters tmp_params(args_array);
01273         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
01274         break;
01275       }
01276 
01277       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
01278         assert(_settings_game.locale.units < lengthof(_units));
01279         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
01280         StringParameters tmp_params(args_array);
01281         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), &tmp_params, last);
01282         break;
01283       }
01284 
01285       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
01286         assert(_settings_game.locale.units < lengthof(_units));
01287         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
01288         StringParameters tmp_params(args_array);
01289         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
01290         break;
01291       }
01292 
01293       case SCC_COMPANY_NAME: { // {COMPANY}
01294         const Company *c = Company::GetIfValid(args->GetInt32());
01295         if (c == NULL) break;
01296 
01297         if (c->name != NULL) {
01298           int64 args_array[] = {(uint64)(size_t)c->name};
01299           StringParameters tmp_params(args_array);
01300           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01301         } else {
01302           int64 args_array[] = {c->name_2};
01303           StringParameters tmp_params(args_array);
01304           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
01305         }
01306         break;
01307       }
01308 
01309       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
01310         CompanyID company = (CompanyID)args->GetInt32();
01311 
01312         /* Nothing is added for AI or inactive companies */
01313         if (Company::IsValidHumanID(company)) {
01314           int64 args_array[] = {company + 1};
01315           StringParameters tmp_params(args_array);
01316           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
01317         }
01318         break;
01319       }
01320 
01321       case SCC_DEPOT_NAME: { // {DEPOT}
01322         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
01323         if (vt == VEH_AIRCRAFT) {
01324           uint64 args_array[] = {args->GetInt32()};
01325           WChar types_array[] = {SCC_STATION_NAME};
01326           StringParameters tmp_params(args_array, 1, types_array);
01327           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
01328           break;
01329         }
01330 
01331         const Depot *d = Depot::Get(args->GetInt32());
01332         if (d->name != NULL) {
01333           int64 args_array[] = {(uint64)(size_t)d->name};
01334           StringParameters tmp_params(args_array);
01335           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01336         } else {
01337           int64 args_array[] = {d->town->index, d->town_cn + 1};
01338           StringParameters tmp_params(args_array);
01339           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
01340         }
01341         break;
01342       }
01343 
01344       case SCC_ENGINE_NAME: { // {ENGINE}
01345         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
01346         if (e == NULL) break;
01347 
01348         if (e->name != NULL && e->IsEnabled()) {
01349           int64 args_array[] = {(uint64)(size_t)e->name};
01350           StringParameters tmp_params(args_array);
01351           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01352         } else {
01353           StringParameters tmp_params(NULL, 0, NULL);
01354           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
01355         }
01356         break;
01357       }
01358 
01359       case SCC_GROUP_NAME: { // {GROUP}
01360         const Group *g = Group::GetIfValid(args->GetInt32());
01361         if (g == NULL) break;
01362 
01363         if (g->name != NULL) {
01364           int64 args_array[] = {(uint64)(size_t)g->name};
01365           StringParameters tmp_params(args_array);
01366           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01367         } else {
01368           int64 args_array[] = {g->index};
01369           StringParameters tmp_params(args_array);
01370 
01371           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
01372         }
01373         break;
01374       }
01375 
01376       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
01377         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
01378         if (i == NULL) break;
01379 
01380         if (_scan_for_gender_data) {
01381           /* Gender is defined by the industry type.
01382            * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
01383           StringParameters tmp_params(NULL, 0, NULL);
01384           buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
01385         } else {
01386           /* First print the town name and the industry type name. */
01387           int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
01388           StringParameters tmp_params(args_array);
01389 
01390           buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
01391         }
01392         next_substr_case_index = 0;
01393         break;
01394       }
01395 
01396       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
01397         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
01398         if (c == NULL) break;
01399 
01400         if (c->president_name != NULL) {
01401           int64 args_array[] = {(uint64)(size_t)c->president_name};
01402           StringParameters tmp_params(args_array);
01403           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01404         } else {
01405           int64 args_array[] = {c->president_name_2};
01406           StringParameters tmp_params(args_array);
01407           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
01408         }
01409         break;
01410       }
01411 
01412       case SCC_STATION_NAME: { // {STATION}
01413         StationID sid = args->GetInt32(SCC_STATION_NAME);
01414         const Station *st = Station::GetIfValid(sid);
01415 
01416         if (st == NULL) {
01417           /* The station doesn't exist anymore. The only place where we might
01418            * be "drawing" an invalid station is in the case of cargo that is
01419            * in transit. */
01420           StringParameters tmp_params(NULL, 0, NULL);
01421           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
01422           break;
01423         }
01424 
01425         if (st->name != NULL) {
01426           int64 args_array[] = {(uint64)(size_t)st->name};
01427           StringParameters tmp_params(args_array);
01428           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01429         } else {
01430           StringID str = st->string_id;
01431           if (st->indtype != IT_INVALID) {
01432             /* Special case where the industry provides the name for the station */
01433             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
01434 
01435             /* Industry GRFs can change which might remove the station name and
01436              * thus cause very strange things. Here we check for that before we
01437              * actually set the station name. */
01438             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
01439               str = indsp->station_name;
01440             }
01441           }
01442 
01443           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
01444           StringParameters tmp_params(args_array);
01445           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01446         }
01447         break;
01448       }
01449 
01450       case SCC_TOWN_NAME: { // {TOWN}
01451         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
01452         if (t == NULL) break;
01453 
01454         if (t->name != NULL) {
01455           int64 args_array[] = {(uint64)(size_t)t->name};
01456           StringParameters tmp_params(args_array);
01457           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01458         } else {
01459           buff = GetTownName(buff, t, last);
01460         }
01461         break;
01462       }
01463 
01464       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
01465         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
01466         if (wp == NULL) break;
01467 
01468         if (wp->name != NULL) {
01469           int64 args_array[] = {(uint64)(size_t)wp->name};
01470           StringParameters tmp_params(args_array);
01471           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01472         } else {
01473           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
01474           StringParameters tmp_params(args_array);
01475           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
01476           if (wp->town_cn != 0) str++;
01477           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01478         }
01479         break;
01480       }
01481 
01482       case SCC_VEHICLE_NAME: { // {VEHICLE}
01483         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
01484         if (v == NULL) break;
01485 
01486         if (v->name != NULL) {
01487           int64 args_array[] = {(uint64)(size_t)v->name};
01488           StringParameters tmp_params(args_array);
01489           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01490         } else {
01491           int64 args_array[] = {v->unitnumber};
01492           StringParameters tmp_params(args_array);
01493 
01494           StringID str;
01495           switch (v->type) {
01496             default: NOT_REACHED();
01497             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
01498             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
01499             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
01500             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
01501           }
01502 
01503           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01504         }
01505         break;
01506       }
01507 
01508       case SCC_SIGN_NAME: { // {SIGN}
01509         const Sign *si = Sign::GetIfValid(args->GetInt32());
01510         if (si == NULL) break;
01511 
01512         if (si->name != NULL) {
01513           int64 args_array[] = {(uint64)(size_t)si->name};
01514           StringParameters tmp_params(args_array);
01515           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01516         } else {
01517           StringParameters tmp_params(NULL, 0, NULL);
01518           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
01519         }
01520         break;
01521       }
01522 
01523       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
01524         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
01525         break;
01526       }
01527 
01528       default:
01529         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01530         break;
01531     }
01532   }
01533   *buff = '\0';
01534   return buff;
01535 }
01536 
01537 
01538 static char *StationGetSpecialString(char *buff, int x, const char *last)
01539 {
01540   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01541   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01542   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
01543   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
01544   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01545   *buff = '\0';
01546   return buff;
01547 }
01548 
01549 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01550 {
01551   return GenerateTownNameString(buff, last, ind, seed);
01552 }
01553 
01554 static const char * const _silly_company_names[] = {
01555   "Bloggs Brothers",
01556   "Tiny Transport Ltd.",
01557   "Express Travel",
01558   "Comfy-Coach & Co.",
01559   "Crush & Bump Ltd.",
01560   "Broken & Late Ltd.",
01561   "Sam Speedy & Son",
01562   "Supersonic Travel",
01563   "Mike's Motors",
01564   "Lightning International",
01565   "Pannik & Loozit Ltd.",
01566   "Inter-City Transport",
01567   "Getout & Pushit Ltd."
01568 };
01569 
01570 static const char * const _surname_list[] = {
01571   "Adams",
01572   "Allan",
01573   "Baker",
01574   "Bigwig",
01575   "Black",
01576   "Bloggs",
01577   "Brown",
01578   "Campbell",
01579   "Gordon",
01580   "Hamilton",
01581   "Hawthorn",
01582   "Higgins",
01583   "Green",
01584   "Gribble",
01585   "Jones",
01586   "McAlpine",
01587   "MacDonald",
01588   "McIntosh",
01589   "Muir",
01590   "Murphy",
01591   "Nelson",
01592   "O'Donnell",
01593   "Parker",
01594   "Phillips",
01595   "Pilkington",
01596   "Quigley",
01597   "Sharkey",
01598   "Thomson",
01599   "Watkins"
01600 };
01601 
01602 static const char * const _silly_surname_list[] = {
01603   "Grumpy",
01604   "Dozy",
01605   "Speedy",
01606   "Nosey",
01607   "Dribble",
01608   "Mushroom",
01609   "Cabbage",
01610   "Sniffle",
01611   "Fishy",
01612   "Swindle",
01613   "Sneaky",
01614   "Nutkins"
01615 };
01616 
01617 static const char _initial_name_letters[] = {
01618   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
01619   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
01620 };
01621 
01622 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
01623 {
01624   const char * const *base;
01625   uint num;
01626 
01627   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01628     base = _silly_surname_list;
01629     num  = lengthof(_silly_surname_list);
01630   } else {
01631     base = _surname_list;
01632     num  = lengthof(_surname_list);
01633   }
01634 
01635   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
01636   buff = strecpy(buff, " & Co.", last);
01637 
01638   return buff;
01639 }
01640 
01641 static char *GenPresidentName(char *buff, uint32 x, const char *last)
01642 {
01643   char initial[] = "?. ";
01644   const char * const *base;
01645   uint num;
01646   uint i;
01647 
01648   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
01649   buff = strecpy(buff, initial, last);
01650 
01651   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
01652   if (i < sizeof(_initial_name_letters)) {
01653     initial[0] = _initial_name_letters[i];
01654     buff = strecpy(buff, initial, last);
01655   }
01656 
01657   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01658     base = _silly_surname_list;
01659     num  = lengthof(_silly_surname_list);
01660   } else {
01661     base = _surname_list;
01662     num  = lengthof(_surname_list);
01663   }
01664 
01665   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
01666 
01667   return buff;
01668 }
01669 
01670 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
01671 {
01672   switch (ind) {
01673     case 1: // not used
01674       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
01675 
01676     case 2: // used for Foobar & Co company names
01677       return GenAndCoName(buff, args->GetInt32(), last);
01678 
01679     case 3: // President name
01680       return GenPresidentName(buff, args->GetInt32(), last);
01681   }
01682 
01683   /* town name? */
01684   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
01685     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
01686     return strecpy(buff, " Transport", last);
01687   }
01688 
01689   /* language name? */
01690   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
01691     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
01692     return strecpy(buff,
01693       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
01694   }
01695 
01696   /* resolution size? */
01697   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
01698     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
01699     buff += seprintf(
01700       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
01701     );
01702     return buff;
01703   }
01704 
01705   /* screenshot format name? */
01706   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
01707     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
01708     return strecpy(buff, GetScreenshotFormatDesc(i), last);
01709   }
01710 
01711   NOT_REACHED();
01712 }
01713 
01714 #ifdef ENABLE_NETWORK
01715 extern void SortNetworkLanguages();
01716 #else /* ENABLE_NETWORK */
01717 static inline void SortNetworkLanguages() {}
01718 #endif /* ENABLE_NETWORK */
01719 
01724 bool LanguagePackHeader::IsValid() const
01725 {
01726   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
01727          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
01728          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
01729          this->text_dir     <= 1 &&
01730          this->newgrflangid < MAX_LANG &&
01731          this->num_genders  < MAX_NUM_GENDERS &&
01732          this->num_cases    < MAX_NUM_CASES &&
01733          StrValid(this->name,                           lastof(this->name)) &&
01734          StrValid(this->own_name,                       lastof(this->own_name)) &&
01735          StrValid(this->isocode,                        lastof(this->isocode)) &&
01736          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
01737          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
01738          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
01739 }
01740 
01746 bool ReadLanguagePack(const LanguageMetadata *lang)
01747 {
01748   /* Current language pack */
01749   size_t len;
01750   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
01751   if (lang_pack == NULL) return false;
01752 
01753   /* End of read data (+ terminating zero added in ReadFileToMem()) */
01754   const char *end = (char *)lang_pack + len + 1;
01755 
01756   /* We need at least one byte of lang_pack->data */
01757   if (end <= lang_pack->data || !lang_pack->IsValid()) {
01758     free(lang_pack);
01759     return false;
01760   }
01761 
01762 #if TTD_ENDIAN == TTD_BIG_ENDIAN
01763   for (uint i = 0; i < TAB_COUNT; i++) {
01764     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
01765   }
01766 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
01767 
01768   uint count = 0;
01769   for (uint i = 0; i < TAB_COUNT; i++) {
01770     uint num = lang_pack->offsets[i];
01771     _langtab_start[i] = count;
01772     _langtab_num[i] = num;
01773     count += num;
01774   }
01775 
01776   /* Allocate offsets */
01777   char **langpack_offs = MallocT<char *>(count);
01778 
01779   /* Fill offsets */
01780   char *s = lang_pack->data;
01781   len = (byte)*s++;
01782   for (uint i = 0; i < count; i++) {
01783     if (s + len >= end) {
01784       free(lang_pack);
01785       free(langpack_offs);
01786       return false;
01787     }
01788     if (len >= 0xC0) {
01789       len = ((len & 0x3F) << 8) + (byte)*s++;
01790       if (s + len >= end) {
01791         free(lang_pack);
01792         free(langpack_offs);
01793         return false;
01794       }
01795     }
01796     langpack_offs[i] = s;
01797     s += len;
01798     len = (byte)*s;
01799     *s++ = '\0'; // zero terminate the string
01800   }
01801 
01802   free(_langpack);
01803   _langpack = lang_pack;
01804 
01805   free(_langpack_offs);
01806   _langpack_offs = langpack_offs;
01807 
01808   _current_language = lang;
01809   _current_text_dir = (TextDirection)_current_language->text_dir;
01810   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
01811   strecpy(_config_language_file, c_file, lastof(_config_language_file));
01812   SetCurrentGrfLangID(_current_language->newgrflangid);
01813 
01814 #ifdef WITH_ICU
01815   /* Delete previous collator. */
01816   if (_current_collator != NULL) {
01817     delete _current_collator;
01818     _current_collator = NULL;
01819   }
01820 
01821   /* Create a collator instance for our current locale. */
01822   UErrorCode status = U_ZERO_ERROR;
01823   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
01824   /* Sort number substrings by their numerical value. */
01825   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
01826   /* Avoid using the collator if it is not correctly set. */
01827   if (U_FAILURE(status)) {
01828     delete _current_collator;
01829     _current_collator = NULL;
01830   }
01831 #endif /* WITH_ICU */
01832 
01833   /* Some lists need to be sorted again after a language change. */
01834   ReconsiderGameScriptLanguage();
01835   InitializeSortedCargoSpecs();
01836   SortIndustryTypes();
01837   BuildIndustriesLegend();
01838   SortNetworkLanguages();
01839   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
01840   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
01841   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
01842   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
01843   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
01844   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
01845   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
01846 
01847   return true;
01848 }
01849 
01850 /* Win32 implementation in win32.cpp.
01851  * OS X implementation in os/macosx/macos.mm. */
01852 #if !(defined(WIN32) || defined(__APPLE__))
01853 
01861 const char *GetCurrentLocale(const char *param)
01862 {
01863   const char *env;
01864 
01865   env = getenv("LANGUAGE");
01866   if (env != NULL) return env;
01867 
01868   env = getenv("LC_ALL");
01869   if (env != NULL) return env;
01870 
01871   if (param != NULL) {
01872     env = getenv(param);
01873     if (env != NULL) return env;
01874   }
01875 
01876   return getenv("LANG");
01877 }
01878 #else
01879 const char *GetCurrentLocale(const char *param);
01880 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
01881 
01882 int CDECL StringIDSorter(const StringID *a, const StringID *b)
01883 {
01884   char stra[512];
01885   char strb[512];
01886   GetString(stra, *a, lastof(stra));
01887   GetString(strb, *b, lastof(strb));
01888 
01889   return strcmp(stra, strb);
01890 }
01891 
01897 const LanguageMetadata *GetLanguage(byte newgrflangid)
01898 {
01899   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
01900     if (newgrflangid == lang->newgrflangid) return lang;
01901   }
01902 
01903   return NULL;
01904 }
01905 
01912 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
01913 {
01914   FILE *f = fopen(file, "rb");
01915   if (f == NULL) return false;
01916 
01917   size_t read = fread(hdr, sizeof(*hdr), 1, f);
01918   fclose(f);
01919 
01920   bool ret = read == 1 && hdr->IsValid();
01921 
01922   /* Convert endianness for the windows language ID */
01923   if (ret) {
01924     hdr->missing = FROM_LE16(hdr->missing);
01925     hdr->winlangid = FROM_LE16(hdr->winlangid);
01926   }
01927   return ret;
01928 }
01929 
01934 static void GetLanguageList(const char *path)
01935 {
01936   DIR *dir = ttd_opendir(path);
01937   if (dir != NULL) {
01938     struct dirent *dirent;
01939     while ((dirent = readdir(dir)) != NULL) {
01940       const char *d_name    = FS2OTTD(dirent->d_name);
01941       const char *extension = strrchr(d_name, '.');
01942 
01943       /* Not a language file */
01944       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
01945 
01946       LanguageMetadata lmd;
01947       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
01948 
01949       /* Check whether the file is of the correct version */
01950       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
01951         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
01952       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
01953         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
01954       } else {
01955         *_languages.Append() = lmd;
01956       }
01957     }
01958     closedir(dir);
01959   }
01960 }
01961 
01966 void InitializeLanguagePacks()
01967 {
01968   Searchpath sp;
01969 
01970   FOR_ALL_SEARCHPATHS(sp) {
01971     char path[MAX_PATH];
01972     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
01973     GetLanguageList(path);
01974   }
01975   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
01976 
01977   /* Acquire the locale of the current system */
01978   const char *lang = GetCurrentLocale("LC_MESSAGES");
01979   if (lang == NULL) lang = "en_GB";
01980 
01981   const LanguageMetadata *chosen_language   = NULL; 
01982   const LanguageMetadata *language_fallback = NULL; 
01983   const LanguageMetadata *en_GB_fallback    = _languages.Begin(); 
01984 
01985   /* Find a proper language. */
01986   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
01987     /* We are trying to find a default language. The priority is by
01988      * configuration file, local environment and last, if nothing found,
01989      * English. */
01990     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
01991     if (strcmp(lang_file, _config_language_file) == 0) {
01992       chosen_language = lng;
01993       break;
01994     }
01995 
01996     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
01997     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
01998     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
01999   }
02000 
02001   /* We haven't found the language in the config nor the one in the locale.
02002    * Now we set it to one of the fallback languages */
02003   if (chosen_language == NULL) {
02004     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
02005   }
02006 
02007   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
02008 }
02009 
02014 const char *GetCurrentLanguageIsoCode()
02015 {
02016   return _langpack->isocode;
02017 }
02018 
02025 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
02026 {
02027   InitFreeType(this->Monospace());
02028   const Sprite *question_mark[FS_END];
02029 
02030   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
02031     question_mark[size] = GetGlyph(size, '?');
02032   }
02033 
02034   this->Reset();
02035   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
02036     FontSize size = this->DefaultSize();
02037     if (str != NULL) *str = text;
02038     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
02039       if (c == SCC_SETX) {
02040         /* SetX is, together with SetXY as special character that
02041           * uses the next (two) characters as data points. We have
02042           * to skip those, otherwise the UTF8 reading will go haywire. */
02043         text++;
02044       } else if (c == SCC_SETXY) {
02045         text += 2;
02046       } else if (c == SCC_TINYFONT) {
02047         size = FS_SMALL;
02048       } else if (c == SCC_BIGFONT) {
02049         size = FS_LARGE;
02050       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
02051         /* The character is printable, but not in the normal font. This is the case we were testing for. */
02052         return true;
02053       }
02054     }
02055   }
02056   return false;
02057 }
02058 
02060 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
02061   uint i; 
02062   uint j; 
02063 
02064   /* virtual */ void Reset()
02065   {
02066     this->i = 0;
02067     this->j = 0;
02068   }
02069 
02070   /* virtual */ FontSize DefaultSize()
02071   {
02072     return FS_NORMAL;
02073   }
02074 
02075   /* virtual */ const char *NextString()
02076   {
02077     if (this->i >= TAB_COUNT) return NULL;
02078 
02079     const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
02080 
02081     this->j++;
02082     while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) {
02083       this->i++;
02084       this->j = 0;
02085     }
02086 
02087     return ret;
02088   }
02089 
02090   /* virtual */ bool Monospace()
02091   {
02092     return false;
02093   }
02094 
02095   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
02096   {
02097 #ifdef WITH_FREETYPE
02098     strecpy(settings->small_font,  font_name, lastof(settings->small_font));
02099     strecpy(settings->medium_font, font_name, lastof(settings->medium_font));
02100     strecpy(settings->large_font,  font_name, lastof(settings->large_font));
02101 #endif /* WITH_FREETYPE */
02102   }
02103 };
02104 
02118 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
02119 {
02120   static LanguagePackGlyphSearcher pack_searcher;
02121   if (searcher == NULL) searcher = &pack_searcher;
02122   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
02123 #ifdef WITH_FREETYPE
02124   if (bad_font) {
02125     /* We found an unprintable character... lets try whether we can find
02126      * a fallback font that can print the characters in the current language. */
02127     FreeTypeSettings backup;
02128     memcpy(&backup, &_freetype, sizeof(backup));
02129 
02130     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
02131 
02132     memcpy(&_freetype, &backup, sizeof(backup));
02133 
02134     if (bad_font && base_font) {
02135       /* Our fallback font does miss characters too, so keep the
02136        * user chosen font as that is more likely to be any good than
02137        * the wild guess we made */
02138       InitFreeType(searcher->Monospace());
02139     }
02140   }
02141 #endif
02142 
02143   if (bad_font) {
02144     /* All attempts have failed. Display an error. As we do not want the string to be translated by
02145      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
02146      * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
02147      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
02148      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
02149     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.");
02150     Utf8Encode(err_str, SCC_YELLOW);
02151     SetDParamStr(0, err_str);
02152     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
02153 
02154     /* Reset the font width */
02155     LoadStringWidthTable(searcher->Monospace());
02156     return;
02157   }
02158 
02159   /* Update the font with cache */
02160   LoadStringWidthTable(searcher->Monospace());
02161 
02162 #if !defined(WITH_ICU)
02163   /*
02164    * For right-to-left languages we need the ICU library. If
02165    * we do not have support for that library we warn the user
02166    * about it with a message. As we do not want the string to
02167    * be translated by the translators, we 'force' it into the
02168    * binary and 'load' it via a BindCString. To do this
02169    * properly we have to set the colour of the string,
02170    * otherwise we end up with a lot of artifacts. The colour
02171    * 'character' might change in the future, so for safety
02172    * we just Utf8 Encode it into the string, which takes
02173    * exactly three characters, so it replaces the "XXX" with
02174    * the colour marker.
02175    */
02176   if (_current_text_dir != TD_LTR) {
02177     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
02178     Utf8Encode(err_str, SCC_YELLOW);
02179     SetDParamStr(0, err_str);
02180     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02181   }
02182 #endif
02183 }