/*
 *	dsrf2rom - SRF to ROMイメージ コンバータ
 *	Copyright (C) 2003 Naoyuki Sawa
 *
 *	* Sat Sep 13 22:29:00 JST 2003 Naoyuki Sawa
 *	- 1st リリース。
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "srf33.h"

#define VERSION	"20030913"

/****************************************************************************
 *	
 ****************************************************************************/

char srf_path[_MAX_PATH];	/* 入力srfファイルのパス名 */
char rom_path[_MAX_PATH];	/* 出力romファイルのパス名 */

unsigned int top;	/* ROMイメージ開始アドレス     */
unsigned int end;	/* ROMイメージ終了アドレス(+1) */
unsigned char* rom;	/* ROMイメージ */

void usage();
void cmdline(int argc, char* argv[]);
void load_srf();
void save_rom();

/****************************************************************************
 *	main
 ****************************************************************************/

int
main(int argc, char* argv[])
{
	/* 構造体のバイトアライメントが正しくコンパイルされていることを確認。 */
	if(sizeof(SRF33_CONTROL_HEADER     ) != SIZEOF_SRF33_CONTROL_HEADER     ) abort();
	if(sizeof(SRF33_SECTION_INFORMATION) != SIZEOF_SRF33_SECTION_INFORMATION) abort();

	/* コマンドライン解析。 */
	cmdline(argc, argv);

	/* srfファイルを読み込む。 */
	load_srf();

	/* romファイルを書き込む。 */
	save_rom();

	return 0;
}

/****************************************************************************
 *	usage
 ****************************************************************************/

void
usage()
{
	fprintf(stderr, "dsrf2rom - SRF to ROMimage converter (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2003 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "    dsrf2rom <filename[.srf]>\n");
	exit(1);
}

/****************************************************************************
 *	cmdline
 ****************************************************************************/

void
cmdline(int argc, char* argv[])
{
	char drive[_MAX_DRIVE];
	char dir[_MAX_DIR];
	char fname[_MAX_FNAME];
	char ext[_MAX_EXT];

	if(argc != 1 + 1) usage();

	/* 入出力ファイルのパス名を取得。 */
	_splitpath(argv[1], drive, dir, fname, ext);
	if(!*ext) strcpy(ext, ".srf"); /* 入力ファイルの拡張子が省略されていたら".srf"を補う */
	_makepath(srf_path, drive, dir, fname, ext);
	_makepath(rom_path, drive, dir, fname, ".rom"); /* 出力ファイルの拡張子は".rom"固定 */
}

/****************************************************************************
 *	load_srf
 ****************************************************************************/

void
load_srf()
{
	int retval;
	unsigned int scnptr, scntyp, off, rdptr, dsiz;
	FILE* fp;
	SRF33_CONTROL_HEADER ch;
	SRF33_SECTION_INFORMATION si;

	printf("%sを読み込みます...\n", srf_path);

	/* ファイルを開く。 */
	fp = fopen(srf_path, "rb");
	if(!fp) {
		fprintf(stderr, "srfファイルが開けません。\n");
		exit(1);
	}

	/* srf33制御ヘッダを読み込む。 */
	retval = fread(&ch, 1, SIZEOF_SRF33_CONTROL_HEADER, fp);
	if(retval != SIZEOF_SRF33_CONTROL_HEADER) {
		fprintf(stderr, "srf33制御ヘッダが読み込めません。\n");
		exit(1);
	}

	/* 最初のセクション情報へのチェイン。 */
	scnptr = SRF33_WORD(ch.c_scnptr);

	/* セクション情報チェインの終端に達するまで... */
	while(scnptr) {
		/* セクション情報を読み込む。 */
		retval = fseek(fp, scnptr, SEEK_SET);
		if(retval) {
			fprintf(stderr, "セクション情報へシークできません。\n");
			exit(1);
		}
		retval = fread(&si, 1, SIZEOF_SRF33_SECTION_INFORMATION, fp);
		if(retval != SIZEOF_SRF33_SECTION_INFORMATION) {
			fprintf(stderr, "セクション情報が読み込めません。\n");
			exit(1);
		}

		/* セクション情報から必要なフィールドを取得。 */
		scnptr = SRF33_WORD(si.s_nxptr );
		scntyp = SRF33_HALF(si.s_scntyp);
		off    = SRF33_WORD(si.s_off   );
		rdptr  = SRF33_WORD(si.s_rdptr );
		dsiz   = SRF33_WORD(si.s_dsiz  );
		if(dsiz) { /* 実データサイズが0のセクションはスキップする */
			/* セクション情報表示。 */
			switch(scntyp) {
			case 1: printf("  CODE: "); break;
			case 2: printf("  DATA: "); break;
			case 3: printf("  BSS : "); break;
			case 4: printf("  ﾀﾞﾐｰ: "); break;
			default:
				fprintf(stderr, "不明なセクションタイプです。\n");
				exit(1);
			}
			printf("%07x - %07x\n", off, off + dsiz - 1);

			/* CODEとDATAセクション以外はスキップする。 */
			switch(scntyp) {
			case 1: break;
			case 2: break;
			default: continue;
			}

			/* 実データを読みこむためのメモリを確保。 */
			if(!top) {
				top = off;
			} else {
				if(off < top) {
					fprintf(stderr, "セクションの先頭アドレスが後退しています。\n");
					exit(1);
				}
				if(off < end) {
					fprintf(stderr, "セクションのアドレス範囲が重複しています。\n");
					exit(1);
				}
			}
			end = off + dsiz;
			rom = realloc(rom, end - top);
			if(rom == NULL) {
				fprintf(stderr, "セクションを読み込むためのメモリが確保できません。\n");
				exit(1);
			}

			/* 実データを読み込む。 */
			retval = fseek(fp, rdptr, SEEK_SET);
			if(retval) {
				fprintf(stderr, "実データへシークできません。\n");
				exit(1);
			}
			retval = fread(rom + (off - top), 1, dsiz, fp);
			if(retval != (int)dsiz) {
				fprintf(stderr, "実データが読み込めません。\n");
				exit(1);
			}
		}
	}

	/* ファイルを閉じる。 */
	fclose(fp);
}

/****************************************************************************
 *	save_rom
 ****************************************************************************/

void
save_rom()
{
	int retval;
	FILE* fp;

	printf("%sを作成します...\n", rom_path);

	/* ファイルを作成する。 */
	fp = fopen(rom_path, "wb");
	if(!fp) {
		fprintf(stderr, "romファイルが作成できません。\n");
		exit(1);
	}

	/* ROM情報を表示。 */
	printf("  ROM : %07x - %07x\n", top, end - 1);

	/* ROMイメージを書き込む。 */
	retval = fwrite(rom, 1, end - top, fp);
	if(retval != (int)(end - top)) {
		fprintf(stderr, "ROMイメージが書き込めません。\n");
		exit(1);
	}

	/* ファイルを閉じる。 */
	fclose(fp);
}
