/*	
 *	dbin2o.exe - バイナリ⇒srf33オブジェクトファイル変換ユーティリティ
 *
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Thu Jun 11 01:41:08 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	  clip/tool/dbin2c/を元にして作成しました。
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

/* [NOTE]
 * * コマンドライン引数のワイルドカードを展開するために、
 *   [プロジェクトの設定]->[リンク]->[オブジェクト/ライブラリモジュール]に
 *   「setargv.obj」を追加しています。
 *   ただし、本プログラムは複数の入力ファイルを受け付けないので、
 *   ワイルドカード展開はコマンド入力の手間を省く程度の目的に過ぎません。
 */

#define VERSION		"20150611"

/* エラーメッセージを表示して終了します。
 * [in]
 *	fmt		書式文字列。
 *	...		パラメータ。
 */
void
err(const char* fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	 fprintf(stderr, "### ");
	vfprintf(stderr, fmt, ap);
	 fprintf(stderr, "\n");
	va_end(ap);
	exit(EXIT_FAILURE);
}

/* 使い方を表示して終了します。
 */
void
usage()
{
	fprintf(stderr, "dbin2o.exe - バイナリ⇒srf33オブジェクトファイル変換ユーティリティ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2015 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "使い方: dbin2o.exe infile [outfile[.o]]\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "  infile         入力バイナリファイル名を指定します。(必須)\n");
	fprintf(stderr, "  [outfile[.o]]  出力オブジェクトファイル名を指定します。(省略可)\n");
	fprintf(stderr, "                 出力オブジェクトファイル名を省略した場合は、入力ファイル名の拡張子を.oに変えたファイル名とします。\n");
	fprintf(stderr, "                 出力オブジェクトファイル名のベース名を指定して拡張子を省略した場合は、自動的に拡張子.oを補います。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "注意点: 当ツールは、エクスターン情報を出力しません。\n");
	fprintf(stderr, "        アプリケーションプログラムがデータのアドレスを得るには、__START_outfile_code を参照してください。\n");
	exit(EXIT_FAILURE);
}

char infile[_MAX_PATH];		/* 入力バイナリファイル名 */
char outfile[_MAX_PATH];	/* 出力オブジェクトファイル名 */

unsigned char hdr[]={
//srf33制御ヘッダ
0x00,0x01,			//c_fatt	ファイル制御フラグ
0x00,0x00,			//c_pentry	エントリーアドレス
0x33,0x00,			//c_ver		srf33バージョン情報
0x00,0x03,			//c_scncnt	セクション情報数			//CODE,DATA,BSSが全て必須であり、空でも出力しなければならない。どれか1つでも足りないと、lk33.exeを実行した時にエラーになる。
0x00,0x00,0x00,0x10,		//c_scnptr	セクション情報チェーン
0x00,0x00,0x00,0x00,		//c_debptr	デバッグ制御情報チェーン
//セクション情報(CODE)
0x00,0x00,0x00,0x3C,		//s_nxptr	次のセクション情報へのチェーン
0x00,0x01,			//s_scntyp	セクションタイプ
0x00,0x00,			//s_lnktyp	リンク方法
0x00,0x01,			//s_scnatt	セクション属性
0x00,0x00,0x00,0x00,		//s_off		セクションのスタートアドレス
0x00,0x00,0x00,0x00,		//s_rcptr	リロケーション情報チェーン
0x00,0x00,0x00,0x00,		//s_rcsiz	リロケーション情報バイトサイズ
0x00,0x00,0x00,0x00,		//s_exptr	エクスターン情報チェーン
0x00,0x00,0x00,0x00,		//s_exsiz	エクスターン情報バイトサイズ
0x00,0x00,0x00,0x00,		//s_excnt	エクスターン情報の個数
0x00,0x00,0x00,0x94,		//s_rdptr	実データへのチェーン
0x00,0x00,0x00,0x00,		//s_dsiz	実データバイトサイズ			←←←ここを書き換える。バイトオフセット=54、ビッグエンディアン
0x00,0x00,			//s_scnndx	セクションID
//セクション情報(DATA)									┐
0x00,0x00,0x00,0x68,		//s_nxptr	次のセクション情報へのチェーン		│
0x00,0x02,			//s_scntyp	セクションタイプ			│
0x00,0x00,			//s_lnktyp	リンク方法				│
0x00,0x01,			//s_scnatt	セクション属性				│
0x00,0x00,0x00,0x00,		//s_off		セクションのスタートアドレス		│
0x00,0x00,0x00,0x00,		//s_rcptr	リロケーション情報チェーン		│
0x00,0x00,0x00,0x00,		//s_rcsiz	リロケーション情報バイトサイズ		│
0x00,0x00,0x00,0x00,		//s_exptr	エクスターン情報チェーン		│
0x00,0x00,0x00,0x00,		//s_exsiz	エクスターン情報バイトサイズ		│
0x00,0x00,0x00,0x00,		//s_excnt	エクスターン情報の個数			│
0x00,0x00,0x00,0x00,		//s_rdptr	実データへのチェーン			│
0x00,0x00,0x00,0x00,		//s_dsiz	実データバイトサイズ			│
0x00,0x01,			//s_scnndx	セクションID				│
//セクション情報(BSS)									│CODE,DATA,BSSが全て必須であり、空でも出力しなければならない。どれか1つでも足りないと、lk33.exeを実行した時にエラーになる。
0x00,0x00,0x00,0x00,		//s_nxptr	次のセクション情報へのチェーン		│
0x00,0x03,			//s_scntyp	セクションタイプ			│
0x00,0x00,			//s_lnktyp	リンク方法				│
0x00,0x01,			//s_scnatt	セクション属性				│
0x00,0x00,0x00,0x00,		//s_off		セクションのスタートアドレス		│
0x00,0x00,0x00,0x00,		//s_rcptr	リロケーション情報チェーン		│
0x00,0x00,0x00,0x00,		//s_rcsiz	リロケーション情報バイトサイズ		│
0x00,0x00,0x00,0x00,		//s_exptr	エクスターン情報チェーン		│
0x00,0x00,0x00,0x00,		//s_exsiz	エクスターン情報バイトサイズ		│
0x00,0x00,0x00,0x00,		//s_excnt	エクスターン情報の個数			│
0x00,0x00,0x00,0x00,		//s_rdptr	実データへのチェーン			│
0x00,0x00,0x00,0x00,		//s_dsiz	実データバイトサイズ			│
0x00,0x02,			//s_scnndx	セクションID				┘
};

int
main(int argc, char* argv[])
{
	char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
	FILE* fp;
	int len;
	unsigned char* buf;

	/* コマンドライン解析。 */
	switch(argc - 1/*コマンド名を除いた引数の数*/) {
	case 1:
		/*** 入力バイナリファイル名のみ指定 ***/
		/* 入力バイナリファイル名を格納します。 */
		strncpy(infile, argv[1], sizeof infile - 1);
		/* 出力オブジェクトファイル名を作成します。 */
		_splitpath(infile, drive, dir, fname, ext);
		_makepath(outfile, drive, dir, fname, ".o");
		break;
	case 2:
		/*** 入力バイナリファイル名と出力オブジェクトファイル名を指定 ***/
		/* 入力バイナリファイル名を格納します。 */
		strncpy(infile, argv[1], sizeof infile - 1);
		/* 出力オブジェクトファイル名を格納します。 */
		strncpy(outfile, argv[2], sizeof outfile - 1);
		_splitpath(outfile, drive, dir, fname, ext);
		if(!ext[0]) { _makepath(outfile, drive, dir, fname, ".o"); }
		break;
	default:
		usage();
	}

	/* 入力バイナリファイルを読み込みます。 */
	fp = fopen(infile, "rb"); /* バイナリモード必須!! */
	if(!fp) { err("%s が開けません。", infile); }
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	rewind(fp);
	buf = malloc(len);
	fread(buf, 1, len, fp);
	fclose(fp);

	/* 出力オブジェクトファイルを作成します。 */
	fp = fopen(outfile, "wb"); /* バイナリモード必須!! */
	if(!fp) { err("%s が作成できません。", outfile); }

	/* ヘッダを出力します。 */
	hdr[54 + 0] = len >> 24;
	hdr[54 + 1] = len >> 16;
	hdr[54 + 2] = len >>  8;
	hdr[54 + 3] = len >>  0;
	fwrite(hdr, 1, sizeof hdr, fp);

	/* データを出力します。 */
	fwrite(buf, 1, len, fp);

	/* 出力オブジェクトファイルを閉じます。 */
	fclose(fp);

	return EXIT_SUCCESS;
}
