/*
Visual Studio Community 2017
Visual C++ / 空のプロジェクト
全般 / 文字セット = マルチバイト文字セット
C/C++ / コード生成 / ランタイム ライブラリ = (構成:Release) マルチスレッド(/MT)
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <Windows.h>
// 関数プロトタイプ宣言
void create_t88file(char *filename);
void write_tag(WORD id, WORD len);
void write_tick(DWORD tick);
void write_bytes(DWORD bytes, int len);
void write_ver(WORD ver);
void write_data_tag(WORD len);
void write_space(DWORD tick);
void write_mark(DWORD tick);
void write_filename(const char *filename);
void write_data(WORD start, int datlen);
void write_data_check(BYTE *buf, int len);
// グローバル変数
char t88file[_MAX_PATH];
FILE *pfin; // 入力ファイルポインタ
FILE *pfout; // 出力ファイルポインタ
DWORD dur; // 経過tick
int main(int argc, char *argv[])
{
if (argc != 4) {
fprintf(stderr, "usage: bin2t88 ファイル名 開始アドレス バイナリファイル\n");
fprintf(stderr, "ex) bin2t88 SAMPLE b000 filename.bin\n");
return 1;
}
char *filename = argv[1];
WORD start = (WORD)strtol(argv[2], nullptr, 16); // HHHH or 0xHHHH
char *binfile = argv[3];
create_t88file(binfile);
struct _stat st;
if (_stat(binfile, &st)) {
perror(binfile);
return 1;
}
if (fopen_s(&pfin, binfile, "rb")) {
perror(binfile);
return 1;
}
if (fopen_s(&pfout, t88file, "wb")) {
perror(t88file);
return 1;
}
dur = 0;
fwrite("PC-8801 Tape Image(T88)", 1, 24, pfout); // ファイルヘッダ
write_ver(0x0100); // バージョンタグ
write_space(7928);
write_mark(1322);
write_filename(filename); // ファイル名
write_mark(330);
write_data(start, st.st_size); // データ
write_mark(3966);
write_space(9252);
write_tag(0x0000, 0); // 終了タグ
_fcloseall();
return 0;
}
void create_t88file(char *filename)
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath_s(filename, drive, dir, fname, ext);
_makepath_s(t88file, drive, dir, fname, ".t88");
}
void write_tag(WORD id, WORD len)
{
WORD buf[2] = { id, len };
fwrite(buf, 2, 2, pfout);
}
void write_tick(DWORD tick)
{
DWORD buf[2] = { dur, tick };
fwrite(buf, 4, 2, pfout);
dur += tick;
}
void write_bytes(DWORD bytes, int len)
{
fwrite(&bytes, 1, len, pfout);
}
// バージョン
void write_ver(WORD ver)
{
write_tag(0x0001, 2);
write_bytes(ver, 2);
}
// データタグ
void write_data_tag(WORD datlen)
{
WORD buf[2] = { datlen, 0x01cc };
write_tag(0x0101, 12 + datlen);
write_tick(44 * datlen);
fwrite(buf, 2, 2, pfout);
}
// スペース(0)
void write_space(DWORD tick)
{
write_tag(0x0102, 8);
write_tick(tick);
}
// マーク(1)
void write_mark(DWORD tick)
{
write_tag(0x0103, 8);
write_tick(tick);
}
void write_filename(const char *filename)
{
char buf[9 + 1];
sprintf_s(buf, "$$$%-6.6s", filename);
write_data_tag(9);
fwrite(buf, 1, 9, pfout);
}
void write_data(WORD start, int datlen)
{
BYTE buf[256];
WORD blk = (datlen + 127) / 128;
write_data_tag(datlen + 7 + 3 * blk);
// 開始アドレス
buf[0] = HIBYTE(start);
buf[1] = LOBYTE(start);
write_data_check(buf, 2);
// データ
while (true) {
size_t read = fread(buf + 1, 1, 128, pfin);
if (!read) break;
buf[0] = (BYTE)read;
write_data_check(buf, read + 1);
}
// 終了
write_bytes(0x3a003a, 3);
}
void write_data_check(BYTE *buf, int len)
{
int sum = 0;
for (int i = 0; i < len; i++) {
sum += buf[i];
}
BYTE check = 0x100 - (sum & 0xff); // チェックバイト
write_bytes(0x3a, 1);
fwrite(buf, 1, len, pfout);
write_bytes(check, 1);
}