開発環境 Microsoft Visual Studio Community 2017
実行環境 Microsoft Windows 10 Home (64bit)
プロジェクトの種類 Visual C++ / 空のプロジェクト
プロジェクト名 bin2t88

T88ファイル確認用
t88view

参考
Manuke Station : T88Format http://www.cug.net/~manuke/t88format.html

Enri's Home PAGE (PC-8001)http://www43.tok2.com/home/cmpslv/Pc80/Pcsio.htm

bin2t88.cpp
/*
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);
}
 
最終更新:2018年07月23日 18:03