Last active
May 18, 2017 18:21
-
-
Save wareya/515480aea76e34a628e1e5fb46acd1bf to your computer and use it in GitHub Desktop.
Dumps a .mjo file (binary script for Katahane) to a human-readable plaintext script. Furigana format 《かな》〈漢字〉
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <string> | |
uint8_t key[1024] = { | |
0x00,0x00,0x00,0x00,0x96,0x30,0x07,0x77,0x2c,0x61,0x0e,0xee,0xba,0x51,0x09,0x99, | |
0x19,0xc4,0x6d,0x07,0x8f,0xf4,0x6a,0x70,0x35,0xa5,0x63,0xe9,0xa3,0x95,0x64,0x9e, | |
0x32,0x88,0xdb,0x0e,0xa4,0xb8,0xdc,0x79,0x1e,0xe9,0xd5,0xe0,0x88,0xd9,0xd2,0x97, | |
0x2b,0x4c,0xb6,0x09,0xbd,0x7c,0xb1,0x7e,0x07,0x2d,0xb8,0xe7,0x91,0x1d,0xbf,0x90, | |
0x64,0x10,0xb7,0x1d,0xf2,0x20,0xb0,0x6a,0x48,0x71,0xb9,0xf3,0xde,0x41,0xbe,0x84, | |
0x7d,0xd4,0xda,0x1a,0xeb,0xe4,0xdd,0x6d,0x51,0xb5,0xd4,0xf4,0xc7,0x85,0xd3,0x83, | |
0x56,0x98,0x6c,0x13,0xc0,0xa8,0x6b,0x64,0x7a,0xf9,0x62,0xfd,0xec,0xc9,0x65,0x8a, | |
0x4f,0x5c,0x01,0x14,0xd9,0x6c,0x06,0x63,0x63,0x3d,0x0f,0xfa,0xf5,0x0d,0x08,0x8d, | |
0xc8,0x20,0x6e,0x3b,0x5e,0x10,0x69,0x4c,0xe4,0x41,0x60,0xd5,0x72,0x71,0x67,0xa2, | |
0xd1,0xe4,0x03,0x3c,0x47,0xd4,0x04,0x4b,0xfd,0x85,0x0d,0xd2,0x6b,0xb5,0x0a,0xa5, | |
0xfa,0xa8,0xb5,0x35,0x6c,0x98,0xb2,0x42,0xd6,0xc9,0xbb,0xdb,0x40,0xf9,0xbc,0xac, | |
0xe3,0x6c,0xd8,0x32,0x75,0x5c,0xdf,0x45,0xcf,0x0d,0xd6,0xdc,0x59,0x3d,0xd1,0xab, | |
0xac,0x30,0xd9,0x26,0x3a,0x00,0xde,0x51,0x80,0x51,0xd7,0xc8,0x16,0x61,0xd0,0xbf, | |
0xb5,0xf4,0xb4,0x21,0x23,0xc4,0xb3,0x56,0x99,0x95,0xba,0xcf,0x0f,0xa5,0xbd,0xb8, | |
0x9e,0xb8,0x02,0x28,0x08,0x88,0x05,0x5f,0xb2,0xd9,0x0c,0xc6,0x24,0xe9,0x0b,0xb1, | |
0x87,0x7c,0x6f,0x2f,0x11,0x4c,0x68,0x58,0xab,0x1d,0x61,0xc1,0x3d,0x2d,0x66,0xb6, | |
0x90,0x41,0xdc,0x76,0x06,0x71,0xdb,0x01,0xbc,0x20,0xd2,0x98,0x2a,0x10,0xd5,0xef, | |
0x89,0x85,0xb1,0x71,0x1f,0xb5,0xb6,0x06,0xa5,0xe4,0xbf,0x9f,0x33,0xd4,0xb8,0xe8, | |
0xa2,0xc9,0x07,0x78,0x34,0xf9,0x00,0x0f,0x8e,0xa8,0x09,0x96,0x18,0x98,0x0e,0xe1, | |
0xbb,0x0d,0x6a,0x7f,0x2d,0x3d,0x6d,0x08,0x97,0x6c,0x64,0x91,0x01,0x5c,0x63,0xe6, | |
0xf4,0x51,0x6b,0x6b,0x62,0x61,0x6c,0x1c,0xd8,0x30,0x65,0x85,0x4e,0x00,0x62,0xf2, | |
0xed,0x95,0x06,0x6c,0x7b,0xa5,0x01,0x1b,0xc1,0xf4,0x08,0x82,0x57,0xc4,0x0f,0xf5, | |
0xc6,0xd9,0xb0,0x65,0x50,0xe9,0xb7,0x12,0xea,0xb8,0xbe,0x8b,0x7c,0x88,0xb9,0xfc, | |
0xdf,0x1d,0xdd,0x62,0x49,0x2d,0xda,0x15,0xf3,0x7c,0xd3,0x8c,0x65,0x4c,0xd4,0xfb, | |
0x58,0x61,0xb2,0x4d,0xce,0x51,0xb5,0x3a,0x74,0x00,0xbc,0xa3,0xe2,0x30,0xbb,0xd4, | |
0x41,0xa5,0xdf,0x4a,0xd7,0x95,0xd8,0x3d,0x6d,0xc4,0xd1,0xa4,0xfb,0xf4,0xd6,0xd3, | |
0x6a,0xe9,0x69,0x43,0xfc,0xd9,0x6e,0x34,0x46,0x88,0x67,0xad,0xd0,0xb8,0x60,0xda, | |
0x73,0x2d,0x04,0x44,0xe5,0x1d,0x03,0x33,0x5f,0x4c,0x0a,0xaa,0xc9,0x7c,0x0d,0xdd, | |
0x3c,0x71,0x05,0x50,0xaa,0x41,0x02,0x27,0x10,0x10,0x0b,0xbe,0x86,0x20,0x0c,0xc9, | |
0x25,0xb5,0x68,0x57,0xb3,0x85,0x6f,0x20,0x09,0xd4,0x66,0xb9,0x9f,0xe4,0x61,0xce, | |
0x0e,0xf9,0xde,0x5e,0x98,0xc9,0xd9,0x29,0x22,0x98,0xd0,0xb0,0xb4,0xa8,0xd7,0xc7, | |
0x17,0x3d,0xb3,0x59,0x81,0x0d,0xb4,0x2e,0x3b,0x5c,0xbd,0xb7,0xad,0x6c,0xba,0xc0, | |
0x20,0x83,0xb8,0xed,0xb6,0xb3,0xbf,0x9a,0x0c,0xe2,0xb6,0x03,0x9a,0xd2,0xb1,0x74, | |
0x39,0x47,0xd5,0xea,0xaf,0x77,0xd2,0x9d,0x15,0x26,0xdb,0x04,0x83,0x16,0xdc,0x73, | |
0x12,0x0b,0x63,0xe3,0x84,0x3b,0x64,0x94,0x3e,0x6a,0x6d,0x0d,0xa8,0x5a,0x6a,0x7a, | |
0x0b,0xcf,0x0e,0xe4,0x9d,0xff,0x09,0x93,0x27,0xae,0x00,0x0a,0xb1,0x9e,0x07,0x7d, | |
0x44,0x93,0x0f,0xf0,0xd2,0xa3,0x08,0x87,0x68,0xf2,0x01,0x1e,0xfe,0xc2,0x06,0x69, | |
0x5d,0x57,0x62,0xf7,0xcb,0x67,0x65,0x80,0x71,0x36,0x6c,0x19,0xe7,0x06,0x6b,0x6e, | |
0x76,0x1b,0xd4,0xfe,0xe0,0x2b,0xd3,0x89,0x5a,0x7a,0xda,0x10,0xcc,0x4a,0xdd,0x67, | |
0x6f,0xdf,0xb9,0xf9,0xf9,0xef,0xbe,0x8e,0x43,0xbe,0xb7,0x17,0xd5,0x8e,0xb0,0x60, | |
0xe8,0xa3,0xd6,0xd6,0x7e,0x93,0xd1,0xa1,0xc4,0xc2,0xd8,0x38,0x52,0xf2,0xdf,0x4f, | |
0xf1,0x67,0xbb,0xd1,0x67,0x57,0xbc,0xa6,0xdd,0x06,0xb5,0x3f,0x4b,0x36,0xb2,0x48, | |
0xda,0x2b,0x0d,0xd8,0x4c,0x1b,0x0a,0xaf,0xf6,0x4a,0x03,0x36,0x60,0x7a,0x04,0x41, | |
0xc3,0xef,0x60,0xdf,0x55,0xdf,0x67,0xa8,0xef,0x8e,0x6e,0x31,0x79,0xbe,0x69,0x46, | |
0x8c,0xb3,0x61,0xcb,0x1a,0x83,0x66,0xbc,0xa0,0xd2,0x6f,0x25,0x36,0xe2,0x68,0x52, | |
0x95,0x77,0x0c,0xcc,0x03,0x47,0x0b,0xbb,0xb9,0x16,0x02,0x22,0x2f,0x26,0x05,0x55, | |
0xbe,0x3b,0xba,0xc5,0x28,0x0b,0xbd,0xb2,0x92,0x5a,0xb4,0x2b,0x04,0x6a,0xb3,0x5c, | |
0xa7,0xff,0xd7,0xc2,0x31,0xcf,0xd0,0xb5,0x8b,0x9e,0xd9,0x2c,0x1d,0xae,0xde,0x5b, | |
0xb0,0xc2,0x64,0x9b,0x26,0xf2,0x63,0xec,0x9c,0xa3,0x6a,0x75,0x0a,0x93,0x6d,0x02, | |
0xa9,0x06,0x09,0x9c,0x3f,0x36,0x0e,0xeb,0x85,0x67,0x07,0x72,0x13,0x57,0x00,0x05, | |
0x82,0x4a,0xbf,0x95,0x14,0x7a,0xb8,0xe2,0xae,0x2b,0xb1,0x7b,0x38,0x1b,0xb6,0x0c, | |
0x9b,0x8e,0xd2,0x92,0x0d,0xbe,0xd5,0xe5,0xb7,0xef,0xdc,0x7c,0x21,0xdf,0xdb,0x0b, | |
0xd4,0xd2,0xd3,0x86,0x42,0xe2,0xd4,0xf1,0xf8,0xb3,0xdd,0x68,0x6e,0x83,0xda,0x1f, | |
0xcd,0x16,0xbe,0x81,0x5b,0x26,0xb9,0xf6,0xe1,0x77,0xb0,0x6f,0x77,0x47,0xb7,0x18, | |
0xe6,0x5a,0x08,0x88,0x70,0x6a,0x0f,0xff,0xca,0x3b,0x06,0x66,0x5c,0x0b,0x01,0x11, | |
0xff,0x9e,0x65,0x8f,0x69,0xae,0x62,0xf8,0xd3,0xff,0x6b,0x61,0x45,0xcf,0x6c,0x16, | |
0x78,0xe2,0x0a,0xa0,0xee,0xd2,0x0d,0xd7,0x54,0x83,0x04,0x4e,0xc2,0xb3,0x03,0x39, | |
0x61,0x26,0x67,0xa7,0xf7,0x16,0x60,0xd0,0x4d,0x47,0x69,0x49,0xdb,0x77,0x6e,0x3e, | |
0x4a,0x6a,0xd1,0xae,0xdc,0x5a,0xd6,0xd9,0x66,0x0b,0xdf,0x40,0xf0,0x3b,0xd8,0x37, | |
0x53,0xae,0xbc,0xa9,0xc5,0x9e,0xbb,0xde,0x7f,0xcf,0xb2,0x47,0xe9,0xff,0xb5,0x30, | |
0x1c,0xf2,0xbd,0xbd,0x8a,0xc2,0xba,0xca,0x30,0x93,0xb3,0x53,0xa6,0xa3,0xb4,0x24, | |
0x05,0x36,0xd0,0xba,0x93,0x06,0xd7,0xcd,0x29,0x57,0xde,0x54,0xbf,0x67,0xd9,0x23, | |
0x2e,0x7a,0x66,0xb3,0xb8,0x4a,0x61,0xc4,0x02,0x1b,0x68,0x5d,0x94,0x2b,0x6f,0x2a, | |
0x37,0xbe,0x0b,0xb4,0xa1,0x8e,0x0c,0xc3,0x1b,0xdf,0x05,0x5a,0x8d,0xef,0x02,0x2d}; | |
void fread_or_die(void * a, size_t b, size_t c, FILE * d) | |
{ | |
size_t got = fread(a, b, c, d); | |
if(feof(d)) {puts("feof"); exit(0);} | |
if(ferror(d)) {puts("ferror"); exit(0);} | |
if(got != c) {exit(0);} | |
} | |
bool is_jis_surrogate(uint8_t c) | |
{ | |
if(c >= 0x80 and c <= 0xA0) return true; | |
if(c >= 0xE0) return true; | |
return false; | |
} | |
int main(int argc, char ** argv) | |
{ | |
//16 header | |
//4 ? | |
//4 ? | |
//4 num? | |
//8[num?] ? | |
//4 scriptsize | |
//1 script[scriptsize] | |
if(argc < 2) return puts("usage: unmjo file.mjo"), 0; | |
auto f = fopen(argv[1], "rb"); | |
char magic[16]; | |
fread(magic, 1, 16, f); | |
if(strncmp(magic, "MajiroObjX1.000", 16) != 0) return puts("unsupported file"), puts(argv[1]), 0; | |
uint32_t crap[2]; | |
fread(crap, 4, 2, f); | |
uint32_t numoffsets; | |
fread(&numoffsets, 4, 1, f); | |
for(uint32_t i = 0; i < numoffsets; i++) | |
{ | |
uint32_t offsetdata[2]; | |
fread(offsetdata, 4, 2, f); | |
} | |
uint32_t length; | |
fread(&length, 4, 1, f); | |
unsigned char * data = (unsigned char *)malloc(length); | |
fread(data, 1, length, f); | |
uint32_t i = 0; | |
while(i < length) | |
{ | |
data[i] ^= key[i%1024]; | |
i++; | |
} | |
auto f2 = fopen((std::string(argv[1])+".script.txt").data(), "wb"); | |
//auto f2 = fopen((std::string(argv[1])+".dec").data(), "wb"); | |
i = 0; | |
auto fake_fread = [data, &i, length](void * write, int size, int num) | |
{ | |
if(i >= length) exit(0); | |
unsigned char * real_write = (unsigned char *)write; | |
for(int j = 0; j < size*num; j++) | |
{ | |
real_write[j] = data[i]; | |
i++; | |
} | |
}; | |
auto fake_fgetc = [data, &i, length]() | |
{ | |
if(i >= length) exit(0); | |
return data[i++]; | |
}; | |
int furigana_length = 0; | |
std::string internal_text(""); | |
while(!ferror(f) and !feof(f)) | |
{ | |
uint16_t n; | |
fake_fread(&n, 2, 1); | |
// 083A XXXX: line in original code? | |
// 0840 XXXX: content text of length XXXX | |
// 0801 XXXX: internal text of length XXXX (also used for furigana) | |
// 0841: after content text, always occurs, but sometimes before it too, no idea what it does | |
// 0810: followed by two shorts, seem to dictate what to do with the significance of whatever's on the stack: | |
// - FDF0 812A F0 FD 2A 81 speech file | |
// - FD01 3198 01 FD 98 31 furigana | |
// - EE67 0836 67 EE 36 08 triggers (allows?) a wait for input (also affects auto mode's wait timer) | |
// further followed by three shorts, the first two are blank in the file but modified at runtime. | |
// if, at runtime, you change the 0810 "command" but not the rewritten shorts, it will continue to act like the old command. | |
// example: | |
// F0 FD 2A 81 -> 25 D6 FE 07 | |
// 01 FD 98 31 -> B6 1C FF 07 | |
// 67 EE 36 08 -> D5 0C FF 07 | |
// the last of the three shorts seems to be 0 or 1, sometimes 2. stack usage? | |
// similar to 0810: 080F, 0835 | |
// 0842: text control? | |
// 0842 0002 XXXX (?), where | |
// 006E : new line. waits for input. fucks up the backlog if you use it multiple times in a row | |
// 0070 : wait for input, even twice if you use it multiple times in a row | |
// 0077 : new page, move to upper left | |
// normally 0070 and 0077 are run in that order together | |
// but if you replace the 0070 with 0077 it doesn't seem to change anything. | |
// | |
if(n == 0x0810 or n == 0x080F) | |
{ | |
uint16_t a[5]; | |
fake_fread(a, 2, 5); | |
if(a[0] == 0xFD01 and a[1] == 0x3198) | |
{ | |
// 〈〉《》 | |
// 8171234 | |
fputs("\x81\x73", f2); | |
bool last_char_first_surrogate = false; | |
int chars_printed = 0; | |
for(char c : internal_text) | |
{ | |
//if(c == '\\' and !is_jis_surrogate(last_c)) | |
//{ | |
// fputc('\\', f2); | |
// fputc('\\', f2); | |
//} | |
//else | |
fputc(c, f2); | |
if(is_jis_surrogate(c) and !last_char_first_surrogate) | |
{ | |
last_char_first_surrogate = true; | |
} | |
else | |
{ | |
last_char_first_surrogate = false; | |
chars_printed++; | |
} | |
} | |
fputs("\x81\x74", f2); | |
furigana_length = chars_printed; | |
internal_text.assign(""); | |
} | |
} | |
else if(n == 0x0842) | |
{ | |
uint16_t a[2]; | |
fake_fread(a, 2, 2); | |
if(a[1] == 0x0077 or a[1] == 0x006E) | |
fputc('\n', f2); | |
if(a[1] == 0x0077) // double newline for new page | |
fputc('\n', f2); | |
} | |
else if(n == 0x0840 or n == 0x0801) | |
{ | |
if(n == 0x0801) | |
internal_text.assign(""); | |
uint16_t len; | |
fake_fread(&len, 2, 1); | |
bool last_char_first_surrogate = 0; | |
if(furigana_length != 0) | |
fputs("\x81\x71", f2); | |
int chars_printed = 0; | |
for(int i = 0; i < len; i++) | |
{ | |
uint8_t c = fake_fgetc(); | |
if(c == 0) | |
{ } | |
else | |
{ | |
if(n == 0x0801) | |
{ | |
internal_text += c; | |
} | |
//else if(c == '\\' and !is_jis_surrogate(last_c)) | |
//{ | |
// fputc('\\', f2); | |
// fputc('\\', f2); | |
//} | |
else | |
fputc(c, f2); | |
} | |
if(is_jis_surrogate(c) and !last_char_first_surrogate) | |
{ | |
last_char_first_surrogate = true; | |
} | |
else | |
{ | |
last_char_first_surrogate = false; | |
chars_printed++; | |
} | |
if(furigana_length != 0 and chars_printed*3 > furigana_length and !last_char_first_surrogate) // This is a hack since I don't know how/if the engine keeps track of hiragana width in fullwidth characters. Gives the right results on sr001.mjo. | |
{ | |
fputs("\x81\x72", f2); | |
furigana_length = 0; | |
} | |
} | |
furigana_length = 0; | |
} | |
// ensure program counter is consistent | |
else if(n == 0x083A) | |
{ | |
uint16_t a[1]; | |
fake_fread(a, 2, 1); | |
} | |
else if(n == 0x0841 or n == 0x082F or n == 0x082B) | |
{ | |
} | |
else if(n == 0x0836) | |
{ | |
uint8_t a[3]; | |
fake_fread(a, 1, 3); | |
} | |
else if(n == 0x0802 or n == 0x01B0 or n == 0x01D0) | |
{ | |
uint16_t a[4]; | |
fake_fread(a, 2, 4); | |
} | |
else if(n == 0x0829) | |
{ | |
uint16_t a[1]; | |
fake_fread(a, 2, 1); | |
} | |
else if(n == 0x0800 or n == 0x082C or n == 0x0830 or n == 0x0831) | |
{ | |
uint16_t a[2]; | |
fake_fread(a, 2, 2); | |
} | |
else if(n == 0x0835) | |
{ | |
uint16_t a[3]; | |
fake_fread(a, 2, 3); | |
} | |
else if(n == 0x0148 or n == 0x0158) | |
{ | |
uint16_t a[3]; | |
fake_fread(a, 2, 3); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment