33 #include "table/strings.h"
47 GRFLB_AMERICAN = 0x01,
55 enum GRFExtendedLanguages {
56 GRFLX_AMERICAN = 0x00,
61 GRFLX_UNSPECIFIED = 0x7F,
101 void *
operator new(
size_t size)
110 void operator delete(
void *p)
126 memcpy(this->
text, text_,
len);
135 void *
operator new(
size_t size,
size_t extra)
137 return MallocT<byte>(size + extra);
161 static uint _num_grf_texts = 0;
175 if (m->newgrf_id == newgrf_id)
return m->openttd_id;
190 if (m->openttd_id == openttd_id)
return m->newgrf_id;
212 type(type), old_d(old_d), offset(offset)
233 grfmsg(1,
"choice list misses default value");
242 size_t len = strlen(this->
strings[0]);
243 memcpy(d, this->
strings[0], len);
249 if (this->
type == SCC_SWITCH_CASE) {
268 char *str = this->
strings[idx];
274 size_t len = strlen(str) + 1;
275 *d++ =
GB(len, 8, 8);
276 *d++ =
GB(len, 0, 8);
284 size_t len = strlen(this->
strings[0]) + 1;
285 memcpy(d, this->
strings[0], len);
288 if (this->
type == SCC_PLURAL_LIST) {
298 *d++ = this->
offset - 0x80;
305 for (
int i = 0; i < count; i++) {
308 size_t len = strlen(str) + 1;
309 if (len > 0xFF)
grfmsg(1,
"choice list string is too long");
310 *d++ =
GB(len, 0, 8);
314 for (
int i = 0; i < count; i++) {
319 size_t len = min<size_t>(0xFE, strlen(str));
341 char *tmp = MallocT<char>(strlen(str) * 10 + 1);
343 bool unicode =
false;
357 c = Utf8Consume(&str);
359 if (
GB(c, 8, 8) == 0xE0) {
361 }
else if (c >= 0x20) {
369 if (c ==
'\0')
break;
373 if (str[0] ==
'\0')
goto string_end;
379 if (allow_newlines) {
382 grfmsg(1,
"Detected newline in string that does not allow one");
388 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
399 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
401 string = ((uint8)*str++);
402 string |= ((uint8)*str++) << 8;
413 case 0x88: d +=
Utf8Encode(d, SCC_BLUE);
break;
414 case 0x89: d +=
Utf8Encode(d, SCC_SILVER);
break;
415 case 0x8A: d +=
Utf8Encode(d, SCC_GOLD);
break;
416 case 0x8B: d +=
Utf8Encode(d, SCC_RED);
break;
417 case 0x8C: d +=
Utf8Encode(d, SCC_PURPLE);
break;
418 case 0x8D: d +=
Utf8Encode(d, SCC_LTBROWN);
break;
419 case 0x8E: d +=
Utf8Encode(d, SCC_ORANGE);
break;
420 case 0x8F: d +=
Utf8Encode(d, SCC_GREEN);
break;
421 case 0x90: d +=
Utf8Encode(d, SCC_YELLOW);
break;
422 case 0x91: d +=
Utf8Encode(d, SCC_DKGREEN);
break;
423 case 0x92: d +=
Utf8Encode(d, SCC_CREAM);
break;
424 case 0x93: d +=
Utf8Encode(d, SCC_BROWN);
break;
425 case 0x94: d +=
Utf8Encode(d, SCC_WHITE);
break;
426 case 0x95: d +=
Utf8Encode(d, SCC_LTBLUE);
break;
427 case 0x96: d +=
Utf8Encode(d, SCC_GRAY);
break;
428 case 0x97: d +=
Utf8Encode(d, SCC_DKBLUE);
break;
429 case 0x98: d +=
Utf8Encode(d, SCC_BLACK);
break;
433 case 0x00:
goto string_end;
443 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
444 uint16 tmp = ((uint8)*str++);
445 tmp |= ((uint8)*str++) << 8;
451 if (str[0] ==
'\0')
goto string_end;
464 if (str[0] ==
'\0')
goto string_end;
467 int mapped = lm != NULL ? lm->
GetMapping(index, code == 0x0E) : -1;
469 d +=
Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE);
470 d +=
Utf8Encode(d, code == 0x0E ? mapped : mapped + 1);
477 if (str[0] ==
'\0')
goto string_end;
478 if (mapping == NULL) {
479 if (code == 0x10) str++;
480 grfmsg(1,
"choice list %s marker found when not expected", code == 0x10 ?
"next" :
"default");
485 int index = (code == 0x10 ? *str++ : 0);
487 grfmsg(1,
"duplicate choice list string, ignoring");
490 d = mapping->
strings[index] = MallocT<char>(strlen(str) * 10 + 1);
496 if (mapping == NULL) {
497 grfmsg(1,
"choice list end marker found when not expected");
512 if (str[0] ==
'\0')
goto string_end;
513 if (mapping != NULL) {
514 grfmsg(1,
"choice lists can't be stacked, it's going to get messy now...");
515 if (code != 0x14) str++;
517 static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST };
534 grfmsg(1,
"missing handler for extended format code");
542 case 0xA0: d +=
Utf8Encode(d, SCC_UP_ARROW);
break;
543 case 0xAA: d +=
Utf8Encode(d, SCC_DOWN_ARROW);
break;
544 case 0xAC: d +=
Utf8Encode(d, SCC_CHECKMARK);
break;
545 case 0xAD: d +=
Utf8Encode(d, SCC_CROSS);
break;
546 case 0xAF: d +=
Utf8Encode(d, SCC_RIGHT_ARROW);
break;
547 case 0xB4: d +=
Utf8Encode(d, SCC_TRAIN);
break;
548 case 0xB5: d +=
Utf8Encode(d, SCC_LORRY);
break;
549 case 0xB6: d +=
Utf8Encode(d, SCC_BUS);
break;
550 case 0xB7: d +=
Utf8Encode(d, SCC_PLANE);
break;
551 case 0xB8: d +=
Utf8Encode(d, SCC_SHIP);
break;
552 case 0xB9: d +=
Utf8Encode(d, SCC_SUPERSCRIPT_M1);
break;
553 case 0xBC: d +=
Utf8Encode(d, SCC_SMALL_UP_ARROW);
break;
554 case 0xBD: d +=
Utf8Encode(d, SCC_SMALL_DOWN_ARROW);
break;
564 if (mapping != NULL) {
565 grfmsg(1,
"choice list was incomplete, the whole list is ignored");
570 if (olen != NULL) *olen = d - tmp + 1;
585 for (ptext = list; (text = *ptext) != NULL; ptext = &text->
next) {
588 *ptext = text_to_add;
595 *ptext = text_to_add;
612 free(translatedtext);
637 for (; orig != NULL; orig = orig->
next) {
639 ptext = &(*ptext)->
next;
647 StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add,
bool new_scheme,
bool allow_newlines,
const char *text_to_add,
StringID def_string)
649 char *translatedtext;
659 if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) {
660 langid_to_add = GRFLX_ENGLISH;
663 if (langid_to_add & GRFLB_GERMAN) ret =
AddGRFString(grfid, stringid, GRFLX_GERMAN,
true, allow_newlines, text_to_add, def_string);
664 if (langid_to_add & GRFLB_FRENCH) ret =
AddGRFString(grfid, stringid, GRFLX_FRENCH,
true, allow_newlines, text_to_add, def_string);
665 if (langid_to_add & GRFLB_SPANISH) ret =
AddGRFString(grfid, stringid, GRFLX_SPANISH,
true, allow_newlines, text_to_add, def_string);
670 for (
id = 0;
id < _num_grf_texts;
id++) {
671 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
677 if (
id ==
lengthof(_grf_text))
return STR_EMPTY;
684 free(translatedtext);
687 if (
id == _num_grf_texts) _num_grf_texts++;
689 if (_grf_text[
id].textholder == NULL) {
690 _grf_text[id].grfid = grfid;
691 _grf_text[id].stringid = stringid;
692 _grf_text[id].def_string = def_string;
696 grfmsg(3,
"Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'",
id, grfid, stringid, newtext->
langid, newtext->
text);
698 return (GRFTAB << TABSIZE) + id;
706 for (uint
id = 0;
id < _num_grf_texts;
id++) {
707 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
708 return (GRFTAB << TABSIZE) + id;
712 return STR_UNDEFINED;
725 const char *default_text = NULL;
728 for (; text != NULL; text = text->
next) {
733 if (text->
langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->
langid == GRFLX_ENGLISH || text->
langid == GRFLX_AMERICAN))) {
734 default_text = text->
text;
746 assert(_grf_text[stringid].grfid != 0);
749 if (str != NULL)
return str;
752 return GetStringPtr(_grf_text[stringid].def_string);
768 bool CheckGrfLangID(byte lang_id, byte grf_version)
770 if (grf_version < 7) {
772 case GRFLX_GERMAN:
return (lang_id & GRFLB_GERMAN) != 0;
773 case GRFLX_FRENCH:
return (lang_id & GRFLB_FRENCH) != 0;
774 case GRFLX_SPANISH:
return (lang_id & GRFLB_SPANISH) != 0;
775 default:
return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
779 return (lang_id ==
_currentLangID || lang_id == GRFLX_UNSPECIFIED);
788 while (grftext != NULL) {
803 for (
id = 0;
id < _num_grf_texts;
id++) {
805 _grf_text[id].grfid = 0;
806 _grf_text[id].stringid = 0;
807 _grf_text[id].textholder = NULL;
819 TextRefStack() : position(0), grffile(NULL), used(
false) {}
822 position(stack.position),
823 grffile(stack.grffile),
826 memcpy(this->stack, stack.stack,
sizeof(this->stack));
829 uint8 PopUnsignedByte() { assert(this->position <
lengthof(this->stack));
return this->stack[this->position++]; }
830 int8 PopSignedByte() {
return (int8)this->PopUnsignedByte(); }
832 uint16 PopUnsignedWord()
834 uint16 val = this->PopUnsignedByte();
835 return val | (this->PopUnsignedByte() << 8);
837 int16 PopSignedWord() {
return (int32)this->PopUnsignedWord(); }
839 uint32 PopUnsignedDWord()
841 uint32 val = this->PopUnsignedWord();
842 return val | (this->PopUnsignedWord() << 16);
844 int32 PopSignedDWord() {
return (int32)this->PopUnsignedDWord(); }
846 uint64 PopUnsignedQWord()
848 uint64 val = this->PopUnsignedDWord();
849 return val | (((uint64)this->PopUnsignedDWord()) << 32);
851 int64 PopSignedQWord() {
return (int64)this->PopUnsignedQWord(); }
857 for (
int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6];
858 for (
int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i];
859 for (
int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i];
862 void PushWord(uint16 word)
864 if (this->position >= 2) {
867 for (
int i =
lengthof(stack) - 1; i >= this->position + 2; i--) {
868 this->stack[i] = this->stack[i - 2];
871 this->stack[this->position] =
GB(word, 0, 8);
872 this->stack[this->position + 1] =
GB(word, 8, 8);
875 void ResetStack(
const GRFFile *grffile)
877 assert(grffile != NULL);
879 this->grffile = grffile;
883 void RewindStack() { this->position = 0; }
895 return _newgrf_textrefstack.used;
913 _newgrf_textrefstack = *backup;
939 _newgrf_textrefstack.ResetStack(grffile);
941 byte *p = _newgrf_textrefstack.stack;
942 for (uint i = 0; i < numEntries; i++) {
943 uint32 value = values != NULL ? values[i] : _temp_store.
GetValue(0x100 + i);
944 for (uint j = 0; j < 32; j += 8) {
945 *p =
GB(value, j, 8);
954 _newgrf_textrefstack.used =
false;
957 void RewindTextRefStack()
959 _newgrf_textrefstack.RewindStack();
1000 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1008 if (argv_size < 2) {
1009 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1015 if (_newgrf_textrefstack.used && modify_argv) {
1017 default: NOT_REACHED();
1055 argv[0] =
GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
1056 argv[1] = _newgrf_textrefstack.PopUnsignedWord();
1060 *argv =
MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord());
1076 default: NOT_REACHED();
1091 return SCC_CURRENCY_LONG;
1098 return SCC_DATE_LONG;
1102 return SCC_DATE_SHORT;
1105 return SCC_VELOCITY;
1108 return SCC_VOLUME_LONG;
1111 return SCC_VOLUME_SHORT;
1114 return SCC_WEIGHT_LONG;
1117 return SCC_WEIGHT_SHORT;
1123 return SCC_CARGO_LONG;
1126 return SCC_CARGO_SHORT;
1129 return SCC_CARGO_TINY;
1132 return SCC_STATION_NAME;