// ビットマップファイル縦方向等分割ツール T.KOHNO '99/09/22

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

typedef struct {
/* ファイルヘッダ */
	char	type[ 2 ];					/* ファイルのID (固定 "BM") */
	char	fsize[ 4 ];					/* ファイルのサイズ */
	char	reserve1[ 2 ];				/* 予約1 */
	char	reserve2[ 2 ];				/* 予約2 */
	char	fhsize[ 4 ];				/* ファイルヘッダ+情報ヘッダのサイズ (54固定) */
/* 情報ヘッダ */
	char	infosize[ 4 ];				/* このヘッダのサイズ(40固定) */
	char	wsize[ 4 ];					/* イメージの幅 */
	char	hsize[ 4 ];					/* イメージの高さ */
	char	planes[ 2 ];				/* プレーン数 (1固定) */
	char	bitcount[ 2 ];				/* ピクセルあたりのビット数 (24固定) */
	char	compress[ 4 ];				/* 圧縮方式 (0固定) */
	char	imgsize[ 4 ];				/* イメージサイズ */
	char	xppm[ 4 ];					/* 水平解像度(0固定) */
	char	yppm[ 4 ];					/* 垂直解像度(0固定) */
	char	clrused[ 4 ];				/* 色数(0固定) */
	char	clrimportant[ 4 ];			/* 重要色数(0固定) */
} BMPHeader;

#define TOC(x, y)	{x[0] = y & 0x0ff; \
					 x[1] = (y >> 8) & 0x0ff; \
					 x[2] = (y >> 16) & 0x0ff; \
					 x[3] = (y >> 24) & 0x0ff;}

#define TOI(x)	(((unsigned char)x[3] << 24) + ((unsigned char)x[2] << 16) + ((unsigned char)x[1] << 8) + (unsigned char)x[0])

void PrintUsage(void);

// メイン
int main(int argc, char* argv[])
{
	// 引数の解析
	for( ;argc > 1 && argv[1][0] == '-'; argv++,argc--){
		switch(argv[1][1]){
			case '?': // 使い方の表示
			case 'h':
				PrintUsage();
				argv++,argc--;
				return 1;
			default:
				break;
		}
	}
	
	// 引数がない場合は USAGE を表示して終了
	if (argc<2){
		PrintUsage();
		return 1;
	}
	
	// 第1引数で指定されたファイルをオープン
	FILE* fp;
	if (!(fp = fopen(argv[1], "rb"))){
		perror("Can't open file.");
		return 1;
	}

	// ヘッダ情報の読み込み
	BMPHeader Header;
	fseek(fp, SEEK_SET, 0);
	if (fread(&Header, 1, sizeof(BMPHeader), fp) < sizeof(BMPHeader)){
		if (ferror(fp)){
			perror("Can't read header.\n");
		} else {
			fprintf(stderr, "File length is less than BITMAP header.\n");
		}
		return 1;
	}
	
	// 分割数が与えられないときはファイルのピクセル数を表示して終了
	if (argc==2){
		fprintf(stdout, "Width %d, Height %d\n",  TOI(Header.wsize), TOI(Header.hsize));
		return 0;
	}
	
	// 第2引数から分割数を取得し各画像の縦方向のピクセル数・データサイズを計算
	int lp;
	int num;
	int lines;
	
	if ((num = atoi(argv[2])) < 1){
		fprintf(stderr, "Number is must larger than 0.\n");
		return 1;
	}
	
	if ((lines = TOI(Header.hsize) / num) == 0){
		fprintf(stderr, "Can't split %d. Because hight is %d.\n", num, Header.hsize);
	}
	
	char* pBuf;
	unsigned int buflen; 
	int mod = ( 2 - (TOI(Header.wsize) % 2));
	buflen = lines * (TOI(Header.wsize) * 3 + mod);
	if (!(pBuf = (char*)malloc(buflen))){
		perror("Can't allocate memory.\n");
		return 1;
	}
	
	char newfile[_MAX_PATH];
	FILE* ofp;
	
	TOC(Header.hsize, lines);
	TOC(Header.fsize, buflen);
	
	// 指定された分割数分だけファイルを作成する。
	for (lp=0; lp<num; lp++){
		if (fread(pBuf, 1, buflen, fp) < buflen){
			if (feof(fp)){
				break;
			}
			perror("Can't read data.\n");
			return 1;
		}
		sprintf(newfile, "%08d.bmp", lp);
		if ((ofp = fopen(newfile, "wb")) == NULL){
			perror("Can't open new file.\n");
			return 1;
		}
		if (fwrite(&Header, 1, sizeof(BMPHeader), ofp) < sizeof(BMPHeader)){
			perror("Can't write header.\n");
			fclose(ofp);
			return 1;
		}
		if (fwrite(pBuf, 1, buflen, ofp) < buflen){
			perror("Can't write data.\n");
			fclose(ofp);
			return 1;
		}
		fclose(ofp);
	}
	fclose(fp);
	
	// 終了
	return 0;
}

// 使い方の表示
void PrintUsage(void)
{
	fprintf(stdout, "BMSplit: Usage\n");
	fprintf(stdout, "\tbm_split [-d] bitmap_filename [num]\n");
	fprintf(stdout, "\t\tbitmap_filename is image with BITMAP format.\n");
	fprintf(stdout, "\t\tnum is number of split image.\n\n");
	fprintf(stdout, "\tIf no tnum are given, bitmap size is printed.\n");
}

