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