/* * fontx2msx.c * * original code by SASANO Takayoshi * --- public domain, no warranty. */ #include #include #include /* FONTX2 header */ #define CODETYPE_ASCII 0 #define CODETYPE_KANJI 1 /* common */ typedef struct { unsigned char identifier[6]; unsigned char fontname[8]; unsigned char xsize; unsigned char ysize; unsigned char codetype; } __attribute__((packed)) FONTX2_HEADER; /* ascii */ typedef struct { FONTX2_HEADER h; unsigned char d[1]; } __attribute__((packed)) FONTX2_ASCII; /* sjis */ typedef struct { FONTX2_HEADER h; unsigned char tnum; unsigned char d[1]; } __attribute__((packed)) FONTX2_KANJI; typedef struct { unsigned short start; unsigned short end; } __attribute__((packed)) FONTX2_CODETABLE; /* ROM data buffer */ #define BUFFERSIZE 262144 static unsigned char RomData[BUFFERSIZE]; static unsigned char font_815e[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x00, }; static unsigned char font_815f[] = { 0x00, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, }; /* convert a kanji characger */ static void convert_kanji_char(unsigned char *in, unsigned char *out) { int i; for (i = 0; i < 8; i++) { out[i + 0] = in[i * 2 + 0]; out[i + 8] = in[i * 2 + 1]; out[i + 16] = in[i * 2 + 16]; out[i + 24] = in[i * 2 + 17]; } return; } /* convert an ANK character */ static void convert_ank_char(unsigned char *in, unsigned char *out, int height, int right) { int i; unsigned char buf[16]; memset(buf, 0, sizeof(buf)); memcpy(buf + sizeof(buf) - height, in, height); for (i = 0; i < 8; i++) { out[i + 0 + right * 8] = buf[i + 0]; out[i + 16 + right * 8] = buf[i + 8]; } return; } /* SJIS -> JIS */ static int _mbcjmstojis(int jms) { int low, high; high = (jms >> 8) & 0xff; low = jms & 0xff; if (low < 0x9f) { if (high < 0xa0) { high -= 0x81; high *= 2; high += 0x21; } else { high -= 0xe0; high *= 2; high += 0x5f; } if (low > 0x7f) low--; low -= 0x1f; } else { if (high < 0xa0) { high -= 0x81; high *= 2; high += 0x22; } else { high -= 0xe0; high *= 2; high += 0x60; } low -= 0x7e; } return (high << 8) | low; } /* get kanji font pointer */ static unsigned char *get_kanji_pointer(int sjis) { int kuten, ku, ten, idx, offset; kuten = _mbcjmstojis(sjis) - 0x2020; ku = (kuten >> 8) & 0xff; ten = kuten & 0xff; /* invalid */ if (ku >= 96 || ten >= 96) return NULL; /* no convert */ if (ku == 0 || (ku > 8 && ku < 16)) return NULL; if (ku < 48) { idx = ku * 96 + ten - (ku >= 16) * 512; offset = 0; } else { idx = (ku - 48) * 96 + ten; offset = 0x00020000; } return RomData + offset + 32 * idx; } /* convert ank font */ void convert_ank_font(void *buf, int right) { int i; FONTX2_ASCII *a = buf; unsigned char *p; if (a->h.codetype != CODETYPE_ASCII || (a->h.xsize + 7) / 8 != 1 || a->h.ysize > 16) { printf("invalid font data (ANK)\n"); return; } for (i = 0x20; i < 0x80; i++) { p = RomData + (i - 0x20) * 32; convert_ank_char(&a->d[i * a->h.ysize], p, a->h.ysize, right); } for (i = 0xa0; i < 0xe0; i++) { p = RomData + (i - 0xa0 + 96 * 9) * 32; convert_ank_char(&a->d[i * a->h.ysize], p, a->h.ysize, right); } return; } /* convert kanji font */ void convert_kanji_font(void *buf) { int i, j; FONTX2_KANJI *k = buf; FONTX2_CODETABLE *c = (FONTX2_CODETABLE *)&k->d[0]; unsigned char *d = &k->d[sizeof(FONTX2_CODETABLE) * k->tnum]; unsigned char *p; if (k->h.codetype != CODETYPE_KANJI || (k->h.xsize + 7) / 8 != 2 || k->h.ysize != 16) { printf("invalid font data (kanji)\n"); return; } for (i = 0; i < k->tnum; i++) { for (j = c[i].start; j <= c[i].end; j++) { p = get_kanji_pointer(j); if (p != NULL) { convert_kanji_char(d, get_kanji_pointer(j)); } d += 32; } } return; } /* fix JIS1 font to recognize MSX kanji ROM */ void fix_jis1data(void) { unsigned char *p; p = get_kanji_pointer(0x815f); convert_kanji_char(font_815f, p); /* this is not required, but it should be same style */ p = get_kanji_pointer(0x815e); convert_kanji_char(font_815e, p); return; } /* load file */ unsigned char *loadfile(char *filename) { FILE *fp; int size; unsigned char *buf = NULL; fp = fopen(filename, "r"); if (fp == NULL) { printf("loadfile: file open error (%s)\n", filename); goto fin0; } fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); buf = malloc(size); if (buf == NULL) { printf("loadfile: memory allocation error (%s)\n", filename); goto fin0; } if (fread(buf, size, 1, fp) < 1) { printf("loadfile: file read error (%s)\n", filename); free(buf); buf = NULL; } fclose(fp); fin0: return buf; } /* save file */ void savefile(char *filename, char *buf, int size) { FILE *fp; fp = fopen(filename, "w"); if (fp == NULL) { printf("savefile: file open error (%s)\n", filename); goto fin0; } if (fwrite(buf, size, 1, fp) < 1) { printf("savefile: file write error (%s)\n", filename); } fclose(fp); fin0: return; } /* entry */ int main(int argc, char *argv[]) { int result; unsigned char *buf; if (argc < 5) { printf("usage: %s [ank(normal)] [ank(small)] [kanji] [romfile]\n", argv[0]); result = EXIT_FAILURE; goto fin0; } memset(RomData, ~0, sizeof(RomData)); buf = loadfile(argv[1]); if (buf != NULL) { convert_ank_font(buf, 0); free(buf); } buf = loadfile(argv[2]); if (buf != NULL) { convert_ank_font(buf, 1); free(buf); } buf = loadfile(argv[3]); if (buf != NULL) { convert_kanji_font(buf); free(buf); } fix_jis1data(); savefile(argv[4], RomData, sizeof(RomData)); result = EXIT_SUCCESS; fin0: return result; }