/*
 *								fax2pbm.exe
 *												Written by SHIMA,  Aug 1993
 *
 *    G3 FAX の圧縮データ(デフォルトは、Starfax形式)を読んで、raw PBM ファイ
 *  ル(デフォルト)、または、monochome GIF ファイルに変換する。ページ毎に別の 
 *  raw PBM ファイル、または、monochrome GIF ファイルとなり、ファイル名はペー
 *  ジに対応して、fax01.pbm, fax02.pbm, fax03.pbm,...  または、fax01.gif, 
 *  fax02.gif, fax03.gif,... となる。
 *
 *    出力された raw PBM ファイル、monochrome GIF ファイルは、dviout によるプ
 *  レビューや、dviprt による印刷ができる。
 *
 *
 *  USAGE : fax2pbm [options] <fax_file>
 *
 *  options are
 *   -s=<top_skip> : byte size of Header of <fax_file>      (default:16)
 *   -d=<dir>      : directory where the PBM files are made (default:current)
 *   -p=<page>     : page to be output                      (default:all pages)
 *   -w=<width>    : size of a line                         (default:1728)
 *	 -w=?          : size of a line is 1728, 2048, 2432, 1216 or 864.
 *   -w            : size of a line will be got from <fax_file>
 *   -i            : Ignore illegal data
 *   -g            : G3 FAX data -> GIF
 *
 */

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<ctype.h>
#include	"g3fax.h"

#define	GIF				1

#define	LIMIT_X			16000
#define	DATA_SIZE		0x920
#define	WRITE_BUF_SIZE	0x4000

#define	FREE_LINE_SIZE	1
#define	FLAG_IGNORE		2
#define	FLAG_GIF		4
#define	AUTO_LINE_SIZE	8

int	line_size[] = {1728, 2048, 2432, 1216, 864, 0};

static char write_buf[WRITE_BUF_SIZE];
static char fbibuf[DATA_SIZE];

#if GIF
void write_gif_head(FILE *file, int width, int height);
void gif_encode(unsigned char *ibuf, int width);
void outputcode(int code, int bits);
void end_gif_file(void);
#endif

static char *pbm_name(char *dir, int page, char *ext)
{
	int	i;
	static char fname[80];

	strncpy(fname, dir, 68);
	i = strlen(fname);
	if (i && isalpha(fname[i-1])){
		fname[i++] = '\\';
		fname[i] = 0;
	}
	sprintf(fname+i, "fax%02d.%s", page, ext);
	return fname;
}


void fax_to_pbm( char *fax_name, char *dir, int skip, int out_page, int flag )
{
	FILE	*fp_pbm, *fp_fax;
	int 	pos, size, total_size;
	int		i, j, c, result, line, eols, page;
	char	*pbm_file;
	static	char *SPC = "     ";				/* length 5 */

	if ( ( fp_fax = fopen( fax_name, "rb" ) ) == NULL ) {
		fprintf( stderr, "Can't open the FAX file %s\n", fax_name );
		exit(1);
	}
	for (i = skip; i-- > 0; )
		fgetc(fp_fax);

	if (initialize_decode(fp_fax)){
		fprintf(stderr, "Not enough memory!\n");
		exit(1);
	}

	page = 1;
	if (flag & FREE_LINE_SIZE) MAX_X = LIMIT_X;
	if (out_page){
		while(page != out_page){
			page++;
			if(next_rtc()){
				fprintf(stderr, "Cannot find page %d.\n", out_page);
				exit(1);
			}
		}
	}

	while(1){
		pbm_file = pbm_name(dir, page, (flag & FLAG_GIF)? "gif":"pbm");
		if( (fp_pbm = fopen( pbm_file, "wb" )) == NULL ) {
			fprintf( stderr, "Can't create the raw PBM file %s\n", pbm_file );
			exit(1);
		}
		setvbuf(fp_pbm, write_buf, _IOFBF, WRITE_BUF_SIZE);
#if	GIF
		if(flag & FLAG_GIF)
			write_gif_head(fp_pbm, MAX_X, 10000);
		else
#endif
		{
			fprintf(fp_pbm, "P4\n#Image generated by fax2pbm (%s %d)\n%d %d\n",
			fax_name, page, MAX_X, 10000);
		}

		for ( line = eols = 0; ; ){
			result = fax_decode_line(fbibuf);
			if (result > 0){
				eols = 0;
				if (result != MAX_X){
					if (!(flag & FREE_LINE_SIZE)
					  || line > 0 || (page > 1 && !out_page)){
err_size:				fprintf(stderr, "Illegal size %d of line %d!\n",
							result, line + 1 );
						goto ask;
					}
					if (flag & AUTO_LINE_SIZE){
						for (i = 0;;){
							if (!line_size[i]) goto err_size;
							if (line_size[i++] == result) break;
						}
					}
					MAX_X = (result >= 100 && result < 10000)?result:MAX_A4X;
					fprintf(stderr, "Line size: %d\n", result);
				}
#if	GIF
				if (flag & FLAG_GIF)
					gif_encode(fbibuf, (MAX_X+7)/8);
				else 
#endif
				if (fwrite(fbibuf, (MAX_X+7)/8, 1, fp_pbm) != 1){
					fprintf( stderr, "Can't write the raw PBM file.\n");
					exit(1);
				}
				line++;
			}
			else if (result < 0){
				switch (result){
					case END_OF_DATA:
							fclose(fp_pbm);
							remove(pbm_file);
							if (page == 1 || out_page)
								fprintf(stderr,
									"End of file in a page!\n");
							exit(0);

					case BAD_DATA:
							fprintf(stderr, "Illegal data 00000000..!\n");
							break;

					case DOUBLE_MAKE:
							fprintf(stderr, "Multiple MAKE UP Codes!\n");
							break;

					case TOO_LONG_LINE:
							fprintf(stderr, "Too long line exists!\n");
							break;

					case OUT_OF_DATA:
							fprintf(stderr, "Out of DATA!\n");
							exit(1);
				}
ask:			if (!(flag & FLAG_IGNORE)){
					do{
						fprintf(stderr, "Continue(y/n)? ");
						if((c = tolower(getchar())) == 'n')
							exit(1);
						(void)getchar();
					}while(c != 'y');
				}
				eols = 0;
			}
			else{
				if(eols++ > 0){
					if( (eols += count_eol()) < 5 ){
						fprintf(stderr, "%d EOLs!\n", eols + 1);
						goto ask;
					}
					break;
				}
			}
		}
#if	GIF
		if(flag & FLAG_GIF){
			end_gif_file();
			fseek(fp_pbm, 0L, SEEK_SET);
			write_gif_head(fp_pbm, MAX_X, line);
		}
		else
#endif
		{
			fseek(fp_pbm, 0L, SEEK_SET);
			c = ((flag & FREE_LINE_SIZE) && MAX_X < 1000)?0:1;
			for (i = line; i >= 10; i /= 10) c++;
			fprintf(fp_pbm,
				"P4\n#Image generated by fax2pbm (%s %d)%s\n%d %d\n",
				fax_name, page, SPC + c, MAX_X, line);
		}
		printf("Create %s (%d x %d)\n", pbm_file, MAX_X, line);
		fclose(fp_pbm);
		page++;
		if (out_page) break;
	}
}

void main( int argc, char *argv[] )
{
	int	i;
	int flag = 0;
	int page = 0;
	int width = 0;
	int skip = 16;
	char *dir = "";

	puts( 
		"\nFAX data to raw PBM/monochrome GIF file Converter  Ver.1.2\n"
		"Copyright(C) SHIMA  Sep. 1993"
	);

	for(i = 1; i < argc - 1; i++){
		if (argv[i][0] != '-') goto usage;
		switch(argv[i][1]){

			case 's':	skip = atoi(argv[i]+3);
						break;

			case 'd':	dir = argv[i]+3;
						break;

			case 'w':	if (argv[i][2] == '='){
							if (argv[i][3] == '?')
								flag |= (AUTO_LINE_SIZE|FREE_LINE_SIZE);
							else{
								width = atoi(argv[i]+3);
								if (width > 0)
									MAX_X = width;
							}
						}
						else	flag |= FREE_LINE_SIZE;
						break;

			case 'p':	page = atoi(argv[i]+3);
						if (page < 1) goto usage;
						break;

			case 'i':	flag |= FLAG_IGNORE;
						break;

#if	GIF
			case 'g':	flag |= FLAG_GIF;
						puts("GIF encoder is written by Asayama");

						break;
#endif

			default:	goto usage;

		}
	}
	if ( argc < 2 ) {
usage:
	puts( 
#if	GIF
	  "GIF encoder is written by Asayama\n\n"
#endif
	  "USAGE : fax2pbm [options] <fax_file>\n\n"
	  "options are\n"
	  " -s=<top_skip> : byte size of Header of <fax_file>\t(default:16)\n"
	  " -d=<dir>      : directory where the PBM files are made"
	  "\t(default:current)\n"
	  " -p=<page>     : page to be output\t\t\t(default:all pages)\n"
	  " -w=<width>    : size of a line\t\t\t\t(default:1728)\n"
	  " -w=?          : size of a line is 1728, 2048, 2432, 1216 or 864\n"
	  " -w            : size of a line will be read from <fax_file>\n"
	  " -i            : Ignore illegal data\n"
#if	GIF
	  " -g            : G3 FAX -> GIF\n"
	  "\nThe Graphics Interchange Format(c) is\n"
	  "the Copyright Property of CompuServe Incorporated.\n"
	  "GIF(sm) is a Service Mark property of CompuServe Incorporated.\n"
#endif
		 );
		exit(1);
	}
	puts("");
	fax_to_pbm( argv[argc-1], dir, skip, page, flag );
}

#if	GIF
#include	"gifencod.c"
#endif
