00001
00002
00003
00004
00005
00006
00007
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 "group.h"
00023 #include "signs_base.h"
00024 #include "cargotype.h"
00025 #include "fontcache.h"
00026 #include "gui.h"
00027 #include "strings_func.h"
00028 #include "rev.h"
00029 #include "core/endian_func.hpp"
00030 #include "date_func.h"
00031 #include "vehicle_base.h"
00032 #include "engine_base.h"
00033 #include "language.h"
00034 #include "townname_func.h"
00035 #include "string_func.h"
00036 #include "company_base.h"
00037 #include "smallmap_gui.h"
00038 #include "window_func.h"
00039 #include "debug.h"
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 uint64 _decode_parameters[20];
00050 WChar _parameter_type[20];
00051
00052 #ifdef WITH_ICU
00053 Collator *_current_collator = NULL;
00054 #endif
00055
00056 static char *StationGetSpecialString(char *buff, int x, const char *last);
00057 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
00058 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt = NULL);
00059
00060 static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt = NULL, bool dry_run = false);
00061
00062 struct LanguagePack : public LanguagePackHeader {
00063 char data[];
00064 };
00065
00066 static char **_langpack_offs;
00067 static LanguagePack *_langpack;
00068 static uint _langtab_num[32];
00069 static uint _langtab_start[32];
00070 static bool _keep_gender_data = false;
00071
00072
00083 static inline int64 GetInt64(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
00084 {
00085 assert(*argv != NULL);
00086 assert(*argv < argve);
00087 if (*argt != NULL) {
00088 assert(**argt == 0 || **argt == type);
00089 **argt = type;
00090 (*argt)++;
00091 }
00092 return *(*argv)++;
00093 }
00094
00096 static inline int32 GetInt32(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
00097 {
00098 return (int32)GetInt64(argv, argve, argt, type);
00099 }
00100
00109 static inline int64 *GetArgvPtr(int64 **argv, int n, const int64 *argve, WChar **argt)
00110 {
00111 int64 *result;
00112 assert(*argv != NULL);
00113 assert((*argv + n) <= argve);
00114 result = *argv;
00115 (*argv) += n;
00116 if (*argt != NULL) (*argt) += n;
00117 return result;
00118 }
00119
00120
00121 const char *GetStringPtr(StringID string)
00122 {
00123 switch (GB(string, 11, 5)) {
00124 case 28: return GetGRFStringPtr(GB(string, 0, 11));
00125 case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
00126 case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
00127 default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
00128 }
00129 }
00130
00144 char *GetStringWithArgs(char *buffr, uint string, int64 *argv, const int64 *argve, const char *last, WChar *argt)
00145 {
00146 if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, argve, last, argt);
00147
00148 uint index = GB(string, 0, 11);
00149 uint tab = GB(string, 11, 5);
00150
00151 switch (tab) {
00152 case 4:
00153 if (index >= 0xC0) {
00154 return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv, argve, &argt), last);
00155 }
00156 break;
00157
00158 case 14:
00159 if (index >= 0xE4) {
00160 return GetSpecialNameString(buffr, index - 0xE4, argv, argve, last, argt);
00161 }
00162 break;
00163
00164 case 15:
00165
00166 error("Incorrect conversion of custom name string.");
00167
00168 case 26:
00169
00170 if (HasBit(index, 10)) {
00171 StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
00172 return GetStringWithArgs(buffr, string, argv, argve, last, argt);
00173 }
00174 break;
00175
00176 case 28:
00177 return FormatString(buffr, GetGRFStringPtr(index), argv, argve, GB(string, 24, 8), last, argt);
00178
00179 case 29:
00180 return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, argve, GB(string, 24, 8), last, argt);
00181
00182 case 30:
00183 return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, argve, GB(string, 24, 8), last, argt);
00184
00185 case 31:
00186 NOT_REACHED();
00187 }
00188
00189 if (index >= _langtab_num[tab]) {
00190 error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
00191 }
00192
00193 return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, argve, GB(string, 24, 8), last, argt);
00194 }
00195
00196 char *GetString(char *buffr, StringID string, const char *last)
00197 {
00198 memset(_parameter_type, 0, sizeof(_parameter_type));
00199 return GetStringWithArgs(buffr, string, (int64*)_decode_parameters, (int64*)endof(_decode_parameters), last, _parameter_type);
00200 }
00201
00202
00203 char *InlineString(char *buf, StringID string)
00204 {
00205 buf += Utf8Encode(buf, SCC_STRING_ID);
00206 buf += Utf8Encode(buf, string);
00207 return buf;
00208 }
00209
00210
00216 void SetDParamStr(uint n, const char *str)
00217 {
00218 SetDParam(n, (uint64)(size_t)str);
00219 }
00220
00225 void InjectDParam(uint amount)
00226 {
00227 assert((uint)amount < lengthof(_decode_parameters));
00228 memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
00229 }
00230
00231 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill_from = 19)
00232 {
00233 uint64 divisor = 10000000000000000000ULL;
00234
00235 if (number < 0) {
00236 buff += seprintf(buff, last, "-");
00237 number = -number;
00238 }
00239
00240 uint64 num = number;
00241 uint64 tot = 0;
00242 for (int i = 0; i < 20; i++) {
00243 uint64 quot = 0;
00244 if (num >= divisor) {
00245 quot = num / divisor;
00246 num = num % divisor;
00247 }
00248 if (tot |= quot || i >= zerofill_from) {
00249 buff += seprintf(buff, last, "%i", (int)quot);
00250 if ((i % 3) == 1 && i != 19) buff = strecpy(buff, separator, last);
00251 }
00252
00253 divisor /= 10;
00254 }
00255
00256 *buff = '\0';
00257
00258 return buff;
00259 }
00260
00261 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
00262 {
00263 const char *separator = _settings_game.locale.digit_group_separator;
00264 if (separator == NULL) separator = _langpack->digit_group_separator;
00265 return FormatNumber(buff, number, last, separator);
00266 }
00267
00268 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
00269 {
00270 return FormatNumber(buff, number, last, "");
00271 }
00272
00273 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
00274 {
00275 return FormatNumber(buff, number, last, "", 20 - count);
00276 }
00277
00278 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
00279 {
00280 return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
00281 }
00282
00290 static char *FormatBytes(char *buff, int64 number, const char *last)
00291 {
00292 assert(number >= 0);
00293
00294
00295 const char * const iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
00296 uint id = 1;
00297 while (number >= 1024 * 1024) {
00298 number /= 1024;
00299 id++;
00300 }
00301
00302 const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
00303 if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
00304
00305 if (number < 1024) {
00306 id = 0;
00307 buff += seprintf(buff, last, "%i", (int)number);
00308 } else if (number < 1024 * 10) {
00309 buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
00310 } else if (number < 1024 * 100) {
00311 buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
00312 } else {
00313 assert(number < 1024 * 1024);
00314 buff += seprintf(buff, last, "%i", (int)number / 1024);
00315 }
00316
00317 assert(id < lengthof(iec_prefixes));
00318 buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
00319
00320 return buff;
00321 }
00322
00323 static char *FormatYmdString(char *buff, Date date, uint modifier, const char *last)
00324 {
00325 YearMonthDay ymd;
00326 ConvertDateToYMD(date, &ymd);
00327
00328 int64 args[3] = { ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year };
00329 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), args, endof(args), modifier >> 24, last);
00330 }
00331
00332 static char *FormatMonthAndYear(char *buff, Date date, uint modifier, const char *last)
00333 {
00334 YearMonthDay ymd;
00335 ConvertDateToYMD(date, &ymd);
00336
00337 int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
00338 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), args, endof(args), modifier >> 24, last);
00339 }
00340
00341 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
00342 {
00343 YearMonthDay ymd;
00344 ConvertDateToYMD(date, &ymd);
00345
00346 char day[3];
00347 char month[3];
00348
00349 snprintf(day, lengthof(day), "%02i", ymd.day);
00350 snprintf(month, lengthof(month), "%02i", ymd.month + 1);
00351
00352 int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
00353 return FormatString(buff, GetStringPtr(str), args, endof(args), 0, last);
00354 }
00355
00356 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
00357 {
00358
00359
00360 bool negative = number < 0;
00361 const char *multiplier = "";
00362
00363 number *= spec->rate;
00364
00365
00366 if (number < 0) {
00367 if (buff + Utf8CharLen(SCC_RED) > last) return buff;
00368 buff += Utf8Encode(buff, SCC_RED);
00369 buff = strecpy(buff, "-", last);
00370 number = -number;
00371 }
00372
00373
00374
00375
00376 if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
00377
00378
00379 if (compact) {
00380
00381
00382 if (number >= 1000000000 - 500) {
00383 number = (number + 500000) / 1000000;
00384 multiplier = "M";
00385 } else if (number >= 1000000) {
00386 number = (number + 500) / 1000;
00387 multiplier = "k";
00388 }
00389 }
00390
00391 const char *separator = _settings_game.locale.digit_group_separator_currency;
00392 if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
00393 if (separator == NULL) separator = _langpack->digit_group_separator_currency;
00394 buff = FormatNumber(buff, number, last, separator);
00395 buff = strecpy(buff, multiplier, last);
00396
00397
00398
00399
00400 if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
00401
00402 if (negative) {
00403 if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
00404 buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
00405 *buff = '\0';
00406 }
00407
00408 return buff;
00409 }
00410
00417 static int DeterminePluralForm(int64 count, int plural_form)
00418 {
00419
00420 uint64 n = abs(count);
00421
00422 switch (plural_form) {
00423 default:
00424 NOT_REACHED();
00425
00426
00427
00428
00429
00430 case 0:
00431 return n != 1;
00432
00433
00434
00435
00436 case 1:
00437 return 0;
00438
00439
00440
00441
00442 case 2:
00443 return n > 1;
00444
00445
00446
00447
00448 case 3:
00449 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
00450
00451
00452
00453
00454 case 4:
00455 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
00456
00457
00458
00459
00460 case 5:
00461 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00462
00463
00464
00465
00466 case 6:
00467 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00468
00469
00470
00471
00472 case 7:
00473 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00474
00475
00476
00477
00478 case 8:
00479 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
00480
00481
00482
00483
00484 case 9:
00485 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
00486
00487
00488
00489
00490 case 10:
00491 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
00492
00493
00494
00495
00496
00497
00498
00499 case 11:
00500 switch (n % 10) {
00501 case 0:
00502 case 1:
00503 case 3:
00504 case 6:
00505 case 7:
00506 case 8:
00507 return 0;
00508
00509 case 2:
00510 case 4:
00511 case 5:
00512 case 9:
00513 return 1;
00514
00515 default:
00516 NOT_REACHED();
00517 }
00518
00519
00520
00521
00522 case 12:
00523 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
00524 }
00525 }
00526
00527 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
00528 {
00529
00530 uint n = (byte)*b++;
00531 uint pos, i, mypos = 0;
00532
00533 for (i = pos = 0; i != n; i++) {
00534 uint len = (byte)*b++;
00535 if (i == form) mypos = pos;
00536 pos += len;
00537 }
00538
00539 *dst += seprintf(*dst, last, "%s", b + mypos);
00540 return b + pos;
00541 }
00542
00543 struct Units {
00544 int s_m;
00545 int s_s;
00546 StringID velocity;
00547 int p_m;
00548 int p_s;
00549 StringID power;
00550 int w_m;
00551 int w_s;
00552 StringID s_weight;
00553 StringID l_weight;
00554 int v_m;
00555 int v_s;
00556 StringID s_volume;
00557 StringID l_volume;
00558 int f_m;
00559 int f_s;
00560 StringID force;
00561 int h_m;
00562 int h_s;
00563 StringID height;
00564 };
00565
00566
00567 static const Units units[] = {
00568 {
00569 1, 0, STR_UNITS_VELOCITY_IMPERIAL,
00570 1, 0, STR_UNITS_POWER_IMPERIAL,
00571 1, 0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00572 1000, 0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00573 1, 0, STR_UNITS_FORCE_SI,
00574 3, 0, STR_UNITS_HEIGHT_IMPERIAL,
00575 },
00576 {
00577 103, 6, STR_UNITS_VELOCITY_METRIC,
00578 1, 0, STR_UNITS_POWER_METRIC,
00579 1, 0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00580 1000, 0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00581 1, 0, STR_UNITS_FORCE_SI,
00582 1, 0, STR_UNITS_HEIGHT_SI,
00583 },
00584 {
00585 1831, 12, STR_UNITS_VELOCITY_SI,
00586 764, 10, STR_UNITS_POWER_SI,
00587 1000, 0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
00588 1, 0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
00589 1, 0, STR_UNITS_FORCE_SI,
00590 1, 0, STR_UNITS_HEIGHT_SI,
00591 },
00592 };
00593
00599 uint ConvertSpeedToDisplaySpeed(uint speed)
00600 {
00601 return (speed * units[_settings_game.locale.units].s_m) >> units[_settings_game.locale.units].s_s;
00602 }
00603
00609 uint ConvertDisplaySpeedToSpeed(uint speed)
00610 {
00611 return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
00612 }
00613
00625 static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt, bool dry_run)
00626 {
00627
00628 if (argt == NULL) dry_run = true;
00629 if (UsingNewGRFTextStack() && !dry_run) {
00630
00631
00632
00633
00634
00635
00636 struct TextRefStack *backup = CreateTextRefStackBackup();
00637 FormatString(buff, str, argv, argve, casei, last, argt, true);
00638 RestoreTextRefStackBackup(backup);
00639 } else if (!dry_run) {
00640 FormatString(buff, str, argv, argve, casei, last, argt, true);
00641 }
00642 WChar b;
00643 int64 *argv_orig = argv;
00644 WChar *argt_orig = argt;
00645 uint modifier = 0;
00646 char *buf_start = buff;
00647
00648 while ((b = Utf8Consume(&str)) != '\0') {
00649 if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
00650
00651
00652 b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, argv);
00653 if (b == 0) continue;
00654 }
00655
00656 switch (b) {
00657 case SCC_SETX:
00658 if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
00659 buff += Utf8Encode(buff, SCC_SETX);
00660 *buff++ = *str++;
00661 }
00662 break;
00663
00664 case SCC_SETXY:
00665 if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
00666 buff += Utf8Encode(buff, SCC_SETXY);
00667 *buff++ = *str++;
00668 *buff++ = *str++;
00669 }
00670 break;
00671
00672 case SCC_STRING_ID:
00673 buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, argve, last, argt);
00674 break;
00675
00676 case SCC_RAW_STRING_POINTER: {
00677 const char *str = (const char*)(size_t)GetInt64(&argv, argve, &argt);
00678 buff = FormatString(buff, str, argv, argve, casei, last, argt);
00679 break;
00680 }
00681
00682 case SCC_DATE_LONG:
00683 buff = FormatYmdString(buff, GetInt32(&argv, argve, &argt, SCC_DATE_LONG), modifier, last);
00684 break;
00685
00686 case SCC_DATE_SHORT:
00687 buff = FormatMonthAndYear(buff, GetInt32(&argv, argve, &argt, SCC_DATE_SHORT), modifier, last);
00688 break;
00689
00690 case SCC_VELOCITY: {
00691 int64 args[1];
00692 assert(_settings_game.locale.units < lengthof(units));
00693 args[0] = ConvertSpeedToDisplaySpeed(GetInt32(&argv, argve, &argt, SCC_VELOCITY) * 10 / 16);
00694 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].velocity), args, endof(args), modifier >> 24, last);
00695 modifier = 0;
00696 break;
00697 }
00698
00699 case SCC_HEIGHT: {
00700 int64 args[1] = {GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].h_m >> units[_settings_game.locale.units].h_s};
00701 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].height), args, endof(args), modifier >> 24, last);
00702 modifier = 0;
00703 break;
00704 }
00705
00706 case SCC_CURRENCY_COMPACT:
00707 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt), true, last);
00708 break;
00709
00710 case SCC_REVISION:
00711 buff = strecpy(buff, _openttd_revision, last);
00712 break;
00713
00714 case SCC_CARGO_SHORT: {
00715
00716
00717
00718 StringID cargo_str = CargoSpec::Get(GetInt32(&argv, argve, &argt, SCC_CARGO_SHORT))->units_volume;
00719 switch (cargo_str) {
00720 case STR_TONS: {
00721 int64 args[1];
00722 assert(_settings_game.locale.units < lengthof(units));
00723 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00724 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
00725 modifier = 0;
00726 break;
00727 }
00728
00729 case STR_LITERS: {
00730 int64 args[1];
00731 assert(_settings_game.locale.units < lengthof(units));
00732 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00733 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
00734 modifier = 0;
00735 break;
00736 }
00737
00738 default:
00739 buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last, argt++);
00740 break;
00741 }
00742 break;
00743 }
00744
00745 case SCC_STRING1: {
00746
00747 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING1);
00748 WChar *orig_argt = argt;
00749 int64 *args = GetArgvPtr(&argv, 1, argve, &argt);
00750 buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00751 modifier = 0;
00752 break;
00753 }
00754
00755 case SCC_STRING2: {
00756
00757 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING2);
00758 WChar *orig_argt = argt;
00759 int64 *args = GetArgvPtr(&argv, 2, argve, &argt);
00760 buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00761 modifier = 0;
00762 break;
00763 }
00764
00765 case SCC_STRING3: {
00766
00767 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING3);
00768 WChar *orig_argt = argt;
00769 int64 *args = GetArgvPtr(&argv, 3, argve, &argt);
00770 buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00771 modifier = 0;
00772 break;
00773 }
00774
00775 case SCC_STRING4: {
00776
00777 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING4);
00778 WChar *orig_argt = argt;
00779 int64 *args = GetArgvPtr(&argv, 4, argve, &argt);
00780 buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00781 modifier = 0;
00782 break;
00783 }
00784
00785 case SCC_STRING5: {
00786
00787 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING5);
00788 WChar *orig_argt = argt;
00789 int64 *args = GetArgvPtr(&argv, 5, argve, &argt);
00790 buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00791 modifier = 0;
00792 break;
00793 }
00794
00795 case SCC_STATION_FEATURES: {
00796 buff = StationGetSpecialString(buff, GetInt32(&argv, argve, &argt, SCC_STATION_FEATURES), last);
00797 break;
00798 }
00799
00800 case SCC_INDUSTRY_NAME: {
00801 const Industry *i = Industry::Get(GetInt32(&argv, argve, &argt, SCC_INDUSTRY_NAME));
00802 int64 args[2];
00803
00804
00805 assert(i != NULL);
00806
00807
00808 args[0] = i->town->index;
00809 args[1] = GetIndustrySpec(i->type)->name;
00810 buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), args, endof(args), modifier >> 24, last);
00811 modifier = 0;
00812 break;
00813 }
00814
00815 case SCC_VOLUME: {
00816 int64 args[1];
00817 assert(_settings_game.locale.units < lengthof(units));
00818 args[0] = GetInt32(&argv, argve, &argt, SCC_VOLUME) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00819 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
00820 modifier = 0;
00821 break;
00822 }
00823
00824 case SCC_GENDER_LIST: {
00825
00826 byte offset = (byte)*str++;
00827 assert(argv_orig + offset < argve);
00828 int gender = 0;
00829 if (!dry_run && argt != NULL && argt_orig[offset] != 0) {
00830
00831
00832
00833 char input[4 + 1];
00834 char *p = input + Utf8Encode(input, argt_orig[offset]);
00835 *p = '\0';
00836
00837
00838 char buf[256];
00839 bool old_kgd = _keep_gender_data;
00840 _keep_gender_data = true;
00841 p = FormatString(buf, input, argv_orig + offset, argve, 0, lastof(buf));
00842 _keep_gender_data = old_kgd;
00843 *p = '\0';
00844
00845
00846 const char *s = buf;
00847 WChar c = Utf8Consume(&s);
00848
00849 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
00850 }
00851 str = ParseStringChoice(str, gender, &buff, last);
00852 break;
00853 }
00854
00855 case SCC_DATE_TINY: {
00856 buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt, SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
00857 break;
00858 }
00859
00860 case SCC_DATE_ISO: {
00861 buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt), STR_FORMAT_DATE_ISO, last);
00862 break;
00863 }
00864
00865 case SCC_CARGO: {
00866
00867 CargoID cargo = GetInt32(&argv, argve, &argt, SCC_CARGO);
00868 StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
00869 buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last);
00870 break;
00871 }
00872
00873 case SCC_POWER: {
00874 int64 args[1];
00875 assert(_settings_game.locale.units < lengthof(units));
00876 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
00877 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, endof(args), modifier >> 24, last);
00878 modifier = 0;
00879 break;
00880 }
00881
00882 case SCC_VOLUME_SHORT: {
00883 int64 args[1];
00884 assert(_settings_game.locale.units < lengthof(units));
00885 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00886 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, endof(args), modifier >> 24, last);
00887 modifier = 0;
00888 break;
00889 }
00890
00891 case SCC_WEIGHT: {
00892 int64 args[1];
00893 assert(_settings_game.locale.units < lengthof(units));
00894 args[0] = GetInt32(&argv, argve, &argt, SCC_WEIGHT) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00895 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
00896 modifier = 0;
00897 break;
00898 }
00899
00900 case SCC_WEIGHT_SHORT: {
00901 int64 args[1];
00902 assert(_settings_game.locale.units < lengthof(units));
00903 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00904 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, endof(args), modifier >> 24, last);
00905 modifier = 0;
00906 break;
00907 }
00908
00909 case SCC_FORCE: {
00910 int64 args[1];
00911 assert(_settings_game.locale.units < lengthof(units));
00912 args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
00913 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, endof(args), modifier >> 24, last);
00914 modifier = 0;
00915 break;
00916 }
00917
00918
00919
00920 case SCC_GENDER_INDEX:
00921 if (_keep_gender_data) {
00922 buff += Utf8Encode(buff, SCC_GENDER_INDEX);
00923 *buff++ = *str++;
00924 } else {
00925 str++;
00926 }
00927 break;
00928
00929 case SCC_STRING: {
00930 uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING);
00931
00932
00933
00934 buff = GetStringWithArgs(buff, str, argv, argve, last);
00935 modifier = 0;
00936 break;
00937 }
00938
00939 case SCC_COMMA:
00940 buff = FormatCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_COMMA), last);
00941 break;
00942
00943 case SCC_ARG_INDEX: {
00944 byte offset = (byte)*str++;
00945 argv = argv_orig + offset;
00946 if (argt_orig != NULL) argt = argt_orig + offset;
00947 break;
00948 }
00949
00950 case SCC_PLURAL_LIST: {
00951 int plural_form = *str++;
00952 byte idx = *str++;
00953 assert(argv_orig + idx < argve);
00954 int64 v = argv_orig[idx];
00955 str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
00956 break;
00957 }
00958
00959 case SCC_NUM:
00960 buff = FormatNoCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_NUM), last);
00961 break;
00962
00963 case SCC_ZEROFILL_NUM: {
00964 int64 num = GetInt64(&argv, argve, &argt);
00965 buff = FormatZerofillNumber(buff, num, GetInt64(&argv, argve, &argt), last);
00966 break;
00967 }
00968
00969 case SCC_HEX:
00970 buff = FormatHexNumber(buff, (uint64)GetInt64(&argv, argve, &argt, SCC_HEX), last);
00971 break;
00972
00973 case SCC_BYTES:
00974 buff = FormatBytes(buff, GetInt64(&argv, argve, &argt), last);
00975 break;
00976
00977 case SCC_CURRENCY:
00978 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt, SCC_CURRENCY), false, last);
00979 break;
00980
00981 case SCC_WAYPOINT_NAME: {
00982 Waypoint *wp = Waypoint::Get(GetInt32(&argv, argve, &argt, SCC_WAYPOINT_NAME));
00983
00984 assert(wp != NULL);
00985
00986 if (wp->name != NULL) {
00987 buff = strecpy(buff, wp->name, last);
00988 } else {
00989 int64 args[2];
00990 args[0] = wp->town->index;
00991 args[1] = wp->town_cn + 1;
00992 StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
00993 if (wp->town_cn != 0) str++;
00994 buff = GetStringWithArgs(buff, str, args, endof(args), last);
00995 }
00996 break;
00997 }
00998
00999 case SCC_STATION_NAME: {
01000 StationID sid = GetInt32(&argv, argve, &argt, SCC_STATION_NAME);
01001 const Station *st = Station::GetIfValid(sid);
01002
01003 if (st == NULL) {
01004
01005
01006
01007 buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, NULL, last);
01008 break;
01009 }
01010
01011 if (st->name != NULL) {
01012 buff = strecpy(buff, st->name, last);
01013 } else {
01014 StringID str = st->string_id;
01015 if (st->indtype != IT_INVALID) {
01016
01017 const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
01018
01019
01020
01021
01022 if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
01023 str = indsp->station_name;
01024 }
01025 }
01026
01027 int64 args[3];
01028 args[0] = STR_TOWN_NAME;
01029 args[1] = st->town->index;
01030 args[2] = st->index;
01031 buff = GetStringWithArgs(buff, str, args, endof(args), last);
01032 }
01033 break;
01034 }
01035
01036 case SCC_DEPOT_NAME: {
01037 VehicleType vt = (VehicleType)GetInt32(&argv, argve, &argt, SCC_DEPOT_NAME);
01038 if (vt == VEH_AIRCRAFT) {
01039 int64 args[] = { GetInt32(&argv, argve, &argt) };
01040 buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, args, endof(args), last);
01041 break;
01042 }
01043
01044 const Depot *d = Depot::Get(GetInt32(&argv, argve, &argt));
01045 if (d->name != NULL) {
01046 buff = strecpy(buff, d->name, last);
01047 } else {
01048 int64 args[] = { d->town->index, d->town_cn + 1 };
01049 buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), args, endof(args), last);
01050 }
01051 break;
01052 }
01053
01054 case SCC_TOWN_NAME: {
01055 const Town *t = Town::Get(GetInt32(&argv, argve, &argt, SCC_TOWN_NAME));
01056
01057 assert(t != NULL);
01058
01059 if (t->name != NULL) {
01060 buff = strecpy(buff, t->name, last);
01061 } else {
01062 buff = GetTownName(buff, t, last);
01063 }
01064 break;
01065 }
01066
01067 case SCC_GROUP_NAME: {
01068 const Group *g = Group::Get(GetInt32(&argv, argve, &argt));
01069
01070 assert(g != NULL);
01071
01072 if (g->name != NULL) {
01073 buff = strecpy(buff, g->name, last);
01074 } else {
01075 int64 args[1];
01076
01077 args[0] = g->index;
01078 buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, args, endof(args), last);
01079 }
01080 break;
01081 }
01082
01083 case SCC_ENGINE_NAME: {
01084 EngineID engine = (EngineID)GetInt32(&argv, argve, &argt, SCC_ENGINE_NAME);
01085 const Engine *e = Engine::Get(engine);
01086
01087 assert(e != NULL);
01088
01089 if (e->name != NULL && e->info.string_id != STR_NEWGRF_INVALID_ENGINE) {
01090 buff = strecpy(buff, e->name, last);
01091 } else {
01092 buff = GetStringWithArgs(buff, e->info.string_id, NULL, NULL, last);
01093 }
01094 break;
01095 }
01096
01097 case SCC_VEHICLE_NAME: {
01098 const Vehicle *v = Vehicle::Get(GetInt32(&argv, argve, &argt, SCC_VEHICLE_NAME));
01099
01100 assert(v != NULL);
01101
01102 if (v->name != NULL) {
01103 buff = strecpy(buff, v->name, last);
01104 } else {
01105 int64 args[1];
01106 args[0] = v->unitnumber;
01107
01108 StringID str;
01109 switch (v->type) {
01110 default: NOT_REACHED();
01111 case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break;
01112 case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME; break;
01113 case VEH_SHIP: str = STR_SV_SHIP_NAME; break;
01114 case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
01115 }
01116
01117 buff = GetStringWithArgs(buff, str, args, endof(args), last);
01118 }
01119 break;
01120 }
01121
01122 case SCC_SIGN_NAME: {
01123 const Sign *si = Sign::Get(GetInt32(&argv, argve, &argt));
01124 if (si->name != NULL) {
01125 buff = strecpy(buff, si->name, last);
01126 } else {
01127 buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, NULL, NULL, last);
01128 }
01129 break;
01130 }
01131
01132 case SCC_COMPANY_NAME: {
01133 const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt));
01134
01135 if (c->name != NULL) {
01136 buff = strecpy(buff, c->name, last);
01137 } else {
01138 int64 args[1];
01139 args[0] = c->name_2;
01140 buff = GetStringWithArgs(buff, c->name_1, args, endof(args), last);
01141 }
01142 break;
01143 }
01144
01145 case SCC_COMPANY_NUM: {
01146 CompanyID company = (CompanyID)GetInt32(&argv, argve, &argt);
01147
01148
01149 if (Company::IsValidHumanID(company)) {
01150 int64 args[1];
01151 args[0] = company + 1;
01152 buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, args, endof(args), last);
01153 }
01154 break;
01155 }
01156
01157 case SCC_PRESIDENT_NAME: {
01158 const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt, SCC_PRESIDENT_NAME));
01159
01160 if (c->president_name != NULL) {
01161 buff = strecpy(buff, c->president_name, last);
01162 } else {
01163 int64 args[1];
01164 args[0] = c->president_name_2;
01165 buff = GetStringWithArgs(buff, c->president_name_1, args, endof(args), last);
01166 }
01167 break;
01168 }
01169
01170 case SCC_SETCASE: {
01171
01172
01173 modifier = (byte)*str++ << 24;
01174 break;
01175 }
01176
01177 case SCC_SWITCH_CASE: {
01178
01179
01180 uint num = (byte)*str++;
01181 while (num) {
01182 if ((byte)str[0] == casei) {
01183
01184 str += 3;
01185 break;
01186 }
01187
01188 str += 3 + (str[1] << 8) + str[2];
01189 num--;
01190 }
01191 break;
01192 }
01193
01194 default:
01195 if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01196 break;
01197 }
01198 }
01199 *buff = '\0';
01200 return buff;
01201 }
01202
01203
01204 static char *StationGetSpecialString(char *buff, int x, const char *last)
01205 {
01206 if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01207 if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01208 if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
01209 if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
01210 if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01211 *buff = '\0';
01212 return buff;
01213 }
01214
01215 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01216 {
01217 return GenerateTownNameString(buff, last, ind, seed);
01218 }
01219
01220 static const char * const _silly_company_names[] = {
01221 "Bloggs Brothers",
01222 "Tiny Transport Ltd.",
01223 "Express Travel",
01224 "Comfy-Coach & Co.",
01225 "Crush & Bump Ltd.",
01226 "Broken & Late Ltd.",
01227 "Sam Speedy & Son",
01228 "Supersonic Travel",
01229 "Mike's Motors",
01230 "Lightning International",
01231 "Pannik & Loozit Ltd.",
01232 "Inter-City Transport",
01233 "Getout & Pushit Ltd."
01234 };
01235
01236 static const char * const _surname_list[] = {
01237 "Adams",
01238 "Allan",
01239 "Baker",
01240 "Bigwig",
01241 "Black",
01242 "Bloggs",
01243 "Brown",
01244 "Campbell",
01245 "Gordon",
01246 "Hamilton",
01247 "Hawthorn",
01248 "Higgins",
01249 "Green",
01250 "Gribble",
01251 "Jones",
01252 "McAlpine",
01253 "MacDonald",
01254 "McIntosh",
01255 "Muir",
01256 "Murphy",
01257 "Nelson",
01258 "O'Donnell",
01259 "Parker",
01260 "Phillips",
01261 "Pilkington",
01262 "Quigley",
01263 "Sharkey",
01264 "Thomson",
01265 "Watkins"
01266 };
01267
01268 static const char * const _silly_surname_list[] = {
01269 "Grumpy",
01270 "Dozy",
01271 "Speedy",
01272 "Nosey",
01273 "Dribble",
01274 "Mushroom",
01275 "Cabbage",
01276 "Sniffle",
01277 "Fishy",
01278 "Swindle",
01279 "Sneaky",
01280 "Nutkins"
01281 };
01282
01283 static const char _initial_name_letters[] = {
01284 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
01285 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
01286 };
01287
01288 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
01289 {
01290 const char * const *base;
01291 uint num;
01292
01293 if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01294 base = _silly_surname_list;
01295 num = lengthof(_silly_surname_list);
01296 } else {
01297 base = _surname_list;
01298 num = lengthof(_surname_list);
01299 }
01300
01301 buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
01302 buff = strecpy(buff, " & Co.", last);
01303
01304 return buff;
01305 }
01306
01307 static char *GenPresidentName(char *buff, uint32 x, const char *last)
01308 {
01309 char initial[] = "?. ";
01310 const char * const *base;
01311 uint num;
01312 uint i;
01313
01314 initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
01315 buff = strecpy(buff, initial, last);
01316
01317 i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
01318 if (i < sizeof(_initial_name_letters)) {
01319 initial[0] = _initial_name_letters[i];
01320 buff = strecpy(buff, initial, last);
01321 }
01322
01323 if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01324 base = _silly_surname_list;
01325 num = lengthof(_silly_surname_list);
01326 } else {
01327 base = _surname_list;
01328 num = lengthof(_surname_list);
01329 }
01330
01331 buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
01332
01333 return buff;
01334 }
01335
01336 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt)
01337 {
01338 switch (ind) {
01339 case 1:
01340 return strecpy(buff, _silly_company_names[GetInt32(&argv, argve, &argt) & 0xFFFF], last);
01341
01342 case 2:
01343 return GenAndCoName(buff, GetInt32(&argv, argve, &argt), last);
01344
01345 case 3:
01346 return GenPresidentName(buff, GetInt32(&argv, argve, &argt), last);
01347 }
01348
01349
01350 if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
01351 buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv, argve, &argt), last);
01352 return strecpy(buff, " Transport", last);
01353 }
01354
01355
01356 if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
01357 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
01358 return strecpy(buff,
01359 &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
01360 }
01361
01362
01363 if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
01364 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
01365 buff += seprintf(
01366 buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
01367 );
01368 return buff;
01369 }
01370
01371
01372 if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
01373 int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
01374 return strecpy(buff, GetScreenshotFormatDesc(i), last);
01375 }
01376
01377 NOT_REACHED();
01378 }
01379
01380 #ifdef ENABLE_NETWORK
01381 extern void SortNetworkLanguages();
01382 #else
01383 static inline void SortNetworkLanguages() {}
01384 #endif
01385
01390 bool LanguagePackHeader::IsValid() const
01391 {
01392 return this->ident == TO_LE32(LanguagePackHeader::IDENT) &&
01393 this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
01394 this->plural_form < LANGUAGE_MAX_PLURAL &&
01395 this->text_dir <= 1 &&
01396 this->newgrflangid < MAX_LANG &&
01397 this->num_genders < MAX_NUM_GENDERS &&
01398 this->num_cases < MAX_NUM_CASES &&
01399 StrValid(this->name, lastof(this->name)) &&
01400 StrValid(this->own_name, lastof(this->own_name)) &&
01401 StrValid(this->isocode, lastof(this->isocode)) &&
01402 StrValid(this->digit_group_separator, lastof(this->digit_group_separator)) &&
01403 StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
01404 StrValid(this->digit_decimal_separator, lastof(this->digit_decimal_separator));
01405 }
01406
01407 bool ReadLanguagePack(const LanguageMetadata *lang)
01408 {
01409
01410 size_t len;
01411 LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 200000);
01412 if (lang_pack == NULL) return false;
01413
01414
01415 const char *end = (char *)lang_pack + len + 1;
01416
01417
01418 if (end <= lang_pack->data || !lang_pack->IsValid()) {
01419 free(lang_pack);
01420 return false;
01421 }
01422
01423 #if TTD_ENDIAN == TTD_BIG_ENDIAN
01424 for (uint i = 0; i < 32; i++) {
01425 lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
01426 }
01427 #endif
01428
01429 uint count = 0;
01430 for (uint i = 0; i < 32; i++) {
01431 uint num = lang_pack->offsets[i];
01432 _langtab_start[i] = count;
01433 _langtab_num[i] = num;
01434 count += num;
01435 }
01436
01437
01438 char **langpack_offs = MallocT<char *>(count);
01439
01440
01441 char *s = lang_pack->data;
01442 len = (byte)*s++;
01443 for (uint i = 0; i < count; i++) {
01444 if (s + len >= end) {
01445 free(lang_pack);
01446 free(langpack_offs);
01447 return false;
01448 }
01449 if (len >= 0xC0) {
01450 len = ((len & 0x3F) << 8) + (byte)*s++;
01451 if (s + len >= end) {
01452 free(lang_pack);
01453 free(langpack_offs);
01454 return false;
01455 }
01456 }
01457 langpack_offs[i] = s;
01458 s += len;
01459 len = (byte)*s;
01460 *s++ = '\0';
01461 }
01462
01463 free(_langpack);
01464 _langpack = lang_pack;
01465
01466 free(_langpack_offs);
01467 _langpack_offs = langpack_offs;
01468
01469 _current_language = lang;
01470 _current_text_dir = (TextDirection)_current_language->text_dir;
01471 const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
01472 strecpy(_config_language_file, c_file, lastof(_config_language_file));
01473 SetCurrentGrfLangID(_current_language->newgrflangid);
01474
01475 #ifdef WITH_ICU
01476
01477 if (_current_collator != NULL) {
01478 delete _current_collator;
01479 _current_collator = NULL;
01480 }
01481
01482
01483 UErrorCode status = U_ZERO_ERROR;
01484 _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
01485
01486 if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
01487
01488 if (U_FAILURE(status)) {
01489 delete _current_collator;
01490 _current_collator = NULL;
01491 }
01492 #endif
01493
01494
01495 InitializeSortedCargoSpecs();
01496 SortIndustryTypes();
01497 BuildIndustriesLegend();
01498 SortNetworkLanguages();
01499 InvalidateWindowClassesData(WC_BUILD_VEHICLE);
01500 InvalidateWindowClassesData(WC_TRAINS_LIST);
01501 InvalidateWindowClassesData(WC_ROADVEH_LIST);
01502 InvalidateWindowClassesData(WC_SHIPS_LIST);
01503 InvalidateWindowClassesData(WC_AIRCRAFT_LIST);
01504 InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY);
01505 InvalidateWindowClassesData(WC_STATION_LIST);
01506
01507 return true;
01508 }
01509
01510
01511
01512 #if !(defined(WIN32) || defined(__APPLE__))
01513
01521 const char *GetCurrentLocale(const char *param)
01522 {
01523 const char *env;
01524
01525 env = getenv("LANGUAGE");
01526 if (env != NULL) return env;
01527
01528 env = getenv("LC_ALL");
01529 if (env != NULL) return env;
01530
01531 if (param != NULL) {
01532 env = getenv(param);
01533 if (env != NULL) return env;
01534 }
01535
01536 return getenv("LANG");
01537 }
01538 #else
01539 const char *GetCurrentLocale(const char *param);
01540 #endif
01541
01542 int CDECL StringIDSorter(const StringID *a, const StringID *b)
01543 {
01544 char stra[512];
01545 char strb[512];
01546 GetString(stra, *a, lastof(stra));
01547 GetString(strb, *b, lastof(strb));
01548
01549 return strcmp(stra, strb);
01550 }
01551
01557 const LanguageMetadata *GetLanguage(byte newgrflangid)
01558 {
01559 for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
01560 if (newgrflangid == lang->newgrflangid) return lang;
01561 }
01562
01563 return NULL;
01564 }
01565
01572 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
01573 {
01574 FILE *f = fopen(file, "rb");
01575 if (f == NULL) return false;
01576
01577 size_t read = fread(hdr, sizeof(*hdr), 1, f);
01578 fclose(f);
01579
01580 bool ret = read == 1 && hdr->IsValid();
01581
01582
01583 if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
01584 return ret;
01585 }
01586
01591 static void GetLanguageList(const char *path)
01592 {
01593 DIR *dir = ttd_opendir(path);
01594 if (dir != NULL) {
01595 struct dirent *dirent;
01596 while ((dirent = readdir(dir)) != NULL) {
01597 const char *d_name = FS2OTTD(dirent->d_name);
01598 const char *extension = strrchr(d_name, '.');
01599
01600
01601 if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
01602
01603 LanguageMetadata lmd;
01604 seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
01605
01606
01607 if (!GetLanguageFileHeader(lmd.file, &lmd)) {
01608 DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
01609 } else if (GetLanguage(lmd.newgrflangid) != NULL) {
01610 DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
01611 } else {
01612 *_languages.Append() = lmd;
01613 }
01614 }
01615 closedir(dir);
01616 }
01617 }
01618
01623 void InitializeLanguagePacks()
01624 {
01625 Searchpath sp;
01626
01627 FOR_ALL_SEARCHPATHS(sp) {
01628 char path[MAX_PATH];
01629 FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
01630 GetLanguageList(path);
01631 }
01632 if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
01633
01634
01635 const char *lang = GetCurrentLocale("LC_MESSAGES");
01636 if (lang == NULL) lang = "en_GB";
01637
01638 const LanguageMetadata *chosen_language = NULL;
01639 const LanguageMetadata *language_fallback = NULL;
01640 const LanguageMetadata *en_GB_fallback = _languages.Begin();
01641
01642
01643 for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
01644
01645
01646
01647 const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
01648 if (strcmp(lang_file, _config_language_file) == 0) {
01649 chosen_language = lng;
01650 break;
01651 }
01652
01653 if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback = lng;
01654 if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng;
01655 if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
01656 }
01657
01658
01659
01660 if (chosen_language == NULL) {
01661 chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
01662 }
01663
01664 if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
01665 }
01666
01671 const char *GetCurrentLanguageIsoCode()
01672 {
01673 return _langpack->isocode;
01674 }
01675
01682 static bool FindMissingGlyphs(const char **str)
01683 {
01684 #ifdef WITH_FREETYPE
01685 UninitFreeType();
01686 InitFreeType();
01687 #endif
01688 const Sprite *question_mark[FS_END];
01689 FontSize size;
01690
01691 for (size = FS_BEGIN; size < FS_END; size++) {
01692 question_mark[size] = GetGlyph(size, '?');
01693 }
01694
01695 for (uint i = 0; i != 32; i++) {
01696 for (uint j = 0; j < _langtab_num[i]; j++) {
01697 size = FS_NORMAL;
01698 const char *text = _langpack_offs[_langtab_start[i] + j];
01699 if (str != NULL) *str = text;
01700 for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
01701 if (c == SCC_SETX) {
01702
01703
01704
01705 text++;
01706 } else if (c == SCC_SETXY) {
01707 text += 2;
01708 } else if (c == SCC_TINYFONT) {
01709 size = FS_SMALL;
01710 } else if (c == SCC_BIGFONT) {
01711 size = FS_LARGE;
01712 } else if (IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
01713
01714 return true;
01715 }
01716 }
01717 }
01718 }
01719 return false;
01720 }
01721
01732 void CheckForMissingGlyphsInLoadedLanguagePack()
01733 {
01734 bool bad_font = FindMissingGlyphs(NULL);
01735 #ifdef WITH_FREETYPE
01736 if (bad_font) {
01737
01738
01739 FreeTypeSettings backup;
01740 memcpy(&backup, &_freetype, sizeof(backup));
01741
01742 bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &FindMissingGlyphs);
01743
01744 memcpy(&_freetype, &backup, sizeof(backup));
01745
01746 if (bad_font) {
01747
01748
01749
01750 UninitFreeType();
01751 InitFreeType();
01752 }
01753 }
01754 #endif
01755
01756 if (bad_font) {
01757
01758
01759
01760
01761
01762 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.");
01763 Utf8Encode(err_str, SCC_YELLOW);
01764 SetDParamStr(0, err_str);
01765 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
01766
01767
01768 LoadStringWidthTable();
01769 return;
01770 }
01771
01772
01773 LoadStringWidthTable();
01774
01775 #if !defined(WITH_ICU)
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789 if (_current_text_dir != TD_LTR) {
01790 static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
01791 Utf8Encode(err_str, SCC_YELLOW);
01792 SetDParamStr(0, err_str);
01793 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
01794 }
01795 #endif
01796 }