/*
 *	app.cpp
 *
 *	dpafxbin.exe - AfterEffectsアニメーションファイル XML形式⇒バイナリ形式 変換ツール
 *	Copyright (C) 2016 Naoyuki Sawa
 *
 *	* Sat Apr 30 21:45:42 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	  MkAfxSeqXml.jsxが出力したXML形式のアニメーションファイル(複数可)を読み込み、(複数ならば)統合して、バイナリ形式のアニメーションファイルに保存します。
 *	  ほぼ、/clip/clipafxb.hの「使用例」そのままの処理を実装したツールです。
 *	  詳細は、/clip/tool/MkAfxSeqXml.jsx,及び,/clip/clipafxb.hを参照して下さい。
 *	* Mon May 02 21:51:14 JST 2016 Naoyuki Sawa
 *	- バイナリ形式のアニメーションファイルでは、ST_AfxSeq.layers[],及び,ST_AfxLyr.pAfxSeqに、オフセットを格納するようにしました。
 *	  詳細は、/clip/clipafxb.cを参照して下さい。
 *	- 上記の変更に伴い、当ツールもリビルドしました。
 *	  当ツールのソースには変更は有りませんが、/clip/clipafxb.cの関数の変更を反映するためです。
 *	* Thu May 05 21:24:20 JST 2016 Naoyuki Sawa
 *	- clipafxb.cにて、ROM化出来るようにするための変更を行いました。
 *	  詳細は、/clip/clipafxb.cを参照して下さい。
 *	  上記の変更に伴い、当ツールもリビルドしました。
 *	- '-u'オプションを追加しました。
 *	* Fri May 06 21:58:10 JST 2016 Naoyuki Sawa
 *	- /clip/clipafxb.cの変更に伴い、当ツールもリビルドしました。
 *	  当ツールの動作は変わりません。
 *	* Sun May 08 23:30:59 JST 2016 Naoyuki Sawa
 *	- /clip/tixml.cモジュールの変更に伴い、当ツールをリビルドしました。
 *	  当ツールのソースには変更有りませんが、/clip/tixml.cモジュールの変更を反映するためです。
 *	  詳細は、/clip/tixml.cの同日のコメントを参照して下さい。
 *	* Mon May 23 22:46:16 JST 2016 Naoyuki Sawa
 *	- clipafxs.c,及び,clipafxb.cのコードを大幅に変更した事に伴い、当ツールをリビルドしました。
 *	  使用方法は変わりませんが、出力バイナリ形式が変わります。
 *	* Sat May 28 21:20:19 JST 2016 Naoyuki Sawa
 *	- ダンプモードを追加しました。
 *	- 既存の変換モード,及び,新規のダンプモード共に、出力ファイルを'-o'オプションで明示的に指定するように変更しました。
 *	  これまでは、引数の順番で指定していましたが、誤って入力ファイルを出力ファイルに指定して、上書きしてしまう危険が高い問題が有ったからです。
 */
#include "app.h"
#define VERSION		"20160528"	//最終更新日
/****************************************************************************
 *	main
 ****************************************************************************/
int main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	putenv("GC_LOG_FILE=CON");//ログ出力先を指定する。
//	GC_set_find_leak(1);//メモリリーク検出を開始する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
#if     (defined(GC_H) && defined(PTHREAD_H))
	GC_init();//この中でGCスレッドが起動する。メインスレッドをpthread_exit()等で終了するとGCスレッドが残ってプロセスが終了しないので注意せよ。
	GC_allow_register_threads();
#endif//(defined(GC_H) && defined(PTHREAD_H))
#ifdef  __CLIP_SEH_H__
	SEH_init();
#endif//__CLIP_SEH_H__
	app_init(argc, argv);
	exitCode = app_main(argc, argv);
	app_exit();
#ifdef  USE_GDIPLUS
	Gdiplus_Exit();
#endif//USE_GDIPLUS
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	CHECK_LEAKS();//メモリリークを検出する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
	return exitCode;
}
/****************************************************************************
 *	usage
 ****************************************************************************/
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dpafxbin.exe - AfterEffectsアニメーションファイル XML形式⇒バイナリ形式 変換ツール (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2016 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "■変換モード\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│USAGE:\n");
	fprintf(stderr, "│  dpafxbin.exe -oバイナリ形式の出力ファイル名 [-u列挙定義スクリプトの出力ファイル名] [XML形式の入力ファイル名 ...]\n");
	fprintf(stderr, "│  ・XML形式の入力ファイル名は、ワイルドカードによる複数指定も可能です。\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│OPTIONS:\n");
	fprintf(stderr, "│  -oバイナリ形式の出力ファイル名        バイナリ形式の出力ファイル名を指定して下さい。\n");
	fprintf(stderr, "│                                        変換モードでは、このオプション指定は必須です。\n");
	fprintf(stderr, "│  -u列挙定義スクリプトの出力ファイル名  アニメーション名の列挙定義スクリプトを出力します。\n");
	fprintf(stderr, "│                                        このオプションを指定しなければ、列挙定義スクリプトを出力しません。\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│EXAMPLE:\n");
	fprintf(stderr, "│  dpafxbin.exe -uEnmAfxBin.txt AfxBin.bin sample1.xml sample2.xml sample3.xml\n");
	fprintf(stderr, "│  sample1.xml,sample2.xml,sample3.xmlを読み込み、統合して、AfxBin.binに保存する。\n");
	fprintf(stderr, "│  列挙定義スクリプトを、EnmAfxBin.txtへ出力する。\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "■ダンプモード\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│USAGE:\n");
	fprintf(stderr, "│  dpafxbin.exe -d [-oYAML形式の出力ファイル名] バイナリ形式の入力ファイル名\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│OPTIONS:\n");
	fprintf(stderr, "│  -d                                    ダンプモードで実行します。\n");
	fprintf(stderr, "│                                        このオプションを指定しなければ、変換モードで実行します。\n");
	fprintf(stderr, "│  -oYAML形式の出力ファイル名            YAML形式の出力ファイル名を指定して下さい。\n");
	fprintf(stderr, "│                                        このオプションを指定しなければ、標準出力へ出力します。\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│EXAMPLE:\n");
	fprintf(stderr, "│  dpafxbin.exe -d -oOutput.yml AfxBin.bin\n");
	fprintf(stderr, "│  AfxBin.binを読み込んで、その内容をOutput.ymlへ、YAML形式でテキスト出力します。\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "■その他\n");
	fprintf(stderr, "│\n");
	fprintf(stderr, "│OPTIONS:\n");
	fprintf(stderr, "│  -h                                    使い方を表示します。\n");
	fprintf(stderr, "│\n");
	exit(EXIT_FAILURE);
}
/****************************************************************************
 *	
 ****************************************************************************/
void app_init(int argc, char* argv[]) {
	/** no job **/
}
/*--------------------------------------------------------------------------*/
void app_exit() {
	/** no job **/
}
/*--------------------------------------------------------------------------*/
int app_main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
	int opt_d = 0;			//'-d'オプションが指定されたら、1をセットする。
	const char* opt_o = NULL;	//'-o'オプションが指定されたら、バイナリ形式の出力ファイル名,又は,YAML形式の出力ファイル名を設定する。
	const char* opt_u = NULL;	//'-u'オプションが指定されたら、列挙定義スクリプトの出力ファイル名を設定する。
	{
		int opt;
		opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
		while((opt = getopt(argc, argv, "do:u:h")) != -1) {	//コマンドラインオプションを処理する。
			switch(opt) {
			case 'd':
				opt_d = 1;	//ダンプモードで実行する。
				break;
			case 'o':
				opt_o = optarg;	//バイナリ形式の出力ファイル名,又は,YAML形式の出力ファイル名を設定する。
				break;
			case 'u':
				opt_u = optarg;	//列挙定義スクリプトの出力ファイル名を設定する。
				break;
			case 'h':
			default:
				usage();
			}
		}
	}
	//変換モードならば…
	if(!opt_d) {
		//変換モードでは、'バイナリ形式の出力ファイル名'は必須です。
		if(!opt_o) { usage(); }
		//'XML形式の入力ファイル名'は0個でも構いません。(無意味だが)
	//不要	if(optind >= argc) { usage(); }
		//変換を実行する。
		AfxBin_Compress_v(
			opt_o,			//バイナリ形式の出力ファイル名
			opt_u/*NULL可*/,	//列挙定義スクリプトの出力ファイル名	'-u'オプションが指定されていなければNULLのままです。
			&argv[optind]);		//[XML形式の入力ファイル名 ...] NULL	'XML形式の入力ファイル名'は0個でも構いません。(無意味だが)
	//ダンプモードならば…
	} else {
		FILE* fp;
		int size;
		void* pAfxSeqBin;
		//ダンプモードでは、'列挙定義スクリプトの出力ファイル名'を指定する事は出来ません。
		if(opt_u) { usage(); }
		//ダンプモードでは、'バイナリ形式の入力ファイル名'は必須です。
		if(optind >= argc) { usage(); }
		//'バイナリ形式の入力ファイル名'を読み込みます。
		fp = fopen(argv[optind], "rb");	//バイナリ形式
		if(!fp) { error(EXIT_FAILURE, errno, "%sが開けません。", argv[optind]); }
		fseek(fp, 0, SEEK_END);
		size = ftell(fp);
		rewind(fp);
		pAfxSeqBin = malloc(size);
		if(!pAfxSeqBin) { DIE(); }	//メモリ不足
		fread(pAfxSeqBin, 1, size, fp);
		fclose(fp);
		//出力ストリームを開く。
		fp = stdout;
		if(opt_o) {	//'YAML形式の出力ファイル名'が指定されていたら…
			fp = fopen(opt_o, "w");	//テキスト形式
			if(!fp) { error(EXIT_FAILURE, errno, "%sが作成出来ません。", opt_o); }
		}
		//ダンプを実行します。
		AfxBin_Dump(fp, pAfxSeqBin);
		//出力ストリームを閉じる。
		if(opt_o) {	//'YAML形式の出力ファイル名'が指定されていたら…
			fclose(fp);
		}
		//'バイナリ形式の入力ファイル名'を開放する。
		free(pAfxSeqBin);
	}
	return exitCode;
}
