OpenTTD
strings.cpp
Go to the documentation of this file.
1 /* $Id: strings.cpp 27381 2015-08-10 20:24:13Z michi_cc $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #include "stdafx.h"
13 #include "currency.h"
14 #include "station_base.h"
15 #include "town.h"
16 #include "waypoint_base.h"
17 #include "depot_base.h"
18 #include "industry.h"
19 #include "newgrf_text.h"
20 #include "fileio_func.h"
21 #include "signs_base.h"
22 #include "fontdetection.h"
23 #include "error.h"
24 #include "strings_func.h"
25 #include "rev.h"
26 #include "core/endian_func.hpp"
27 #include "date_func.h"
28 #include "vehicle_base.h"
29 #include "engine_base.h"
30 #include "language.h"
31 #include "townname_func.h"
32 #include "string_func.h"
33 #include "company_base.h"
34 #include "smallmap_gui.h"
35 #include "window_func.h"
36 #include "debug.h"
37 #include "game/game_text.hpp"
39 #include <stack>
40 
41 #include "table/strings.h"
42 #include "table/control_codes.h"
43 
44 #include "safeguards.h"
45 
46 char _config_language_file[MAX_PATH];
49 
51 
52 #ifdef WITH_ICU_SORT
53 Collator *_current_collator = NULL;
54 #endif /* WITH_ICU_SORT */
55 
56 static uint64 _global_string_params_data[20];
59 
62 {
63  assert(this->type != NULL);
64  MemSetT(this->type, 0, this->num_param);
65 }
66 
67 
73 {
74  if (this->offset >= this->num_param) {
75  DEBUG(misc, 0, "Trying to read invalid string parameter");
76  return 0;
77  }
78  if (this->type != NULL) {
79  assert(this->type[this->offset] == 0 || this->type[this->offset] == type);
80  this->type[this->offset] = type;
81  }
82  return this->data[this->offset++];
83 }
84 
90 {
91  assert(amount <= this->num_param);
92  MemMoveT(this->data + amount, this->data, this->num_param - amount);
93 }
94 
103 void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
104 {
105  uint num_digits = 1;
106  while (max_value >= 10) {
107  num_digits++;
108  max_value /= 10;
109  }
110  SetDParamMaxDigits(n, max(min_count, num_digits), size);
111 }
112 
119 void SetDParamMaxDigits(uint n, uint count, FontSize size)
120 {
121  uint front, next;
122  GetBroadestDigit(&front, &next, size);
123  uint64 val = count > 1 ? front : next;
124  for (; count > 1; count--) {
125  val = 10 * val + next;
126  }
127  SetDParam(n, val);
128 }
129 
136 void CopyInDParam(int offs, const uint64 *src, int num)
137 {
138  MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num);
139 }
140 
147 void CopyOutDParam(uint64 *dst, int offs, int num)
148 {
149  MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num);
150 }
151 
160 void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num)
161 {
162  char buf[DRAW_STRING_BUFFER];
163  GetString(buf, string, lastof(buf));
164 
165  MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num);
166  for (int i = 0; i < num; i++) {
167  if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) {
168  strings[i] = stredup((const char *)(size_t)_global_string_params.GetParam(i));
169  dst[i] = (size_t)strings[i];
170  } else {
171  strings[i] = NULL;
172  }
173  }
174 }
175 
176 static char *StationGetSpecialString(char *buff, int x, const char *last);
177 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
178 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
179 
180 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);
181 
183  char data[]; // list of strings
184 };
185 
186 static char **_langpack_offs;
187 static LanguagePack *_langpack;
188 static uint _langtab_num[TAB_COUNT];
189 static uint _langtab_start[TAB_COUNT];
190 static bool _scan_for_gender_data = false;
191 
192 
193 const char *GetStringPtr(StringID string)
194 {
195  switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
197  /* 0xD0xx and 0xD4xx IDs have been converted earlier. */
198  case 26: NOT_REACHED();
199  case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
200  case 29: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x0800);
201  case 30: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x1000);
202  default: return _langpack_offs[_langtab_start[GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)] + GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)];
203  }
204 }
205 
216 char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
217 {
218  if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
219 
220  uint index = GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS);
221  uint tab = GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS);
222 
223  switch (tab) {
224  case 4:
225  if (index >= 0xC0 && !game_script) {
226  return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
227  }
228  break;
229 
230  case 14:
231  if (index >= 0xE4 && !game_script) {
232  return GetSpecialNameString(buffr, index - 0xE4, args, last);
233  }
234  break;
235 
236  case 15:
237  /* Old table for custom names. This is no longer used */
238  if (!game_script) {
239  error("Incorrect conversion of custom name string.");
240  }
241  break;
242 
243  case GAME_TEXT_TAB:
244  return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
245 
246  case 26:
247  NOT_REACHED();
248 
249  case 28:
250  return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
251 
252  case 29:
253  return FormatString(buffr, GetGRFStringPtr(index + 0x0800), args, last, case_index);
254 
255  case 30:
256  return FormatString(buffr, GetGRFStringPtr(index + 0x1000), args, last, case_index);
257  }
258 
259  if (index >= _langtab_num[tab]) {
260  if (game_script) {
261  return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
262  }
263  error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
264  }
265 
266  return FormatString(buffr, GetStringPtr(string), args, last, case_index);
267 }
268 
269 char *GetString(char *buffr, StringID string, const char *last)
270 {
271  _global_string_params.ClearTypeInformation();
272  _global_string_params.offset = 0;
273  return GetStringWithArgs(buffr, string, &_global_string_params, last);
274 }
275 
276 
282 void SetDParamStr(uint n, const char *str)
283 {
284  SetDParam(n, (uint64)(size_t)str);
285 }
286 
291 void InjectDParam(uint amount)
292 {
293  _global_string_params.ShiftParameters(amount);
294 }
295 
307 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0)
308 {
309  static const int max_digits = 20;
310  uint64 divisor = 10000000000000000000ULL;
311  zerofill += fractional_digits;
312  int thousands_offset = (max_digits - fractional_digits - 1) % 3;
313 
314  if (number < 0) {
315  buff += seprintf(buff, last, "-");
316  number = -number;
317  }
318 
319  uint64 num = number;
320  uint64 tot = 0;
321  for (int i = 0; i < max_digits; i++) {
322  if (i == max_digits - fractional_digits) {
323  const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
324  if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
325  buff += seprintf(buff, last, "%s", decimal_separator);
326  }
327 
328  uint64 quot = 0;
329  if (num >= divisor) {
330  quot = num / divisor;
331  num = num % divisor;
332  }
333  if ((tot |= quot) || i >= max_digits - zerofill) {
334  buff += seprintf(buff, last, "%i", (int)quot);
335  if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last);
336  }
337 
338  divisor /= 10;
339  }
340 
341  *buff = '\0';
342 
343  return buff;
344 }
345 
346 static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
347 {
348  const char *separator = _settings_game.locale.digit_group_separator;
349  if (separator == NULL) separator = _langpack->digit_group_separator;
350  return FormatNumber(buff, number, last, separator, 1, fractional_digits);
351 }
352 
353 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
354 {
355  return FormatNumber(buff, number, last, "");
356 }
357 
358 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
359 {
360  return FormatNumber(buff, number, last, "", count);
361 }
362 
363 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
364 {
365  return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
366 }
367 
375 static char *FormatBytes(char *buff, int64 number, const char *last)
376 {
377  assert(number >= 0);
378 
379  /* 1 2^10 2^20 2^30 2^40 2^50 2^60 */
380  const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
381  uint id = 1;
382  while (number >= 1024 * 1024) {
383  number /= 1024;
384  id++;
385  }
386 
387  const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
388  if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
389 
390  if (number < 1024) {
391  id = 0;
392  buff += seprintf(buff, last, "%i", (int)number);
393  } else if (number < 1024 * 10) {
394  buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
395  } else if (number < 1024 * 100) {
396  buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
397  } else {
398  assert(number < 1024 * 1024);
399  buff += seprintf(buff, last, "%i", (int)number / 1024);
400  }
401 
402  assert(id < lengthof(iec_prefixes));
403  buff += seprintf(buff, last, NBSP "%sB", iec_prefixes[id]);
404 
405  return buff;
406 }
407 
408 static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index)
409 {
410  YearMonthDay ymd;
411  ConvertDateToYMD(date, &ymd);
412 
413  int64 args[] = {ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
414  StringParameters tmp_params(args);
415  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
416 }
417 
418 static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index)
419 {
420  YearMonthDay ymd;
421  ConvertDateToYMD(date, &ymd);
422 
423  int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
424  StringParameters tmp_params(args);
425  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
426 }
427 
428 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
429 {
430  YearMonthDay ymd;
431  ConvertDateToYMD(date, &ymd);
432 
433  char day[3];
434  char month[3];
435  /* We want to zero-pad the days and months */
436  seprintf(day, lastof(day), "%02i", ymd.day);
437  seprintf(month, lastof(month), "%02i", ymd.month + 1);
438 
439  int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year};
440  StringParameters tmp_params(args);
441  return FormatString(buff, GetStringPtr(str), &tmp_params, last);
442 }
443 
444 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
445 {
446  /* We are going to make number absolute for printing, so
447  * keep this piece of data as we need it later on */
448  bool negative = number < 0;
449  const char *multiplier = "";
450 
451  number *= spec->rate;
452 
453  /* convert from negative */
454  if (number < 0) {
455  if (buff + Utf8CharLen(SCC_RED) > last) return buff;
456  buff += Utf8Encode(buff, SCC_RED);
457  buff = strecpy(buff, "-", last);
458  number = -number;
459  }
460 
461  /* Add prefix part, following symbol_pos specification.
462  * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
463  * The only remaining value is 1 (suffix), so everything that is not 1 */
464  if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
465 
466  /* for huge numbers, compact the number into k or M */
467  if (compact) {
468  /* Take care of the 'k' rounding. Having 1 000 000 k
469  * and 1 000 M is inconsistent, so always use 1 000 M. */
470  if (number >= 1000000000 - 500) {
471  number = (number + 500000) / 1000000;
472  multiplier = NBSP "M";
473  } else if (number >= 1000000) {
474  number = (number + 500) / 1000;
475  multiplier = NBSP "k";
476  }
477  }
478 
479  const char *separator = _settings_game.locale.digit_group_separator_currency;
480  if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
481  if (separator == NULL) separator = _langpack->digit_group_separator_currency;
482  buff = FormatNumber(buff, number, last, separator);
483  buff = strecpy(buff, multiplier, last);
484 
485  /* Add suffix part, following symbol_pos specification.
486  * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
487  * The only remaining value is 1 (prefix), so everything that is not 0 */
488  if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
489 
490  if (negative) {
491  if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
492  buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
493  *buff = '\0';
494  }
495 
496  return buff;
497 }
498 
505 static int DeterminePluralForm(int64 count, int plural_form)
506 {
507  /* The absolute value determines plurality */
508  uint64 n = abs(count);
509 
510  switch (plural_form) {
511  default:
512  NOT_REACHED();
513 
514  /* Two forms: singular used for one only.
515  * Used in:
516  * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
517  * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
518  case 0:
519  return n != 1 ? 1 : 0;
520 
521  /* Only one form.
522  * Used in:
523  * Hungarian, Japanese, Korean, Turkish */
524  case 1:
525  return 0;
526 
527  /* Two forms: singular used for 0 and 1.
528  * Used in:
529  * French, Brazilian Portuguese */
530  case 2:
531  return n > 1 ? 1 : 0;
532 
533  /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
534  * Note: Cases are out of order for hysterical reasons. '0' is last.
535  * Used in:
536  * Latvian */
537  case 3:
538  return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
539 
540  /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
541  * Used in:
542  * Gaelige (Irish) */
543  case 4:
544  return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
545 
546  /* 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.
547  * Used in:
548  * Lithuanian */
549  case 5:
550  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
551 
552  /* 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.
553  * Used in:
554  * Croatian, Russian, Ukrainian */
555  case 6:
556  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
557 
558  /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
559  * Used in:
560  * Polish */
561  case 7:
562  return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
563 
564  /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
565  * Used in:
566  * Slovenian */
567  case 8:
568  return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
569 
570  /* Two forms: singular used for numbers ending in 1 except when ending in 11.
571  * Used in:
572  * Icelandic */
573  case 9:
574  return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
575 
576  /* Three forms: special cases for 1, and 2 to 4
577  * Used in:
578  * Czech, Slovak */
579  case 10:
580  return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
581 
582  /* Two forms: cases for numbers ending with a consonant, and with a vowel.
583  * Korean doesn't have the concept of plural, but depending on how a
584  * number is pronounced it needs another version of a particle.
585  * As such the plural system is misused to give this distinction.
586  */
587  case 11:
588  switch (n % 10) {
589  case 0: // yeong
590  case 1: // il
591  case 3: // sam
592  case 6: // yuk
593  case 7: // chil
594  case 8: // pal
595  return 0;
596 
597  case 2: // i
598  case 4: // sa
599  case 5: // o
600  case 9: // gu
601  return 1;
602 
603  default:
604  NOT_REACHED();
605  }
606 
607  /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
608  * Used in:
609  * Maltese */
610  case 12:
611  return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
612  /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
613  * Used in:
614  * Scottish Gaelic */
615  case 13:
616  return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
617  }
618 }
619 
620 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
621 {
622  /* <NUM> {Length of each string} {each string} */
623  uint n = (byte)*b++;
624  uint pos, i, mypos = 0;
625 
626  for (i = pos = 0; i != n; i++) {
627  uint len = (byte)*b++;
628  if (i == form) mypos = pos;
629  pos += len;
630  }
631 
632  *dst += seprintf(*dst, last, "%s", b + mypos);
633  return b + pos;
634 }
635 
639  int shift;
640 
647  int64 ToDisplay(int64 input, bool round = true) const
648  {
649  return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
650  }
651 
659  int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
660  {
661  return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
662  }
663 };
664 
666 struct Units {
669 };
670 
672 struct UnitsLong {
676 };
677 
679 static const Units _units_velocity[] = {
680  { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
681  { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
682  { {1831, 12}, STR_UNITS_VELOCITY_SI },
683 };
684 
686 static const Units _units_power[] = {
687  { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
688  { {4153, 12}, STR_UNITS_POWER_METRIC },
689  { {6109, 13}, STR_UNITS_POWER_SI },
690 };
691 
693 static const UnitsLong _units_weight[] = {
694  { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
695  { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
696  { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
697 };
698 
700 static const UnitsLong _units_volume[] = {
701  { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
702  { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
703  { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
704 };
705 
707 static const Units _units_force[] = {
708  { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
709  { {3263, 5}, STR_UNITS_FORCE_METRIC },
710  { { 1, 0}, STR_UNITS_FORCE_SI },
711 };
712 
714 static const Units _units_height[] = {
715  { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL }, // "Wrong" conversion factor for more nicer GUI values
716  { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
717  { { 1, 0}, STR_UNITS_HEIGHT_SI },
718 };
719 
726 {
727  /* For historical reasons we don't want to mess with the
728  * conversion for speed. So, don't round it and keep the
729  * original conversion factors instead of the real ones. */
730  return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed, false);
731 }
732 
739 {
740  return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed);
741 }
742 
749 {
750  return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16;
751 }
752 
759 {
760  return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10);
761 }
771 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
772 {
773  uint orig_offset = args->offset;
774 
775  /* When there is no array with types there is no need to do a dry run. */
776  if (args->HasTypeInformation() && !dry_run) {
777  if (UsingNewGRFTextStack()) {
778  /* Values from the NewGRF text stack are only copied to the normal
779  * argv array at the time they are encountered. That means that if
780  * another string command references a value later in the string it
781  * would fail. We solve that by running FormatString twice. The first
782  * pass makes sure the argv array is correctly filled and the second
783  * pass can reference later values without problems. */
784  struct TextRefStack *backup = CreateTextRefStackBackup();
785  FormatString(buff, str_arg, args, last, case_index, game_script, true);
787  } else {
788  FormatString(buff, str_arg, args, last, case_index, game_script, true);
789  }
790  /* We have to restore the original offset here to to read the correct values. */
791  args->offset = orig_offset;
792  }
793  WChar b = '\0';
794  uint next_substr_case_index = 0;
795  char *buf_start = buff;
796  std::stack<const char *> str_stack;
797  str_stack.push(str_arg);
798 
799  for (;;) {
800  while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
801  str_stack.pop();
802  }
803  if (str_stack.empty()) break;
804  const char *&str = str_stack.top();
805 
806  if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
807  /* We need to pass some stuff as it might be modified; oh boy. */
808  //todo: should argve be passed here too?
809  b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), args->GetDataLeft(), dry_run);
810  if (b == 0) continue;
811  }
812 
813  switch (b) {
814  case SCC_ENCODED: {
815  uint64 sub_args_data[20];
816  WChar sub_args_type[20];
817  bool sub_args_need_free[20];
818  StringParameters sub_args(sub_args_data, 20, sub_args_type);
819 
820  sub_args.ClearTypeInformation();
821  memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
822 
823  uint16 stringid;
824  const char *s = str;
825  char *p;
826  stringid = strtol(str, &p, 16);
827  if (*p != ':' && *p != '\0') {
828  while (*p != '\0') p++;
829  str = p;
830  buff = strecat(buff, "(invalid SCC_ENCODED)", last);
831  break;
832  }
833  if (stringid >= TAB_SIZE) {
834  while (*p != '\0') p++;
835  str = p;
836  buff = strecat(buff, "(invalid StringID)", last);
837  break;
838  }
839 
840  int i = 0;
841  while (*p != '\0' && i < 20) {
842  uint64 param;
843  s = ++p;
844 
845  /* Find the next value */
846  bool instring = false;
847  bool escape = false;
848  for (;; p++) {
849  if (*p == '\\') {
850  escape = true;
851  continue;
852  }
853  if (*p == '"' && escape) {
854  escape = false;
855  continue;
856  }
857  escape = false;
858 
859  if (*p == '"') {
860  instring = !instring;
861  continue;
862  }
863  if (instring) {
864  continue;
865  }
866 
867  if (*p == ':') break;
868  if (*p == '\0') break;
869  }
870 
871  if (*s != '"') {
872  /* Check if we want to look up another string */
873  WChar l;
874  size_t len = Utf8Decode(&l, s);
875  bool lookup = (l == SCC_ENCODED);
876  if (lookup) s += len;
877 
878  param = strtoull(s, &p, 16);
879 
880  if (lookup) {
881  if (param >= TAB_SIZE) {
882  while (*p != '\0') p++;
883  str = p;
884  buff = strecat(buff, "(invalid sub-StringID)", last);
885  break;
886  }
887  param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param;
888  }
889 
890  sub_args.SetParam(i++, param);
891  } else {
892  char *g = stredup(s);
893  g[p - s] = '\0';
894 
895  sub_args_need_free[i] = true;
896  sub_args.SetParam(i++, (uint64)(size_t)g);
897  }
898  }
899  /* If we didn't error out, we can actually print the string. */
900  if (*str != '\0') {
901  str = p;
902  buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
903  }
904 
905  for (int i = 0; i < 20; i++) {
906  if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
907  }
908  break;
909  }
910 
911  case SCC_NEWGRF_STRINL: {
912  StringID substr = Utf8Consume(&str);
913  str_stack.push(GetStringPtr(substr));
914  break;
915  }
916 
919  str_stack.push(GetStringPtr(substr));
920  case_index = next_substr_case_index;
921  next_substr_case_index = 0;
922  break;
923  }
924 
925 
926  case SCC_GENDER_LIST: { // {G 0 Der Die Das}
927  /* First read the meta data from the language file. */
928  uint offset = orig_offset + (byte)*str++;
929  int gender = 0;
930  if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
931  /* Now we need to figure out what text to resolve, i.e.
932  * what do we need to draw? So get the actual raw string
933  * first using the control code to get said string. */
934  char input[4 + 1];
935  char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
936  *p = '\0';
937 
938  /* Now do the string formatting. */
939  char buf[256];
940  bool old_sgd = _scan_for_gender_data;
941  _scan_for_gender_data = true;
942  StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
943  p = FormatString(buf, input, &tmp_params, lastof(buf));
944  _scan_for_gender_data = old_sgd;
945  *p = '\0';
946 
947  /* And determine the string. */
948  const char *s = buf;
949  WChar c = Utf8Consume(&s);
950  /* Does this string have a gender, if so, set it */
951  if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
952  }
953  str = ParseStringChoice(str, gender, &buff, last);
954  break;
955  }
956 
957  /* This sets up the gender for the string.
958  * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
959  case SCC_GENDER_INDEX: // {GENDER 0}
960  if (_scan_for_gender_data) {
961  buff += Utf8Encode(buff, SCC_GENDER_INDEX);
962  *buff++ = *str++;
963  } else {
964  str++;
965  }
966  break;
967 
968  case SCC_PLURAL_LIST: { // {P}
969  int plural_form = *str++; // contains the plural form for this string
970  uint offset = orig_offset + (byte)*str++;
971  int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
972  str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
973  break;
974  }
975 
976  case SCC_ARG_INDEX: { // Move argument pointer
977  args->offset = orig_offset + (byte)*str++;
978  break;
979  }
980 
981  case SCC_SET_CASE: { // {SET_CASE}
982  /* This is a pseudo command, it's outputted when someone does {STRING.ack}
983  * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
984  next_substr_case_index = (byte)*str++;
985  break;
986  }
987 
988  case SCC_SWITCH_CASE: { // {Used to implement case switching}
989  /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
990  * Each LEN is printed using 2 bytes in big endian order. */
991  uint num = (byte)*str++;
992  while (num) {
993  if ((byte)str[0] == case_index) {
994  /* Found the case, adjust str pointer and continue */
995  str += 3;
996  break;
997  }
998  /* Otherwise skip to the next case */
999  str += 3 + (str[1] << 8) + str[2];
1000  num--;
1001  }
1002  break;
1003  }
1004 
1005  case SCC_REVISION: // {REV}
1006  buff = strecpy(buff, _openttd_revision, last);
1007  break;
1008 
1009  case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
1010  if (game_script) break;
1011  const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
1012  buff = FormatString(buff, str, args, last);
1013  break;
1014  }
1015 
1016  case SCC_STRING: {// {STRING}
1017  StringID str = args->GetInt32(SCC_STRING);
1018  if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
1019  /* WARNING. It's prohibited for the included string to consume any arguments.
1020  * For included strings that consume argument, you should use STRING1, STRING2 etc.
1021  * To debug stuff you can set argv to NULL and it will tell you */
1022  StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), NULL);
1023  buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1024  next_substr_case_index = 0;
1025  break;
1026  }
1027 
1028  case SCC_STRING1:
1029  case SCC_STRING2:
1030  case SCC_STRING3:
1031  case SCC_STRING4:
1032  case SCC_STRING5:
1033  case SCC_STRING6:
1034  case SCC_STRING7: { // {STRING1..7}
1035  /* Strings that consume arguments */
1036  StringID str = args->GetInt32(b);
1037  if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
1038  uint size = b - SCC_STRING1 + 1;
1039  if (game_script && size > args->GetDataLeft()) {
1040  buff = strecat(buff, "(too many parameters)", last);
1041  } else {
1042  StringParameters sub_args(*args, size);
1043  buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1044  }
1045  next_substr_case_index = 0;
1046  break;
1047  }
1048 
1049  case SCC_COMMA: // {COMMA}
1050  buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
1051  break;
1052 
1053  case SCC_DECIMAL: {// {DECIMAL}
1054  int64 number = args->GetInt64(SCC_DECIMAL);
1055  int digits = args->GetInt32(SCC_DECIMAL);
1056  buff = FormatCommaNumber(buff, number, last, digits);
1057  break;
1058  }
1059 
1060  case SCC_NUM: // {NUM}
1061  buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
1062  break;
1063 
1064  case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
1065  int64 num = args->GetInt64();
1066  buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
1067  break;
1068  }
1069 
1070  case SCC_HEX: // {HEX}
1071  buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
1072  break;
1073 
1074  case SCC_BYTES: // {BYTES}
1075  buff = FormatBytes(buff, args->GetInt64(), last);
1076  break;
1077 
1078  case SCC_CARGO_TINY: { // {CARGO_TINY}
1079  /* Tiny description of cargotypes. Layout:
1080  * param 1: cargo type
1081  * param 2: cargo count */
1082  CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
1083  if (cargo >= CargoSpec::GetArraySize()) break;
1084 
1085  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1086  int64 amount = 0;
1087  switch (cargo_str) {
1088  case STR_TONS:
1089  amount = _units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64());
1090  break;
1091 
1092  case STR_LITERS:
1093  amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64());
1094  break;
1095 
1096  default: {
1097  amount = args->GetInt64();
1098  break;
1099  }
1100  }
1101 
1102  buff = FormatCommaNumber(buff, amount, last);
1103  break;
1104  }
1105 
1106  case SCC_CARGO_SHORT: { // {CARGO_SHORT}
1107  /* Short description of cargotypes. Layout:
1108  * param 1: cargo type
1109  * param 2: cargo count */
1110  CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
1111  if (cargo >= CargoSpec::GetArraySize()) break;
1112 
1113  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1114  switch (cargo_str) {
1115  case STR_TONS: {
1116  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1117  int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1118  StringParameters tmp_params(args_array);
1119  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1120  break;
1121  }
1122 
1123  case STR_LITERS: {
1124  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1125  int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1126  StringParameters tmp_params(args_array);
1127  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1128  break;
1129  }
1130 
1131  default: {
1132  StringParameters tmp_params(*args, 1);
1133  buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
1134  break;
1135  }
1136  }
1137  break;
1138  }
1139 
1140  case SCC_CARGO_LONG: { // {CARGO_LONG}
1141  /* First parameter is cargo type, second parameter is cargo count */
1142  CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
1143  if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
1144 
1145  StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
1146  StringParameters tmp_args(*args, 1);
1147  buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
1148  break;
1149  }
1150 
1151  case SCC_CARGO_LIST: { // {CARGO_LIST}
1152  uint32 cmask = args->GetInt32(SCC_CARGO_LIST);
1153  bool first = true;
1154 
1155  const CargoSpec *cs;
1157  if (!HasBit(cmask, cs->Index())) continue;
1158 
1159  if (buff >= last - 2) break; // ',' and ' '
1160 
1161  if (first) {
1162  first = false;
1163  } else {
1164  /* Add a comma if this is not the first item */
1165  *buff++ = ',';
1166  *buff++ = ' ';
1167  }
1168 
1169  buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
1170  }
1171 
1172  /* If first is still true then no cargo is accepted */
1173  if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1174 
1175  *buff = '\0';
1176  next_substr_case_index = 0;
1177 
1178  /* Make sure we detect any buffer overflow */
1179  assert(buff < last);
1180  break;
1181  }
1182 
1183  case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
1184  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
1185  break;
1186 
1187  case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
1188  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
1189  break;
1190 
1191  case SCC_DATE_TINY: // {DATE_TINY}
1192  buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1193  break;
1194 
1195  case SCC_DATE_SHORT: // {DATE_SHORT}
1196  buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1197  next_substr_case_index = 0;
1198  break;
1199 
1200  case SCC_DATE_LONG: // {DATE_LONG}
1201  buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1202  next_substr_case_index = 0;
1203  break;
1204 
1205  case SCC_DATE_ISO: // {DATE_ISO}
1206  buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
1207  break;
1208 
1209  case SCC_FORCE: { // {FORCE}
1210  assert(_settings_game.locale.units_force < lengthof(_units_force));
1211  int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())};
1212  StringParameters tmp_params(args_array);
1213  buff = FormatString(buff, GetStringPtr(_units_force[_settings_game.locale.units_force].s), &tmp_params, last);
1214  break;
1215  }
1216 
1217  case SCC_HEIGHT: { // {HEIGHT}
1218  assert(_settings_game.locale.units_height < lengthof(_units_height));
1219  int64 args_array[] = {_units_height[_settings_game.locale.units_height].c.ToDisplay(args->GetInt64())};
1220  StringParameters tmp_params(args_array);
1221  buff = FormatString(buff, GetStringPtr(_units_height[_settings_game.locale.units_height].s), &tmp_params, last);
1222  break;
1223  }
1224 
1225  case SCC_POWER: { // {POWER}
1226  assert(_settings_game.locale.units_power < lengthof(_units_power));
1227  int64 args_array[1] = {_units_power[_settings_game.locale.units_power].c.ToDisplay(args->GetInt64())};
1228  StringParameters tmp_params(args_array);
1229  buff = FormatString(buff, GetStringPtr(_units_power[_settings_game.locale.units_power].s), &tmp_params, last);
1230  break;
1231  }
1232 
1233  case SCC_VELOCITY: { // {VELOCITY}
1234  assert(_settings_game.locale.units_velocity < lengthof(_units_velocity));
1235  int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
1236  StringParameters tmp_params(args_array);
1237  buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last);
1238  break;
1239  }
1240 
1241  case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
1242  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1243  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1244  StringParameters tmp_params(args_array);
1245  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].s), &tmp_params, last);
1246  break;
1247  }
1248 
1249  case SCC_VOLUME_LONG: { // {VOLUME_LONG}
1250  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1251  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
1252  StringParameters tmp_params(args_array);
1253  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1254  break;
1255  }
1256 
1257  case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
1258  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1259  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1260  StringParameters tmp_params(args_array);
1261  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].s), &tmp_params, last);
1262  break;
1263  }
1264 
1265  case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
1266  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1267  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
1268  StringParameters tmp_params(args_array);
1269  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1270  break;
1271  }
1272 
1273  case SCC_COMPANY_NAME: { // {COMPANY}
1274  const Company *c = Company::GetIfValid(args->GetInt32());
1275  if (c == NULL) break;
1276 
1277  if (c->name != NULL) {
1278  int64 args_array[] = {(int64)(size_t)c->name};
1279  StringParameters tmp_params(args_array);
1280  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1281  } else {
1282  int64 args_array[] = {c->name_2};
1283  StringParameters tmp_params(args_array);
1284  buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
1285  }
1286  break;
1287  }
1288 
1289  case SCC_COMPANY_NUM: { // {COMPANY_NUM}
1290  CompanyID company = (CompanyID)args->GetInt32();
1291 
1292  /* Nothing is added for AI or inactive companies */
1293  if (Company::IsValidHumanID(company)) {
1294  int64 args_array[] = {company + 1};
1295  StringParameters tmp_params(args_array);
1296  buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
1297  }
1298  break;
1299  }
1300 
1301  case SCC_DEPOT_NAME: { // {DEPOT}
1302  VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
1303  if (vt == VEH_AIRCRAFT) {
1304  uint64 args_array[] = {(uint64)args->GetInt32()};
1305  WChar types_array[] = {SCC_STATION_NAME};
1306  StringParameters tmp_params(args_array, 1, types_array);
1307  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1308  break;
1309  }
1310 
1311  const Depot *d = Depot::Get(args->GetInt32());
1312  if (d->name != NULL) {
1313  int64 args_array[] = {(int64)(size_t)d->name};
1314  StringParameters tmp_params(args_array);
1315  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1316  } else {
1317  int64 args_array[] = {d->town->index, d->town_cn + 1};
1318  StringParameters tmp_params(args_array);
1319  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
1320  }
1321  break;
1322  }
1323 
1324  case SCC_ENGINE_NAME: { // {ENGINE}
1325  const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
1326  if (e == NULL) break;
1327 
1328  if (e->name != NULL && e->IsEnabled()) {
1329  int64 args_array[] = {(int64)(size_t)e->name};
1330  StringParameters tmp_params(args_array);
1331  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1332  } else {
1333  StringParameters tmp_params(NULL, 0, NULL);
1334  buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
1335  }
1336  break;
1337  }
1338 
1339  case SCC_GROUP_NAME: { // {GROUP}
1340  const Group *g = Group::GetIfValid(args->GetInt32());
1341  if (g == NULL) break;
1342 
1343  if (g->name != NULL) {
1344  int64 args_array[] = {(int64)(size_t)g->name};
1345  StringParameters tmp_params(args_array);
1346  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1347  } else {
1348  int64 args_array[] = {g->index};
1349  StringParameters tmp_params(args_array);
1350 
1351  buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
1352  }
1353  break;
1354  }
1355 
1356  case SCC_INDUSTRY_NAME: { // {INDUSTRY}
1357  const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
1358  if (i == NULL) break;
1359 
1360  if (_scan_for_gender_data) {
1361  /* Gender is defined by the industry type.
1362  * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
1363  StringParameters tmp_params(NULL, 0, NULL);
1364  buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
1365  } else {
1366  /* First print the town name and the industry type name. */
1367  int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
1368  StringParameters tmp_params(args_array);
1369 
1370  buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1371  }
1372  next_substr_case_index = 0;
1373  break;
1374  }
1375 
1376  case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
1377  const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
1378  if (c == NULL) break;
1379 
1380  if (c->president_name != NULL) {
1381  int64 args_array[] = {(int64)(size_t)c->president_name};
1382  StringParameters tmp_params(args_array);
1383  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1384  } else {
1385  int64 args_array[] = {c->president_name_2};
1386  StringParameters tmp_params(args_array);
1387  buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
1388  }
1389  break;
1390  }
1391 
1392  case SCC_STATION_NAME: { // {STATION}
1393  StationID sid = args->GetInt32(SCC_STATION_NAME);
1394  const Station *st = Station::GetIfValid(sid);
1395 
1396  if (st == NULL) {
1397  /* The station doesn't exist anymore. The only place where we might
1398  * be "drawing" an invalid station is in the case of cargo that is
1399  * in transit. */
1400  StringParameters tmp_params(NULL, 0, NULL);
1401  buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
1402  break;
1403  }
1404 
1405  if (st->name != NULL) {
1406  int64 args_array[] = {(int64)(size_t)st->name};
1407  StringParameters tmp_params(args_array);
1408  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1409  } else {
1410  StringID str = st->string_id;
1411  if (st->indtype != IT_INVALID) {
1412  /* Special case where the industry provides the name for the station */
1413  const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
1414 
1415  /* Industry GRFs can change which might remove the station name and
1416  * thus cause very strange things. Here we check for that before we
1417  * actually set the station name. */
1418  if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
1419  str = indsp->station_name;
1420  }
1421  }
1422 
1423  int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
1424  StringParameters tmp_params(args_array);
1425  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1426  }
1427  break;
1428  }
1429 
1430  case SCC_TOWN_NAME: { // {TOWN}
1431  const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
1432  if (t == NULL) break;
1433 
1434  if (t->name != NULL) {
1435  int64 args_array[] = {(int64)(size_t)t->name};
1436  StringParameters tmp_params(args_array);
1437  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1438  } else {
1439  buff = GetTownName(buff, t, last);
1440  }
1441  break;
1442  }
1443 
1444  case SCC_WAYPOINT_NAME: { // {WAYPOINT}
1445  Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
1446  if (wp == NULL) break;
1447 
1448  if (wp->name != NULL) {
1449  int64 args_array[] = {(int64)(size_t)wp->name};
1450  StringParameters tmp_params(args_array);
1451  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1452  } else {
1453  int64 args_array[] = {wp->town->index, wp->town_cn + 1};
1454  StringParameters tmp_params(args_array);
1455  StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1456  if (wp->town_cn != 0) str++;
1457  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1458  }
1459  break;
1460  }
1461 
1462  case SCC_VEHICLE_NAME: { // {VEHICLE}
1463  const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
1464  if (v == NULL) break;
1465 
1466  if (v->name != NULL) {
1467  int64 args_array[] = {(int64)(size_t)v->name};
1468  StringParameters tmp_params(args_array);
1469  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1470  } else {
1471  int64 args_array[] = {v->unitnumber};
1472  StringParameters tmp_params(args_array);
1473 
1474  StringID str;
1475  switch (v->type) {
1476  default: str = STR_INVALID_VEHICLE; break;
1477  case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break;
1478  case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME; break;
1479  case VEH_SHIP: str = STR_SV_SHIP_NAME; break;
1480  case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
1481  }
1482 
1483  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1484  }
1485  break;
1486  }
1487 
1488  case SCC_SIGN_NAME: { // {SIGN}
1489  const Sign *si = Sign::GetIfValid(args->GetInt32());
1490  if (si == NULL) break;
1491 
1492  if (si->name != NULL) {
1493  int64 args_array[] = {(int64)(size_t)si->name};
1494  StringParameters tmp_params(args_array);
1495  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1496  } else {
1497  StringParameters tmp_params(NULL, 0, NULL);
1498  buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
1499  }
1500  break;
1501  }
1502 
1503  case SCC_STATION_FEATURES: { // {STATIONFEATURES}
1504  buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
1505  break;
1506  }
1507 
1508  default:
1509  if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
1510  break;
1511  }
1512  }
1513  *buff = '\0';
1514  return buff;
1515 }
1516 
1517 
1518 static char *StationGetSpecialString(char *buff, int x, const char *last)
1519 {
1520  if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
1521  if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
1522  if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
1523  if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
1524  if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
1525  *buff = '\0';
1526  return buff;
1527 }
1528 
1529 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
1530 {
1531  return GenerateTownNameString(buff, last, ind, seed);
1532 }
1533 
1534 static const char * const _silly_company_names[] = {
1535  "Bloggs Brothers",
1536  "Tiny Transport Ltd.",
1537  "Express Travel",
1538  "Comfy-Coach & Co.",
1539  "Crush & Bump Ltd.",
1540  "Broken & Late Ltd.",
1541  "Sam Speedy & Son",
1542  "Supersonic Travel",
1543  "Mike's Motors",
1544  "Lightning International",
1545  "Pannik & Loozit Ltd.",
1546  "Inter-City Transport",
1547  "Getout & Pushit Ltd."
1548 };
1549 
1550 static const char * const _surname_list[] = {
1551  "Adams",
1552  "Allan",
1553  "Baker",
1554  "Bigwig",
1555  "Black",
1556  "Bloggs",
1557  "Brown",
1558  "Campbell",
1559  "Gordon",
1560  "Hamilton",
1561  "Hawthorn",
1562  "Higgins",
1563  "Green",
1564  "Gribble",
1565  "Jones",
1566  "McAlpine",
1567  "MacDonald",
1568  "McIntosh",
1569  "Muir",
1570  "Murphy",
1571  "Nelson",
1572  "O'Donnell",
1573  "Parker",
1574  "Phillips",
1575  "Pilkington",
1576  "Quigley",
1577  "Sharkey",
1578  "Thomson",
1579  "Watkins"
1580 };
1581 
1582 static const char * const _silly_surname_list[] = {
1583  "Grumpy",
1584  "Dozy",
1585  "Speedy",
1586  "Nosey",
1587  "Dribble",
1588  "Mushroom",
1589  "Cabbage",
1590  "Sniffle",
1591  "Fishy",
1592  "Swindle",
1593  "Sneaky",
1594  "Nutkins"
1595 };
1596 
1597 static const char _initial_name_letters[] = {
1598  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
1599  'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
1600 };
1601 
1602 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
1603 {
1604  const char * const *base;
1605  uint num;
1606 
1607  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1608  base = _silly_surname_list;
1609  num = lengthof(_silly_surname_list);
1610  } else {
1611  base = _surname_list;
1612  num = lengthof(_surname_list);
1613  }
1614 
1615  buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
1616  buff = strecpy(buff, " & Co.", last);
1617 
1618  return buff;
1619 }
1620 
1621 static char *GenPresidentName(char *buff, uint32 x, const char *last)
1622 {
1623  char initial[] = "?. ";
1624  const char * const *base;
1625  uint num;
1626  uint i;
1627 
1628  initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
1629  buff = strecpy(buff, initial, last);
1630 
1631  i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
1632  if (i < sizeof(_initial_name_letters)) {
1633  initial[0] = _initial_name_letters[i];
1634  buff = strecpy(buff, initial, last);
1635  }
1636 
1637  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1638  base = _silly_surname_list;
1639  num = lengthof(_silly_surname_list);
1640  } else {
1641  base = _surname_list;
1642  num = lengthof(_surname_list);
1643  }
1644 
1645  buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
1646 
1647  return buff;
1648 }
1649 
1650 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
1651 {
1652  switch (ind) {
1653  case 1: // not used
1654  return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
1655 
1656  case 2: // used for Foobar & Co company names
1657  return GenAndCoName(buff, args->GetInt32(), last);
1658 
1659  case 3: // President name
1660  return GenPresidentName(buff, args->GetInt32(), last);
1661  }
1662 
1663  /* town name? */
1664  if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1665  buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
1666  return strecpy(buff, " Transport", last);
1667  }
1668 
1669  /* language name? */
1670  if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1671  int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1672  return strecpy(buff,
1673  &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
1674  }
1675 
1676  /* resolution size? */
1677  if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
1678  int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1679  buff += seprintf(
1680  buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
1681  );
1682  return buff;
1683  }
1684 
1685  NOT_REACHED();
1686 }
1687 
1688 #ifdef ENABLE_NETWORK
1689 extern void SortNetworkLanguages();
1690 #else /* ENABLE_NETWORK */
1691 static inline void SortNetworkLanguages() {}
1692 #endif /* ENABLE_NETWORK */
1693 
1699 {
1700  return this->ident == TO_LE32(LanguagePackHeader::IDENT) &&
1701  this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1702  this->plural_form < LANGUAGE_MAX_PLURAL &&
1703  this->text_dir <= 1 &&
1704  this->newgrflangid < MAX_LANG &&
1705  this->num_genders < MAX_NUM_GENDERS &&
1706  this->num_cases < MAX_NUM_CASES &&
1707  StrValid(this->name, lastof(this->name)) &&
1708  StrValid(this->own_name, lastof(this->own_name)) &&
1709  StrValid(this->isocode, lastof(this->isocode)) &&
1713 }
1714 
1721 {
1722  /* Current language pack */
1723  size_t len;
1724  LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
1725  if (lang_pack == NULL) return false;
1726 
1727  /* End of read data (+ terminating zero added in ReadFileToMem()) */
1728  const char *end = (char *)lang_pack + len + 1;
1729 
1730  /* We need at least one byte of lang_pack->data */
1731  if (end <= lang_pack->data || !lang_pack->IsValid()) {
1732  free(lang_pack);
1733  return false;
1734  }
1735 
1736 #if TTD_ENDIAN == TTD_BIG_ENDIAN
1737  for (uint i = 0; i < TAB_COUNT; i++) {
1738  lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
1739  }
1740 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
1741 
1742  uint count = 0;
1743  for (uint i = 0; i < TAB_COUNT; i++) {
1744  uint16 num = lang_pack->offsets[i];
1745  if (num > TAB_SIZE) {
1746  free(lang_pack);
1747  return false;
1748  }
1749 
1750  _langtab_start[i] = count;
1751  _langtab_num[i] = num;
1752  count += num;
1753  }
1754 
1755  /* Allocate offsets */
1756  char **langpack_offs = MallocT<char *>(count);
1757 
1758  /* Fill offsets */
1759  char *s = lang_pack->data;
1760  len = (byte)*s++;
1761  for (uint i = 0; i < count; i++) {
1762  if (s + len >= end) {
1763  free(lang_pack);
1764  free(langpack_offs);
1765  return false;
1766  }
1767  if (len >= 0xC0) {
1768  len = ((len & 0x3F) << 8) + (byte)*s++;
1769  if (s + len >= end) {
1770  free(lang_pack);
1771  free(langpack_offs);
1772  return false;
1773  }
1774  }
1775  langpack_offs[i] = s;
1776  s += len;
1777  len = (byte)*s;
1778  *s++ = '\0'; // zero terminate the string
1779  }
1780 
1781  free(_langpack);
1782  _langpack = lang_pack;
1783 
1784  free(_langpack_offs);
1785  _langpack_offs = langpack_offs;
1786 
1787  _current_language = lang;
1788  _current_text_dir = (TextDirection)_current_language->text_dir;
1789  const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
1791  SetCurrentGrfLangID(_current_language->newgrflangid);
1792 
1793 #ifdef WITH_ICU_SORT
1794  /* Delete previous collator. */
1795  if (_current_collator != NULL) {
1796  delete _current_collator;
1797  _current_collator = NULL;
1798  }
1799 
1800  /* Create a collator instance for our current locale. */
1801  UErrorCode status = U_ZERO_ERROR;
1802  _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
1803  /* Sort number substrings by their numerical value. */
1804  if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
1805  /* Avoid using the collator if it is not correctly set. */
1806  if (U_FAILURE(status)) {
1807  delete _current_collator;
1808  _current_collator = NULL;
1809  }
1810 #endif /* WITH_ICU_SORT */
1811 
1812  /* Some lists need to be sorted again after a language change. */
1817  SortNetworkLanguages();
1819  InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window.
1820  InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window.
1821  InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window.
1822  InvalidateWindowClassesData(WC_SHIPS_LIST); // Ship group window.
1823  InvalidateWindowClassesData(WC_AIRCRAFT_LIST); // Aircraft group window.
1824  InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
1825  InvalidateWindowClassesData(WC_STATION_LIST); // Station list window.
1826 
1827  return true;
1828 }
1829 
1830 /* Win32 implementation in win32.cpp.
1831  * OS X implementation in os/macosx/macos.mm. */
1832 #if !(defined(WIN32) || defined(__APPLE__))
1833 
1841 const char *GetCurrentLocale(const char *param)
1842 {
1843  const char *env;
1844 
1845  env = getenv("LANGUAGE");
1846  if (env != NULL) return env;
1847 
1848  env = getenv("LC_ALL");
1849  if (env != NULL) return env;
1850 
1851  if (param != NULL) {
1852  env = getenv(param);
1853  if (env != NULL) return env;
1854  }
1855 
1856  return getenv("LANG");
1857 }
1858 #else
1859 const char *GetCurrentLocale(const char *param);
1860 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
1861 
1862 int CDECL StringIDSorter(const StringID *a, const StringID *b)
1863 {
1864  char stra[512];
1865  char strb[512];
1866  GetString(stra, *a, lastof(stra));
1867  GetString(strb, *b, lastof(strb));
1868 
1869  return strnatcmp(stra, strb);
1870 }
1871 
1877 const LanguageMetadata *GetLanguage(byte newgrflangid)
1878 {
1879  for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
1880  if (newgrflangid == lang->newgrflangid) return lang;
1881  }
1882 
1883  return NULL;
1884 }
1885 
1892 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
1893 {
1894  FILE *f = fopen(file, "rb");
1895  if (f == NULL) return false;
1896 
1897  size_t read = fread(hdr, sizeof(*hdr), 1, f);
1898  fclose(f);
1899 
1900  bool ret = read == 1 && hdr->IsValid();
1901 
1902  /* Convert endianness for the windows language ID */
1903  if (ret) {
1904  hdr->missing = FROM_LE16(hdr->missing);
1905  hdr->winlangid = FROM_LE16(hdr->winlangid);
1906  }
1907  return ret;
1908 }
1909 
1914 static void GetLanguageList(const char *path)
1915 {
1916  DIR *dir = ttd_opendir(path);
1917  if (dir != NULL) {
1918  struct dirent *dirent;
1919  while ((dirent = readdir(dir)) != NULL) {
1920  const char *d_name = FS2OTTD(dirent->d_name);
1921  const char *extension = strrchr(d_name, '.');
1922 
1923  /* Not a language file */
1924  if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
1925 
1926  LanguageMetadata lmd;
1927  seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
1928 
1929  /* Check whether the file is of the correct version */
1930  if (!GetLanguageFileHeader(lmd.file, &lmd)) {
1931  DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
1932  } else if (GetLanguage(lmd.newgrflangid) != NULL) {
1933  DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
1934  } else {
1935  *_languages.Append() = lmd;
1936  }
1937  }
1938  closedir(dir);
1939  }
1940 }
1941 
1947 {
1948  Searchpath sp;
1949 
1950  FOR_ALL_SEARCHPATHS(sp) {
1951  char path[MAX_PATH];
1952  FioAppendDirectory(path, lastof(path), sp, LANG_DIR);
1953  GetLanguageList(path);
1954  }
1955  if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
1956 
1957  /* Acquire the locale of the current system */
1958  const char *lang = GetCurrentLocale("LC_MESSAGES");
1959  if (lang == NULL) lang = "en_GB";
1960 
1961  const LanguageMetadata *chosen_language = NULL;
1962  const LanguageMetadata *language_fallback = NULL;
1963  const LanguageMetadata *en_GB_fallback = _languages.Begin();
1964 
1965  /* Find a proper language. */
1966  for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
1967  /* We are trying to find a default language. The priority is by
1968  * configuration file, local environment and last, if nothing found,
1969  * English. */
1970  const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
1971  if (strcmp(lang_file, _config_language_file) == 0) {
1972  chosen_language = lng;
1973  break;
1974  }
1975 
1976  if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback = lng;
1977  if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng;
1978  if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
1979  }
1980 
1981  /* We haven't found the language in the config nor the one in the locale.
1982  * Now we set it to one of the fallback languages */
1983  if (chosen_language == NULL) {
1984  chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
1985  }
1986 
1987  if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
1988 }
1989 
1995 {
1996  return _langpack->isocode;
1997 }
1998 
2006 {
2007  InitFreeType(this->Monospace());
2008  const Sprite *question_mark[FS_END];
2009 
2010  for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
2011  question_mark[size] = GetGlyph(size, '?');
2012  }
2013 
2014  this->Reset();
2015  for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
2016  FontSize size = this->DefaultSize();
2017  if (str != NULL) *str = text;
2018  for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
2019  if (c == SCC_TINYFONT) {
2020  size = FS_SMALL;
2021  } else if (c == SCC_BIGFONT) {
2022  size = FS_LARGE;
2023  } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
2024  /* The character is printable, but not in the normal font. This is the case we were testing for. */
2025  return true;
2026  }
2027  }
2028  }
2029  return false;
2030 }
2031 
2034  uint i;
2035  uint j;
2036 
2037  /* virtual */ void Reset()
2038  {
2039  this->i = 0;
2040  this->j = 0;
2041  }
2042 
2043  /* virtual */ FontSize DefaultSize()
2044  {
2045  return FS_NORMAL;
2046  }
2047 
2048  /* virtual */ const char *NextString()
2049  {
2050  if (this->i >= TAB_COUNT) return NULL;
2051 
2052  const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
2053 
2054  this->j++;
2055  while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) {
2056  this->i++;
2057  this->j = 0;
2058  }
2059 
2060  return ret;
2061  }
2062 
2063  /* virtual */ bool Monospace()
2064  {
2065  return false;
2066  }
2067 
2068  /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
2069  {
2070 #ifdef WITH_FREETYPE
2071  strecpy(settings->small.font, font_name, lastof(settings->small.font));
2072  strecpy(settings->medium.font, font_name, lastof(settings->medium.font));
2073  strecpy(settings->large.font, font_name, lastof(settings->large.font));
2074 #endif /* WITH_FREETYPE */
2075  }
2076 };
2077 
2091 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
2092 {
2093  static LanguagePackGlyphSearcher pack_searcher;
2094  if (searcher == NULL) searcher = &pack_searcher;
2095  bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
2096 #ifdef WITH_FREETYPE
2097  if (bad_font) {
2098  /* We found an unprintable character... lets try whether we can find
2099  * a fallback font that can print the characters in the current language. */
2100  FreeTypeSettings backup;
2101  memcpy(&backup, &_freetype, sizeof(backup));
2102 
2103  bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
2104 
2105  memcpy(&_freetype, &backup, sizeof(backup));
2106 
2107  if (bad_font && base_font) {
2108  /* Our fallback font does miss characters too, so keep the
2109  * user chosen font as that is more likely to be any good than
2110  * the wild guess we made */
2111  InitFreeType(searcher->Monospace());
2112  }
2113  }
2114 #endif
2115 
2116  if (bad_font) {
2117  /* All attempts have failed. Display an error. As we do not want the string to be translated by
2118  * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
2119  * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
2120  * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
2121  * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
2122  static char *err_str = stredup("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.");
2123  Utf8Encode(err_str, SCC_YELLOW);
2124  SetDParamStr(0, err_str);
2125  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
2126 
2127  /* Reset the font width */
2128  LoadStringWidthTable(searcher->Monospace());
2129  return;
2130  }
2131 
2132  /* Update the font with cache */
2133  LoadStringWidthTable(searcher->Monospace());
2134 
2135 #if !defined(WITH_ICU_LAYOUT)
2136  /*
2137  * For right-to-left languages we need the ICU library. If
2138  * we do not have support for that library we warn the user
2139  * about it with a message. As we do not want the string to
2140  * be translated by the translators, we 'force' it into the
2141  * binary and 'load' it via a BindCString. To do this
2142  * properly we have to set the colour of the string,
2143  * otherwise we end up with a lot of artifacts. The colour
2144  * 'character' might change in the future, so for safety
2145  * we just Utf8 Encode it into the string, which takes
2146  * exactly three characters, so it replaces the "XXX" with
2147  * the colour marker.
2148  */
2149  if (_current_text_dir != TD_LTR) {
2150  static char *err_str = stredup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
2151  Utf8Encode(err_str, SCC_YELLOW);
2152  SetDParamStr(0, err_str);
2153  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
2154  }
2155 #endif /* !WITH_ICU_LAYOUT */
2156 }