33 #include "table/strings.h"
44 GRFLB_AMERICAN = 0x01,
52 enum GRFExtendedLanguages {
53 GRFLX_AMERICAN = 0x00,
58 GRFLX_UNSPECIFIED = 0x7F,
98 void *
operator new(
size_t size)
107 void operator delete(
void *p)
123 memcpy(this->
text, text_,
len);
132 void *
operator new(
size_t size,
size_t extra)
134 return MallocT<byte>(size + extra);
158 static uint _num_grf_texts = 0;
172 if (m->newgrf_id == newgrf_id)
return m->openttd_id;
187 if (m->openttd_id == openttd_id)
return m->newgrf_id;
209 type(type), old_d(old_d), offset(offset)
230 grfmsg(1,
"choice list misses default value");
239 size_t len = strlen(this->
strings[0]);
240 memcpy(d, this->
strings[0], len);
246 if (this->
type == SCC_SWITCH_CASE) {
265 char *str = this->
strings[idx];
271 size_t len = strlen(str) + 1;
272 *d++ =
GB(len, 8, 8);
273 *d++ =
GB(len, 0, 8);
281 size_t len = strlen(this->
strings[0]) + 1;
282 memcpy(d, this->
strings[0], len);
285 if (this->
type == SCC_PLURAL_LIST) {
295 *d++ = this->
offset - 0x80;
302 for (
int i = 0; i < count; i++) {
305 size_t len = strlen(str) + 1;
306 if (len > 0xFF)
grfmsg(1,
"choice list string is too long");
307 *d++ =
GB(len, 0, 8);
311 for (
int i = 0; i < count; i++) {
316 size_t len = min<size_t>(0xFE, strlen(str));
338 char *tmp = MallocT<char>(strlen(str) * 10 + 1);
340 bool unicode =
false;
354 c = Utf8Consume(&str);
356 if (
GB(c, 8, 8) == 0xE0) {
358 }
else if (c >= 0x20) {
366 if (c ==
'\0')
break;
370 if (str[0] ==
'\0')
goto string_end;
376 if (allow_newlines) {
379 grfmsg(1,
"Detected newline in string that does not allow one");
385 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
396 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
398 string = ((uint8)*str++);
399 string |= ((uint8)*str++) << 8;
410 case 0x88: d +=
Utf8Encode(d, SCC_BLUE);
break;
411 case 0x89: d +=
Utf8Encode(d, SCC_SILVER);
break;
412 case 0x8A: d +=
Utf8Encode(d, SCC_GOLD);
break;
413 case 0x8B: d +=
Utf8Encode(d, SCC_RED);
break;
414 case 0x8C: d +=
Utf8Encode(d, SCC_PURPLE);
break;
415 case 0x8D: d +=
Utf8Encode(d, SCC_LTBROWN);
break;
416 case 0x8E: d +=
Utf8Encode(d, SCC_ORANGE);
break;
417 case 0x8F: d +=
Utf8Encode(d, SCC_GREEN);
break;
418 case 0x90: d +=
Utf8Encode(d, SCC_YELLOW);
break;
419 case 0x91: d +=
Utf8Encode(d, SCC_DKGREEN);
break;
420 case 0x92: d +=
Utf8Encode(d, SCC_CREAM);
break;
421 case 0x93: d +=
Utf8Encode(d, SCC_BROWN);
break;
422 case 0x94: d +=
Utf8Encode(d, SCC_WHITE);
break;
423 case 0x95: d +=
Utf8Encode(d, SCC_LTBLUE);
break;
424 case 0x96: d +=
Utf8Encode(d, SCC_GRAY);
break;
425 case 0x97: d +=
Utf8Encode(d, SCC_DKBLUE);
break;
426 case 0x98: d +=
Utf8Encode(d, SCC_BLACK);
break;
430 case 0x00:
goto string_end;
440 if (str[0] ==
'\0' || str[1] ==
'\0')
goto string_end;
441 uint16 tmp = ((uint8)*str++);
442 tmp |= ((uint8)*str++) << 8;
448 if (str[0] ==
'\0')
goto string_end;
461 if (str[0] ==
'\0')
goto string_end;
464 int mapped = lm != NULL ? lm->
GetMapping(index, code == 0x0E) : -1;
466 d +=
Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE);
467 d +=
Utf8Encode(d, code == 0x0E ? mapped : mapped + 1);
474 if (str[0] ==
'\0')
goto string_end;
475 if (mapping == NULL) {
476 if (code == 0x10) str++;
477 grfmsg(1,
"choice list %s marker found when not expected", code == 0x10 ?
"next" :
"default");
482 int index = (code == 0x10 ? *str++ : 0);
484 grfmsg(1,
"duplicate choice list string, ignoring");
487 d = mapping->
strings[index] = MallocT<char>(strlen(str) * 10 + 1);
493 if (mapping == NULL) {
494 grfmsg(1,
"choice list end marker found when not expected");
509 if (str[0] ==
'\0')
goto string_end;
510 if (mapping != NULL) {
511 grfmsg(1,
"choice lists can't be stacked, it's going to get messy now...");
512 if (code != 0x14) str++;
514 static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST };
532 grfmsg(1,
"missing handler for extended format code");
540 case 0xA0: d +=
Utf8Encode(d, SCC_UP_ARROW);
break;
541 case 0xAA: d +=
Utf8Encode(d, SCC_DOWN_ARROW);
break;
542 case 0xAC: d +=
Utf8Encode(d, SCC_CHECKMARK);
break;
543 case 0xAD: d +=
Utf8Encode(d, SCC_CROSS);
break;
544 case 0xAF: d +=
Utf8Encode(d, SCC_RIGHT_ARROW);
break;
545 case 0xB4: d +=
Utf8Encode(d, SCC_TRAIN);
break;
546 case 0xB5: d +=
Utf8Encode(d, SCC_LORRY);
break;
547 case 0xB6: d +=
Utf8Encode(d, SCC_BUS);
break;
548 case 0xB7: d +=
Utf8Encode(d, SCC_PLANE);
break;
549 case 0xB8: d +=
Utf8Encode(d, SCC_SHIP);
break;
550 case 0xB9: d +=
Utf8Encode(d, SCC_SUPERSCRIPT_M1);
break;
551 case 0xBC: d +=
Utf8Encode(d, SCC_SMALL_UP_ARROW);
break;
552 case 0xBD: d +=
Utf8Encode(d, SCC_SMALL_DOWN_ARROW);
break;
562 if (mapping != NULL) {
563 grfmsg(1,
"choice list was incomplete, the whole list is ignored");
568 if (olen != NULL) *olen = d - tmp + 1;
583 for (ptext = list; (text = *ptext) != NULL; ptext = &text->
next) {
586 *ptext = text_to_add;
593 *ptext = text_to_add;
610 free(translatedtext);
635 for (; orig != NULL; orig = orig->
next) {
637 ptext = &(*ptext)->
next;
645 StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add,
bool new_scheme,
bool allow_newlines,
const char *text_to_add,
StringID def_string)
647 char *translatedtext;
657 if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) {
658 langid_to_add = GRFLX_ENGLISH;
661 if (langid_to_add & GRFLB_GERMAN) ret =
AddGRFString(grfid, stringid, GRFLX_GERMAN,
true, allow_newlines, text_to_add, def_string);
662 if (langid_to_add & GRFLB_FRENCH) ret =
AddGRFString(grfid, stringid, GRFLX_FRENCH,
true, allow_newlines, text_to_add, def_string);
663 if (langid_to_add & GRFLB_SPANISH) ret =
AddGRFString(grfid, stringid, GRFLX_SPANISH,
true, allow_newlines, text_to_add, def_string);
668 for (
id = 0;
id < _num_grf_texts;
id++) {
669 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
675 if (
id ==
lengthof(_grf_text))
return STR_EMPTY;
682 free(translatedtext);
685 if (
id == _num_grf_texts) _num_grf_texts++;
687 if (_grf_text[
id].textholder == NULL) {
688 _grf_text[id].grfid = grfid;
689 _grf_text[id].stringid = stringid;
690 _grf_text[id].def_string = def_string;
694 grfmsg(3,
"Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'",
id, grfid, stringid, newtext->
langid, newtext->
text);
704 for (uint
id = 0;
id < _num_grf_texts;
id++) {
705 if (_grf_text[
id].grfid == grfid && _grf_text[
id].stringid == stringid) {
710 return STR_UNDEFINED;
723 const char *default_text = NULL;
726 for (; text != NULL; text = text->
next) {
731 if (text->
langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->
langid == GRFLX_ENGLISH || text->
langid == GRFLX_AMERICAN))) {
732 default_text = text->
text;
744 assert(_grf_text[stringid].grfid != 0);
747 if (str != NULL)
return str;
750 return GetStringPtr(_grf_text[stringid].def_string);
766 bool CheckGrfLangID(byte lang_id, byte grf_version)
768 if (grf_version < 7) {
770 case GRFLX_GERMAN:
return (lang_id & GRFLB_GERMAN) != 0;
771 case GRFLX_FRENCH:
return (lang_id & GRFLB_FRENCH) != 0;
772 case GRFLX_SPANISH:
return (lang_id & GRFLB_SPANISH) != 0;
773 default:
return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
777 return (lang_id ==
_currentLangID || lang_id == GRFLX_UNSPECIFIED);
786 while (grftext != NULL) {
801 for (
id = 0;
id < _num_grf_texts;
id++) {
803 _grf_text[id].grfid = 0;
804 _grf_text[id].stringid = 0;
805 _grf_text[id].textholder = NULL;
817 TextRefStack() : position(0), grffile(NULL), used(
false) {}
820 position(stack.position),
821 grffile(stack.grffile),
824 memcpy(this->stack, stack.stack,
sizeof(this->stack));
827 uint8 PopUnsignedByte() { assert(this->position <
lengthof(this->stack));
return this->stack[this->position++]; }
828 int8 PopSignedByte() {
return (int8)this->PopUnsignedByte(); }
830 uint16 PopUnsignedWord()
832 uint16 val = this->PopUnsignedByte();
833 return val | (this->PopUnsignedByte() << 8);
835 int16 PopSignedWord() {
return (int32)this->PopUnsignedWord(); }
837 uint32 PopUnsignedDWord()
839 uint32 val = this->PopUnsignedWord();
840 return val | (this->PopUnsignedWord() << 16);
842 int32 PopSignedDWord() {
return (int32)this->PopUnsignedDWord(); }
844 uint64 PopUnsignedQWord()
846 uint64 val = this->PopUnsignedDWord();
847 return val | (((uint64)this->PopUnsignedDWord()) << 32);
849 int64 PopSignedQWord() {
return (int64)this->PopUnsignedQWord(); }
855 for (
int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6];
856 for (
int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i];
857 for (
int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i];
860 void PushWord(uint16 word)
862 if (this->position >= 2) {
865 for (
int i =
lengthof(stack) - 1; i >= this->position + 2; i--) {
866 this->stack[i] = this->stack[i - 2];
869 this->stack[this->position] =
GB(word, 0, 8);
870 this->stack[this->position + 1] =
GB(word, 8, 8);
873 void ResetStack(
const GRFFile *grffile)
875 assert(grffile != NULL);
877 this->grffile = grffile;
881 void RewindStack() { this->position = 0; }
893 return _newgrf_textrefstack.used;
911 _newgrf_textrefstack = *backup;
937 _newgrf_textrefstack.ResetStack(grffile);
939 byte *p = _newgrf_textrefstack.stack;
940 for (uint i = 0; i < numEntries; i++) {
941 uint32 value = values != NULL ? values[i] : _temp_store.
GetValue(0x100 + i);
942 for (uint j = 0; j < 32; j += 8) {
943 *p =
GB(value, j, 8);
952 _newgrf_textrefstack.used =
false;
955 void RewindTextRefStack()
957 _newgrf_textrefstack.RewindStack();
999 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1007 if (argv_size < 2) {
1008 DEBUG(misc, 0,
"Too many NewGRF string parameters.");
1014 if (_newgrf_textrefstack.used && modify_argv) {
1016 default: NOT_REACHED();
1054 argv[0] =
GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
1055 argv[1] = _newgrf_textrefstack.PopUnsignedWord();
1059 *argv =
MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord());
1064 *argv = cargo <
NUM_CARGO ? 1 << cargo : 0;
1081 default: NOT_REACHED();
1096 return SCC_CURRENCY_LONG;
1103 return SCC_DATE_LONG;
1107 return SCC_DATE_SHORT;
1110 return SCC_VELOCITY;
1113 return SCC_VOLUME_LONG;
1116 return SCC_VOLUME_SHORT;
1119 return SCC_WEIGHT_LONG;
1122 return SCC_WEIGHT_SHORT;
1128 return SCC_CARGO_LONG;
1131 return SCC_CARGO_SHORT;
1134 return SCC_CARGO_TINY;
1137 return SCC_CARGO_LIST;
1140 return SCC_STATION_NAME;