#include "app.h"
/****************************************************************************
 *	
 ****************************************************************************/
__declspec(noreturn) static void usage();
static void dumpKeyBody(int indent, const unsigned char* keyBody);
static void printIndent(int indent, const char* fmt, ...);
/****************************************************************************
 *	
 ****************************************************************************/
int main(int argc, char* argv[]) {
	FILE* fp;
	void* buf;
	int opt, len;
	//コマンドラインオプションを処理する。
	opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
	while((opt = getopt(argc, argv, "h")) != -1) {
		switch(opt) {
		case 'h':
		default:
			usage();
		}
	}
	//レジストリテーブルのバイナリデータを読み込む。
	if(optind != (argc - 1)) { usage(); }	//引数の数が不正
	fp = fopen(argv[optind], "rb");
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	rewind(fp);
	buf = malloc(len);
	if(!buf) { DIE(); }	//メモリ不足
	fread(buf, 1, len, fp);
	fclose(fp);
	//レジストリテーブルをダンプする。
	dumpKeyBody(0, buf);
	return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dRegTblD - レジストリテーブル逆コンパイラ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2015 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dRegTblD [option] RegTbl.bin\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -h 使い方を表示します。\n");
	exit(EXIT_FAILURE);
}
/*--------------------------------------------------------------------------*/
//{{2015/09/22変更:clipreg.cに「インデクスアクセス型,及び,イテレーション用の関数」を追加した事に伴い、レジストリテーブルのバイナリを直接解析するのでなく、左記の関数を利用するように変更しました。実行結果はこれまでと変わりません。
//static void dumpKeyBody(int indent, const unsigned char* keyBody) {
//	//--- キー ---
//	{
//		int nKey, keyName, keyBodyDist;
//		nKey      = *keyBody++;				//┐
//		nKey    <<= 8;					//├符号無し16ビット,ビッグエンディアン
//		nKey     |= *keyBody++;				//┘
//		while(--nKey >= 0) {
//			keyName       =       *keyBody++;	//┐
//			keyName     <<= 8;			//├符号無し16ビット,ビッグエンディアン
//			keyName      |=       *keyBody++;	//┘
//			keyBodyDist   = (char)*keyBody++;	//┐
//			keyBodyDist <<= 8;			//│
//			keyBodyDist  |=       *keyBody++;	//├符号有り24ビット,ビッグエンディアン
//			keyBodyDist <<= 8;			//│
//			keyBodyDist  |=       *keyBody++;	//┘
//			printIndent(indent, "%u", keyName);
//			dumpKeyBody(indent + 1, keyBody + keyBodyDist);
//			printIndent(indent, "end");
//		}
//	}
//	//--- 値 ---
//	{
//		int nValue, valueName, valueData;
//		nValue    = *keyBody++;				//┐
//		nValue  <<= 8;					//├符号無し16ビット,ビッグエンディアン
//		nValue   |= *keyBody++;				//┘
//		while(--nValue >= 0) {
//			valueName     =       *keyBody++;	//┐
//			valueName   <<= 8;			//├符号無し16ビット,ビッグエンディアン
//			valueName    |=       *keyBody++;	//┘
//			valueData     =       *keyBody++;	//┐
//			valueData   <<= 8;			//├符号無し16ビット,ビッグエンディアン
//			valueData    |=       *keyBody++;	//┘
//			printIndent(indent, "%u\t=\t%u", valueName, valueData);
//		}
//	}
//	//--- 文字列 ---
//	{
//		int nString, stringName, stringDist;
//		nString   = *keyBody++;				//┐
//		nString <<= 8;					//├符号無し16ビット,ビッグエンディアン
//		nString  |= *keyBody++;				//┘
//		while(--nString >= 0) {
//			stringName    =       *keyBody++;	//┐
//			stringName  <<= 8;			//├符号無し16ビット,ビッグエンディアン
//			stringName   |=       *keyBody++;	//┘
//			stringDist    = (char)*keyBody++;	//┐
//			stringDist  <<= 8;			//│
//			stringDist   |=       *keyBody++;	//├符号有り24ビット,ビッグエンディアン
//			stringDist  <<= 8;			//│
//			stringDist   |=       *keyBody++;	//┘
//			printIndent(indent, "%u\t=\t\"%s\"", stringName, keyBody + stringDist);
//		}
//	}
//}
//↓2015/09/22変更:clipreg.cに「インデクスアクセス型,及び,イテレーション用の関数」を追加した事に伴い、レジストリテーブルのバイナリを直接解析するのでなく、左記の関数を利用するように変更しました。実行結果はこれまでと変わりません。
static void dumpKeyBody(int indent, const unsigned char* keyBody) {
	//--- キー ---
	{
		const unsigned char* keyBody2;
		int index, keyName;
		for(index = 0;
		   (keyBody2 = REG_open_nth_key(keyBody, index, &keyName)) != NULL;
		    index++) {
			printIndent(indent, "%u", keyName);
			dumpKeyBody(indent + 1, keyBody2);
			printIndent(indent, "end");
		}
	}
	//--- 値 ---
	{
		int index, valueName, valueData;
		for(index = 0;
		   (valueData = REG_get_nth_value(keyBody, index, &valueName)) != -1;
		    index++) {
		    //{{2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
		    //	printIndent(indent, "%u\t=\t%u", valueName, valueData);
		    //↓2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
			printIndent(indent, "%u\t= %u", valueName, valueData);
		    //}}2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
		}
	}
	//--- 文字列 ---
	{
		const char* stringData;
		int index, stringName;
		for(index = 0;
		   (stringData = REG_get_nth_string(keyBody, index, &stringName)) != NULL;
		    index++) {
		    //{{2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
		    //	printIndent(indent, "%u\t=\t\"%s\"", stringName, stringData);
		    //↓2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
			printIndent(indent, "%u\t= \"%s\"", stringName, stringData);
		    //}}2015/10/01変更:'='の後のタブを空白に変更しました。dPrpTblD.exeの出力書式と見た目を合わせるためだけの変更であり、意味上の違いは有りません。
		}
	}
}
//}}2015/09/22変更:clipreg.cに「インデクスアクセス型,及び,イテレーション用の関数」を追加した事に伴い、レジストリテーブルのバイナリを直接解析するのでなく、左記の関数を利用するように変更しました。実行結果はこれまでと変わりません。
/*--------------------------------------------------------------------------*/
static void printIndent(int indent, const char* fmt, ...) {
	va_list ap;
	while(--indent >= 0) { putchar('\t'); }
	va_start(ap, fmt);
	vprintf(fmt, ap);
	va_end(ap);
	putchar('\n');
}
