Binary script with entry points for saves. Ignore the entry points.
Bytecode implementation here is hacky.
Shift-JIS, except hiragana is encoded in single bytes.
1 //「日本語 This file is shift‐jis. I’m sorry, but there’s a reason.」
2 // This file is shift-jis. I'm sorry, but there's a reason.
3 // IF THIS FILE IS NOT ENCODED AS SHIFT-JIS, HIRAGANA WILL NOT DUMP CORRECTLY.
4
5 // Dumper for Nanairo Reincarnation's script and maybe others
6
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <stdio.h>
10
11 // For some reason, they use compressed hiragana encodings.
12 // Not only does this make it impossible to encode ascii text, it's batshit crazy.
13 const char * array[] = {
14 /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF*/
15 /*0X*/ "", "ぁ", "あ", "ぃ", "い", "ぅ", "う", "ぇ", "え", "ぉ", "お", "か", "が", "き", "ぎ", "く",
16 /*1X*/ "ぐ", "け", "げ", "こ", "ご", "さ", "ざ", "し", "じ", "す", "ず", "せ", "ぜ", "そ", "ぞ", "た",
17 /*2X*/ "だ", "ち", "ぢ", "っ", "つ", "づ", "て", "で", "と", "ど", "な", "に", "ぬ", "ね", "の", "は",
18 /*3X*/ "ば", "ぱ", "ひ", "び", "ぴ", "ふ", "ぶ", "ぷ", "へ", "べ", "ぺ", "ほ", "ぼ", "ぽ", "ま", "み",
19 /*4X*/ "む", "め", "も", "ゃ", "や", "ゅ", "ゆ", "ょ", "よ", "ら", "り", "る", "れ", "ろ", "ゎ", "わ",
20 /*5X*/ "ゐ", "ゑ", "を", "ん", "", "", "", "", "", "", "", "", "", "", "", "",
21 /*6X*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
22 /*7X*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
23 /*8X*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
24 /*9X*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
25 /*AX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
26 /*BX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
27 /*CX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
28 /*DX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
29 /*EX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
30 /*FX*/ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
31 };
32
33 bool is_jis_surrogate(uint8_t c)
34 {
35 if(c >= 0x80 and c <= 0xA0) return true;
36 if(c >= 0xE0) return true;
37 return false;
38 }
39
40 void output(int c)
41 {
42 putc(c, stdout);
43 }
44
45 int main(int argc, char ** argv)
46 {
47 // feed .MES files
48 for(int i = 1; i < argc; i++)
49 {
50 auto f = fopen(argv[i], "rb");
51
52 if(!f) return puts("failed to open"), 0;
53
54 uint32_t numlines;
55 fread(&numlines, 4, 1, f);
56
57 uint32_t defines;
58 fread(&defines, 4, 1, f);
59
60 fseek(f, 4*defines, SEEK_CUR);
61
62 uint32_t startpoint = numlines*4 + defines*4 + 8;
63
64 // documentation as code, not used
65 // address of where to go for various save indexes?
66 uint32_t * lineaddrs = (uint32_t *)malloc(sizeof(uint32_t)*numlines);
67 fread(lineaddrs, 4, numlines, f);
68
69 int c = 0;
70 while(1)
71 {
72 c = fgetc(f);
73 if(c < 0) break;
74
75 // Opcode handling to stay in sync. Not proper reverse engineering, 95% guesswork.
76 if(c != 0x0A)
77 {
78 switch(c)
79 {
80 case 0x32: // some kind of load command - variable width?
81 case 0x1B: // some kind of jump?
82 case 0x14: // some kind of jump?
83 case 0x15: // some kind of jump?
84 case 0x1A:
85 fseek(f, 4, SEEK_CUR);
86 continue;
87 case 0x19: // related to text, seems to work to interpret it as a page marker
88 fseek(f, 4, SEEK_CUR);
89 printf("\n");
90 continue;
91 case 0x18:
92 case 0x04:
93 case 0x0F:
94 case 0x0E:
95 case 0x0D:
96 case 0x05:
97 case 0x3C:
98 case 0x42:
99 case 0x43:
100 case 0x34:
101 case 0x17:
102 case 0x3A:
103 case 0x00: // ????????????????????
104 case 0x0C:
105 case 0x02:
106 case 0x11:
107 case 0x3F:
108 case 0x41:
109 case 0x3B:
110 case 0x35:
111 continue;
112 case 0x1C: // between lines in multi-line messages; line wrap?
113 //printf(" ");
114 continue;
115 case 0x36:
116 c = fgetc(f);
117 if(c != 0x3D)
118 {
119 printf("Unexpected pattern byte %02X after 36 at %08X\n", uint8_t(c), ftell(f)-2);
120 exit(0);
121 }
122 continue;
123 case 0x33: // e.g. op33: 6E 6E 5F 68 30 30 30 30 2E 6F 67 67 "0x33: nn_h0000.ogg"
124 while((c = fgetc(f)) != 0);
125 continue;
126 }
127 if(c < 0)
128 continue;
129
130 printf("Unknown command %02X at %08X in %s\n", uint8_t(c), ftell(f)-1, argv[i]);
131 printf("Next byte is %02X\n", fgetc(f));
132 exit(0);
133 }
134 // fall-through case command 0x0A: display text
135 c = fgetc(f);
136 while(c != 0)
137 {
138 if(is_jis_surrogate(c))
139 {
140 output(c);
141 c = fgetc(f);
142 if(c == 0) break;
143 output(c);
144 }
145 else
146 {
147 if(*(array[c]) == 0)
148 {
149 printf("Unknown encoded character %02X at %08X\n", uint8_t(c), ftell(f)-1);
150 exit(0);
151 }
152 else if(*(array[c]) != 1)
153 printf(array[c]);
154 }
155 c = fgetc(f);
156 }
157 }
158 free(lineaddrs);
159 fclose(f);
160 }
161 }