#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, ...);
static void printIndent_nonewline(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");
//{{2016/05/28追加:ファイルオープンエラーを検査し忘れていたバグを修正しました。
	if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", argv[optind]); }
//}}2016/05/28追加:ファイルオープンエラーを検査し忘れていたバグを修正しました。
	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-2016 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);
}
/*--------------------------------------------------------------------------*/
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++) {
			printIndent(indent, "%u\t= %u", valueName, valueData);
		}
	}
	//--- 文字列 ---
	{
		const char* stringData;
		int index, stringName;
		for(index = 0;
		   (stringData = REG_get_nth_string(keyBody, index, &stringName)) != NULL;
		    index++) {
			printIndent(indent, "%u\t= \"%s\"", stringName, stringData);
		}
	}
	//--- BLOB ---
	{
		const uint8_t* blobData;
		int index, blobName, blobSize, i;
		for(index = 0;
		   (blobData = REG_get_nth_blob(keyBody, index, &blobName)) != NULL;
		    index++) {
			printIndent_nonewline(indent, "%u\t= {", blobName);
			blobSize = REG_get_blob_size(blobData);
			for(i = 0; i < blobSize; i++) {
				printf("0x%02X", blobData[i]);
				if(i < (blobSize - 1)) {
					putchar(',');
					if((i & 15) == 15) {	//BLOBは一行16バイトで改行する事にしました。変更しても構いません。
						putchar('\n');
						printIndent_nonewline(indent, "\t   ");
					}
				}
			}
			printf("}\n");
		}
	}
}
/*--------------------------------------------------------------------------*/
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');
}
static void printIndent_nonewline(int indent, const char* fmt, ...) {
	va_list ap;
	while(--indent >= 0) { putchar('\t'); }
	va_start(ap, fmt);
	vprintf(fmt, ap);
	va_end(ap);
}
