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