/**
 * katte.cpp
 *   QuickTimeProで生成したMobile MP4ファイルから'dcmd'という
 *   パターンを検索し、その後2バイトをある規則で書き換えたファイルを
 *   out.3gpという名前で出力します。
 *
 * コンパイル方法
 *   g++ -o katte katte.cpp
 *
 * 2007 T.Shimada
 * このコードについて一切の権利は主張しませんが責任も一切負いません。
 */

#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <new>

// 使い方を表示
void usage(const char* progname)
{
	printf("Usage:\n");
	printf("  %s filename.3gp\n\n", progname);
	printf("Modified audio file will be saved as './out.3gp'\n\n");
}

// メインルーチン
int main(int argc, char* argv[])
{
	// 引数なしで起動された場合
	if (argc < 2) {
		// 使い方を表示して終了
		usage(argv[0]);
		return 0;
	}

	// ファイルサイズを得る
	struct stat sb;
	if (stat(argv[1], &sb) < 0) {
		// ファイルのプロパティを得るのに失敗したらエラー終了
		puts("Stat() failed(File not found?).");
		return -1;
	}
	
	if (sb.st_size < 6) {
		// ファイルが小さすぎる。なにかの間違いでしょう。
		puts("Input file is too short.");
		return -1;
	}

	// ファイルを読み込むためのメモリを確保する
	char* buf = NULL;
	try {
		buf = new char[sb.st_size];
	}
	catch (std::bad_alloc) {
		// まさか・・・
		puts("Out of memory.\n");
		return -1;
	}
	
	// ファイルを読み込みモードで開く
	FILE* f = fopen(argv[1], "r");
	if (!f) {
		// ファイルを開くのに失敗したらエラー終了
		puts("File could not open.");
		return -1;
	}
	
	// ファイルを全部メモリに読み込んでクローズする
	fread(buf, 1, sb.st_size, f);
	fclose(f);

	// 書き換え後の２バイトを決定する。
	char byte1 = 0x09, byte2 = 0x0e;	// ファイルサイズが奇数の場合
	if (sb.st_size % 2 == 0) {
		// ファイルサイズが偶数の場合
		byte1 = 0x0d;
		byte2 = 0x0a;
	}

	// ファイルの先頭から'dcmd'というパターンを探す
	bool success = false;
	for (int i = 0; i < sb.st_size - 8; i++) {
		if (strncmp(buf + i, "dcmd", 4) == 0) {
			// パターンが見つかったらその次の2バイトを上書きして
			// ループを抜ける
			*(buf + i + 4) = byte1;
			*(buf + i + 5) = byte2;
			success = true;
			break;
		}
	}

	if (success) {
		// 書き換えが成功したら、出力ファイルに保存
		f = fopen("out.3gp", "w");
		if (!f) {
			puts("Output file 'out.3gp' couldn't open.");
			delete [] buf;
			return -1;
		}
		fwrite(buf, 1, sb.st_size, f);
		fclose(f);
	} else {
		// 書き換える対象となるパターンが見つからなかったらその旨お知らせ
		puts("Pattern 'dcmd' not found.");
	}

	// メモリを解放して終了
	delete []buf;

	return 0;
}

