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 };
535 grfmsg(1,
"missing handler for extended format code");
543 case 0xA0: d +=
Utf8Encode(d, SCC_UP_ARROW);
break;
544 case 0xAA: d +=
Utf8Encode(d, SCC_DOWN_ARROW);
break;
545 case 0xAC: d +=
Utf8Encode(d, SCC_CHECKMARK);
break;
546 case 0xAD: d +=
Utf8Encode(d, SCC_CROSS);
break;
547 case 0xAF: d +=
Utf8Encode(d, SCC_RIGHT_ARROW);
break;
548 case 0xB4: d +=
Utf8Encode(d, SCC_TRAIN);
break;
549 case 0xB5: d +=
Utf8Encode(d, SCC_LORRY);
break;
550 case 0xB6: d +=
Utf8Encode(d, SCC_BUS);
break;
551 case 0xB7: d +=
Utf8Encode(d, SCC_PLANE);
break;
552 case 0xB8: d +=
Utf8Encode(d, SCC_SHIP);
break;
553 case 0xB9: d +=
Utf8Encode(d, SCC_SUPERSCRIPT_M1);
break;
554 case 0xBC: d +=
Utf8Encode(d, SCC_SMALL_UP_ARROW);
break;
555 case 0xBD: d +=
Utf8Encode(d, SCC_SMALL_DOWN_ARROW);
break;
565 if (mapping != NULL) {
566 grfmsg(1,
"choice list was incomplete, the whole list is ignored");
571 if (olen != NULL) *olen = d - tmp + 1;
586 for (ptext = list; (text = *ptext) != NULL; ptext = &text->
next) {
589 *ptext = text_to_add;
596 *ptext = text_to_add;
613 free(translatedtext);
638 for (; orig != NULL; orig = orig->
next) {
640 ptext = &(*ptext)->
next;
648 StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add,
bool new_scheme,
bool allow_newlines,
const char *text_to_add,
StringID def_string)
650 char *translatedtext;
660 if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) {
661 langid_to_add = GRFLX_ENGLISH;
664 if (langid_to_add & GRFLB_GERMAN) ret =
AddGRFString(grfid, stringid, GRFLX_GERMAN,
true, allow_newlines, text_to_add, def_string);
665 if (langid_to_add & GRFLB_FRENCH) ret =
AddGRFString(grfid, stringid, GRFLX_FRENCH,
true, allow_newlines, text_to_add, def_string);
666 if (langid_to_add & GRFLB_SPANISH) ret =
AddGRFString(grfid, stringid, GRFLX_SPANISH,
true, allow_newlines, text_to_add, def_string);
671 for (
id = 0;
id < _num_grf_texts;
id++) {
672 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
678 if (
id ==
lengthof(_grf_text))
return STR_EMPTY;
685 free(translatedtext);
688 if (
id == _num_grf_texts) _num_grf_texts++;
690 if (_grf_text[
id].textholder == NULL) {
691 _grf_text[id].grfid = grfid;
692 _grf_text[id].stringid = stringid;
693 _grf_text[id].def_string = def_string;
697 grfmsg(3,
"Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'",
id, grfid, stringid, newtext->
langid, newtext->
text);
699 return (GRFTAB << TABSIZE) + id;
707 for (uint
id = 0;
id < _num_grf_texts;
id++) {
708 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
709 return (GRFTAB << TABSIZE) + id;
713 return STR_UNDEFINED;
726 const char *default_text = NULL;
729 for (; text != NULL; text = text->
next) {
734 if (text->
langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->
langid == GRFLX_ENGLISH || text->
langid == GRFLX_AMERICAN))) {
735 default_text = text->
text;
747 assert(_grf_text[stringid].grfid != 0);
750 if (str != NULL)
return str;
753 return GetStringPtr(_grf_text[stringid].def_string);
769 bool CheckGrfLangID(byte lang_id, byte grf_version)
771 if (grf_version < 7) {
773 case GRFLX_GERMAN:
return (lang_id & GRFLB_GERMAN) != 0;
774 case GRFLX_FRENCH:
return (lang_id & GRFLB_FRENCH) != 0;
775 case GRFLX_SPANISH:
return (lang_id & GRFLB_SPANISH) != 0;
776 default:
return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
780 return (lang_id ==
_currentLangID || lang_id == GRFLX_UNSPECIFIED);
789 while (grftext != NULL) {
804 for (
id = 0;
id < _num_grf_texts;
id++) {
806 _grf_text[id].grfid = 0;
807 _grf_text[id].stringid = 0;
808 _grf_text[id].textholder = NULL;
820 TextRefStack() : position(0), grffile(NULL), used(
false) {}
823 position(stack.position),
824 grffile(stack.grffile),
827 memcpy(this->stack, stack.stack,
sizeof(this->stack));
830 uint8 PopUnsignedByte() { assert(this->position <
lengthof(this->stack));
return this->stack[this->position++]; }
831 int8 PopSignedByte() {
return (int8)this->PopUnsignedByte(); }
833 uint16 PopUnsignedWord()
835 uint16 val = this->PopUnsignedByte();
836 return val | (this->PopUnsignedByte() << 8);
838 int16 PopSignedWord() {
return (int32)this->PopUnsignedWord(); }
840 uint32 PopUnsignedDWord()
842 uint32 val = this->PopUnsignedWord();
843 return val | (this->PopUnsignedWord() << 16);
845 int32 PopSignedDWord() {
return (int32)this->PopUnsignedDWord(); }
847 uint64 PopUnsignedQWord()
849 uint64 val = this->PopUnsignedDWord();
850 return val | (((uint64)this->PopUnsignedDWord()) << 32);
852 int64 PopSignedQWord() {
return (int64)this->PopUnsignedQWord(); }
858 for (
int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6];
859 for (
int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i];
860 for (
int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i];
863 void PushWord(uint16 word)
865 if (this->position >= 2) {
868 for (
int i =
lengthof(stack) - 1; i >= this->position + 2; i--) {
869 this->stack[i] = this->stack[i - 2];
872 this->stack[this->position] =
GB(word, 0, 8);
873 this->stack[this->position + 1] =
GB(word, 8, 8);
876 void ResetStack(
const GRFFile *grffile)
878 assert(grffile != NULL);
880 this->grffile = grffile;
884 void RewindStack() { this->position = 0; }
896 return _newgrf_textrefstack.used;
914 _newgrf_textrefstack = *backup;
940 _newgrf_textrefstack.ResetStack(grffile);
942 byte *p = _newgrf_textrefstack.stack;
943 for (uint i = 0; i < numEntries; i++) {
944 uint32 value = values != NULL ? values[i] : _temp_store.
GetValue(0x100 + i);
945 for (uint j = 0; j < 32; j += 8) {
946 *p =
GB(value, j, 8);
955 _newgrf_textrefstack.used =
false;
958 void RewindTextRefStack()
960 _newgrf_textrefstack.RewindStack();
1001 if (argv_size < 1) {
1002 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1010 if (argv_size < 2) {
1011 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1017 if (_newgrf_textrefstack.used && modify_argv) {
1019 default: NOT_REACHED();
1057 argv[0] =
GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
1058 argv[1] = _newgrf_textrefstack.PopUnsignedWord();
1062 *argv =
MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord());
1067 *argv = cargo <
NUM_CARGO ? 1 << cargo : 0;
1084 default: NOT_REACHED();
1099 return SCC_CURRENCY_LONG;
1106 return SCC_DATE_LONG;
1110 return SCC_DATE_SHORT;
1113 return SCC_VELOCITY;
1116 return SCC_VOLUME_LONG;
1119 return SCC_VOLUME_SHORT;
1122 return SCC_WEIGHT_LONG;
1125 return SCC_WEIGHT_SHORT;
1131 return SCC_CARGO_LONG;
1134 return SCC_CARGO_SHORT;
1137 return SCC_CARGO_TINY;
1140 return SCC_CARGO_LIST;
1143 return SCC_STATION_NAME;